viewer/molochparser.js
/* Do all the magic around ip field parsing.
 * Supports many formats such as
 * ip
 * ip/cidr
 * ip1 = ip1.0.0.0/24
 * ip1.ip2 = ip1.ip2.0.0/16
 * ip1.ip2.ip3 = ip1.ip2.ip3.0/8
 * All of the above with a :port(v4) or .port(v6) at the end
 * Arrays of all of the above
 */
Do all the magic around ip field parsing.
Do all the magic around ip field parsing .
function parseIpPort (yy, field, ipPortStr) {
  const dbField = getFieldInfo(yy, field).dbField;
  function parseSingleIp (exp, singleDbField, singleIp, singlePort) {
    let singleObj;
    if (typeof (singlePort) === 'string' && singlePort.match(/[^0-9]/)) {
      throw singlePort + ' not a valid singlePort';
    }
    if (singleIp !== undefined) {
      const colon = singleIp.indexOf(':');
      if ((colon === -1 && singleIp.match(/[^.0-9/]/)) || 
          (colon !== -1 && singleIp.match(/[^a-fA-F:0-9/]/)) || 
          singleIp.match(/\/.*[^0-9]/)) { 
        throw singleIp + ' not a valid ip';
      }
      singleObj = { term: {} };
      singleObj.term[singleDbField] = singleIp;
    }
    if (singlePort !== -1) {
      const expInfo = getFieldInfo(yy, exp);
      if (expInfo.portField) {
        singleObj = { bool: { filter: [singleObj, { term: {} }] } };
        singleObj.bool.filter[1].term[expInfo.portField] = singlePort;
      } else {
        throw exp + " doesn't support port";
      }
      if (singleIp === undefined) {
        singleObj = singleObj.bool.filter[1];
      }
    }
    return singleObj;
  }
  function parseAllIp (allIp, allPort) {
    const infos = getIpInfoList(yy, allPort !== -1);
    const ors = [];
    for (const info of infos) {
      const allObj = parseSingleIp(info.exp, info.dbField, allIp, allPort);
      if (allObj) {
        ors.push(allObj);
      }
    }
    return { bool: { should: ors } };
  }
  let obj;
  ipPortStr = ipPortStr.trim();
  if (isArrayFull(ipPortStr)) {
    const list = ListToArrayMap(ipPortStr, str => parseIpPort(yy, field, str));
    if (list.length === 1) {
      return list[0]
    }
    if (isArrayAND(ipPortStr)) {
      obj = { bool: { filter: list } };
    } else {
      obj = { bool: { should: list } };
    }
    return obj;
  }
  if ((ipPortStr[0] === ':' && ipPortStr[0] !== ':') ||
      (ipPortStr[0] === '.')) {
    if (dbField !== 'ipall') {
      return parseSingleIp(field, dbField, undefined, +ipPortStr.slice(1));
    } else {
      return parseAllIp(undefined, +ipPortStr.slice(1));
    }
  }
  let ip;
  let port = -1;
  const colons = ipPortStr.split(':');
  if (colons.length > 2) {
    const dots = ipPortStr.split('.');
    if (dots.length > 1 && dots[1] !== '') {
      port = dots[1];
    }
    ip = dots[0];
  } else {
    if (colons.length > 1 && colons[1] !== '') {
      port = colons[1];
    }
    const slash = colons[0].split('/');
    const dots = slash[0].split('.');
    if (dots[dots.length - 1] === '') {
      dots.length--;
    }
    switch (dots.length) {
    case 4:
      ip = `${dots[0]}.${dots[1]}.${dots[2]}.${dots[3]}`;
      break;
    case 3:
      ip = `${dots[0]}.${dots[1]}.${dots[2]}.0`;
      if (slash[1] === undefined) { slash[1] = '24'; }
      break;
    case 2:
      ip = `${dots[0]}.${dots[1]}.0.0`;
      if (slash[1] === undefined) { slash[1] = '16'; }
      break;
    case 1:
      if (dots[0].length > 0) {
        ip = `${dots[0]}.0.0.0`;
        if (slash[1] === undefined) { slash[1] = '8'; }
      }
      break;
    }
    if (slash[1] && slash[1] !== '32') {
      ip = `${ip}/${slash[1]}`;
    }
  }
  if (dbField !== 'ipall') {
    return parseSingleIp(field, dbField, ip, port);
  } else {
    return parseAllIp(ip, port);
  }
}
function parseIpPort ( yy , field , ipPortStr ) { const dbField = getFieldInfo ( yy , field ) . dbField ; function parseSingleIp ( exp , singleDbField , singleIp , singlePort ) { let singleObj ; if ( typeof ( singlePort ) === 'string' && singlePort . match ( / [^0-9] / ) ) { throw singlePort + ' not a valid singlePort' ; } if ( singleIp !== undefined ) { const colon = singleIp . indexOf ( ':' ) ; if ( ( colon === - 1 && singleIp . match ( / [^.0-9/] / ) ) || ( colon !== - 1 && singleIp . match ( / [^a-fA-F:0-9/] / ) ) || singleIp . match ( / \/.*[^0-9] / ) ) { throw singleIp + ' not a valid ip' ; } singleObj = { term : { } } ; singleObj . term [ singleDbField ] = singleIp ; } if ( singlePort !== - 1 ) { const expInfo = getFieldInfo ( yy , exp ) ; if ( expInfo . portField ) { singleObj = { bool : { filter : [ singleObj , { term : { } } ] } } ; singleObj . bool . filter [ 1 ] . term [ expInfo . portField ] = singlePort ; } else { throw exp + " doesn't support port" ; } if ( singleIp === undefined ) { singleObj = singleObj . bool . filter [ 1 ] ; } } return singleObj ; } function parseAllIp ( allIp , allPort ) { const infos = getIpInfoList ( yy , allPort !== - 1 ) ; const ors = [ ] ; for ( const info of infos ) { const allObj = parseSingleIp ( info . exp , info . dbField , allIp , allPort ) ; if ( allObj ) { ors . push ( allObj ) ; } } return { bool : { should : ors } } ; } let obj ; ipPortStr = ipPortStr . trim ( ) ; if ( isArrayFull ( ipPortStr ) ) { const list = ListToArrayMap ( ipPortStr , str => parseIpPort ( yy , field , str ) ) ; if ( list . length === 1 ) { return list [ 0 ] } if ( isArrayAND ( ipPortStr ) ) { obj = { bool : { filter : list } } ; } else { obj = { bool : { should : list } } ; } return obj ; } if ( ( ipPortStr [ 0 ] === ':' && ipPortStr [ 0 ] !== ':' ) || ( ipPortStr [ 0 ] === '.' ) ) { if ( dbField !== 'ipall' ) { return parseSingleIp ( field , dbField , undefined , + ipPortStr . slice ( 1 ) ) ; } else { return parseAllIp ( undefined , + ipPortStr . slice ( 1 ) ) ; } } let ip ; let port = - 1 ; const colons = ipPortStr . split ( ':' ) ; if ( colons . length > 2 ) { const dots = ipPortStr . split ( '.' ) ; if ( dots . length > 1 && dots [ 1 ] !== '' ) { port = dots [ 1 ] ; } ip = dots [ 0 ] ; } else { if ( colons . length > 1 && colons [ 1 ] !== '' ) { port = colons [ 1 ] ; } const slash = colons [ 0 ] . split ( '/' ) ; const dots = slash [ 0 ] . split ( '.' ) ; if ( dots [ dots . length - 1 ] === '' ) { dots . length -- ; } switch ( dots . length ) { case 4 : ip = ` ${ dots [ 0 ] } ${ dots [ 1 ] } ${ dots [ 2 ] } ${ dots [ 3 ] } ` ; break ; case 3 : ip = ` ${ dots [ 0 ] } ${ dots [ 1 ] } ${ dots [ 2 ] } ` ; if ( slash [ 1 ] === undefined ) { slash [ 1 ] = '24' ; } break ; case 2 : ip = ` ${ dots [ 0 ] } ${ dots [ 1 ] } ` ; if ( slash [ 1 ] === undefined ) { slash [ 1 ] = '16' ; } break ; case 1 : if ( dots [ 0 ] . length > 0 ) { ip = ` ${ dots [ 0 ] } ` ; if ( slash [ 1 ] === undefined ) { slash [ 1 ] = '8' ; } } break ; } if ( slash [ 1 ] && slash [ 1 ] !== '32' ) { ip = ` ${ ip } ${ slash [ 1 ] } ` ; } } if ( dbField !== 'ipall' ) { return parseSingleIp ( field , dbField , ip , port ) ; } else { return parseAllIp ( ip , port ) ; } }
Do all the magic around ip field parsing.
Do all the magic around ip field parsing .
// Have just a single Ip, create obj for it // IP4 // IP6 // CIDR // Special case of ip= // We really have a list of them // Optimize 1 item in array // Support ':80' and '.80' // Support ip4: '10.10.10.10' '10.10.10/16:80' '10.10.10:80' '10.10.10/16' // Support ip6: '1::2' '1::2/16.80' '1::2.80' '1::2/16' // More then 1 colon is ip 6 // Everything after . is port // Everything before . is ip and slash // everything after : is port // Have to do extra because we allow shorthand for /8, /16, /24 // If the last one is empty just pretend . isn't there, for auto complete // Add the slash back to the ip