Function to determine if IP is in CIDR network?

jason_lau
Tera Contributor

Is there an existing script class I can use to determine if an IP address is in a given CIDR range?

Basically I want to make a call like: isInCIDR(ip_addr, cidr) and it returns true or false. I'd like to do this without first converting CIDR to range and then using SncIPRangeV4 for example.

Or as a corollary, is there a function I can call where given an IP address, it will return the IP Network (cmdb_ci_ip_network) that IP belongs to, regardless if I have that IP address mapped in CMDB.

1 ACCEPTED SOLUTION

Chuck Tomasi
Tera Patron

Hi Jason,



Thanks for the inquiry. As far as I know, there's nothing OOB. It sounded like a fun thing to build on a weekend so... here's a script include you can use.



var CidrUtil = Class.create();


CidrUtil.prototype = {


  initialize: function() {


  },



  ipIsInCidr : function(ip, cidr) {


            var cidrIp = cidr.split('/')[0];


            var cidrSm = cidr.split('/')[1];



            return (this.IPnumber(ip) & this.IPmask(cidrSm)) == this.IPnumber(cidrIp);


  },



  IPnumber : function (IPaddress) {


            var ip = IPaddress.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);


            if(ip) {


                      return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4]);


            }


            // else ... ?


            return null;


  },



  IPmask : function(maskSize) {


            return -1<<(32-maskSize);


  },


  type: 'CidrUtil'


};



Here's a small example how it can be used:



var ip = '192.168.1.4';


var cidr = '192.168.1.0/24';



var cu = new CidrUtil();


gs.log(cu.ipIsInCidr(ip, cidr));


View solution in original post

16 REPLIES 16

Chuck Tomasi
Tera Patron

Hi Jason,



Thanks for the inquiry. As far as I know, there's nothing OOB. It sounded like a fun thing to build on a weekend so... here's a script include you can use.



var CidrUtil = Class.create();


CidrUtil.prototype = {


  initialize: function() {


  },



  ipIsInCidr : function(ip, cidr) {


            var cidrIp = cidr.split('/')[0];


            var cidrSm = cidr.split('/')[1];



            return (this.IPnumber(ip) & this.IPmask(cidrSm)) == this.IPnumber(cidrIp);


  },



  IPnumber : function (IPaddress) {


            var ip = IPaddress.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);


            if(ip) {


                      return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4]);


            }


            // else ... ?


            return null;


  },



  IPmask : function(maskSize) {


            return -1<<(32-maskSize);


  },


  type: 'CidrUtil'


};



Here's a small example how it can be used:



var ip = '192.168.1.4';


var cidr = '192.168.1.0/24';



var cu = new CidrUtil();


gs.log(cu.ipIsInCidr(ip, cidr));


Jason,



I was just working on this the other week actually. Below is a Business Rule on the cmdb_ci table where it will match the update of an IP address to an existing IP Network record. I recommend adding more qualifiers to your IP Networks (line 6-8) to be more precise on your results.



Condition: current.ip_address.changes() && !current.location.changes()



var ip = current.ip_address;


var location = '';




var netGR = new GlideRecord('cmdb_ci_ip_network');


//netGR.addQuery('discover', true);


netGR.addNotNullQuery('location');


//netGR.addQuery('state', 'Processed');


netGR.orderBy('location');


netGR.query();




while (netGR.next()){



if (inSubNet(ip, netGR.subnet)){


  location = netGR.location.sys_id;


  break;


}


}




current.location = location;



function ip2long(ip){


      var components;




      if(components = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)){


              var iplong = 0;


              var power   = 1;


              for(var i=4; i>=1; i-=1)


              {


                      iplong += power * parseInt(components[i]);


                      power   *= 256;


              }


              return iplong;


      }


      else return -1;


}




function inSubNet(ip, subnet){    


      var mask, base_ip, long_ip = ip2long(ip);


      if( (mask = subnet.match(/^(.*?)\/(\d{1,2})$/)) && ((base_ip=ip2long(mask[1])) >= 0) ){


              var freedom = Math.pow(2, 32 - parseInt(mask[2]));


              return (long_ip > base_ip) && (long_ip < base_ip + freedom - 1);


      }


      else return false;


}


Thanks Andrew, this is very helpful. We have strructured vlans (each VLAN maps to a business unit) so if I add BU information to network object, I can use that to populate some fields in the server CI as they're discovered (owner, etc).


Thanks Chuck! Would be great if this could be built into an OOB servicenow class for IP utils. I know there's a few classes already out there but hard to chase down documention.