Find which range an IP address is in

conanlloyd
Giga Guru

We have the IP Range table populated, including the starting IP and Ending IP fields.  The requirement is whenever the IP Address of a computer changes, we want to update the IP Location field with the Site Name of the corresponding range.  I wrote the following on change script but the glide lookup isn't working.  I'm assuming it's because I don't have the correct operators for finding it.  Can anyone out there help me?

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }

//Get current IP address
  var myIP = g_form.getValue("ip_address");

//Find IP Range where current IP is between Start IP and End IP	
  var gr = new GlideRecord("ip_address_range");
  gr.addQuery("start_ip",">=",myIP);
  gr.addQuery("end_ip","<=",myIP);
  gr.query();
    if (gr.next()) {
// Update IP location with Range Site name
      g_form.setValue("u_ip_location",gr.u_site_name);   
    }
}
1 ACCEPTED SOLUTION

Ankur Bawiskar
Tera Patron
Tera Patron

Hi,

I think you cannot compare IP addresses directly using those operators

here is the script which will check whether a particular Ip address is in range; The logic would be

1) query the ip address range table

2) pass the start, end, your ip to this function

3) function will return true/false

4) if it returns true then pick up the site name

5) set the value

I would recommend using business rule i.e. before update/insert to do this; since it will take more time to query every single record and compare and then set

Avoid client script

Sample business rule script here: I assume you have configured the ip address range table properly so that it returns true only for 1 record i.e. single ip address won't be present in range for multiple records; if it is then it will pick the first

Note: the function won't validate the ip address but just check whether your ip falls in that range or not

var gr = new GlideRecord("ip_address_range");
gr.query();
while(gr.next()) {

var start = gr.start_ip;
var end = gr.end_ip;
var myIP = current.ip_address;

if(isWithinRange(myIP,start,end))
current.u_ip_location = gr.u_site_name;

}

function isWithinRange(ip, lowerBound, upperBound) {

  var ips = [ip.split('.'), lowerBound.split('.'), upperBound.split('.')];

  for(var i = 0; i < ips.length; i++) {
    for(var j = 0; j < ips[i].length; j++) {
      ips[i][j] = parseInt(ips[i][j]);
    }

    ips[i] = 
      (ips[i][0] << 24) + 
      (ips[i][1] << 16) + 
      (ips[i][2] << 8) + 
      (ips[i][3]);
  }

  if(ips[0] >= ips[1] && ips[0] <= ips[2])
    return true;
  else 
   return false;
}

Mark Correct if this solves your issue and also mark 👍 Helpful if you find my response worthy based on the impact.
Thanks
Ankur

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

9 REPLIES 9

Alikutty A
Tera Sage

Hi,

Using GlideRecord on a client side script is not a best practice and it is recommended to use GlideAjax. You could try the following and see if it works for you

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
   if (isLoading || newValue === '') {
      return;
   }

//Get current IP address
  var myIP = g_form.getValue("ip_address");

//Find IP Range where current IP is between Start IP and End IP	
  var gr = new GlideRecord("ip_address_range");
  gr.addQuery("start_ip",">=",myIP);
  gr.addQuery("end_ip","<=",myIP);
  gr.query(function(rec) {
    if (gr.next()) {
//Update IP location with Range Site name
      g_form.setValue("u_ip_location",rec.u_site_name);   
    }
    });
}

Ankur Bawiskar
Tera Patron
Tera Patron

Hi,

I think you cannot compare IP addresses directly using those operators

here is the script which will check whether a particular Ip address is in range; The logic would be

1) query the ip address range table

2) pass the start, end, your ip to this function

3) function will return true/false

4) if it returns true then pick up the site name

5) set the value

I would recommend using business rule i.e. before update/insert to do this; since it will take more time to query every single record and compare and then set

Avoid client script

Sample business rule script here: I assume you have configured the ip address range table properly so that it returns true only for 1 record i.e. single ip address won't be present in range for multiple records; if it is then it will pick the first

Note: the function won't validate the ip address but just check whether your ip falls in that range or not

var gr = new GlideRecord("ip_address_range");
gr.query();
while(gr.next()) {

var start = gr.start_ip;
var end = gr.end_ip;
var myIP = current.ip_address;

if(isWithinRange(myIP,start,end))
current.u_ip_location = gr.u_site_name;

}

function isWithinRange(ip, lowerBound, upperBound) {

  var ips = [ip.split('.'), lowerBound.split('.'), upperBound.split('.')];

  for(var i = 0; i < ips.length; i++) {
    for(var j = 0; j < ips[i].length; j++) {
      ips[i][j] = parseInt(ips[i][j]);
    }

    ips[i] = 
      (ips[i][0] << 24) + 
      (ips[i][1] << 16) + 
      (ips[i][2] << 8) + 
      (ips[i][3]);
  }

  if(ips[0] >= ips[1] && ips[0] <= ips[2])
    return true;
  else 
   return false;
}

Mark Correct if this solves your issue and also mark 👍 Helpful if you find my response worthy based on the impact.
Thanks
Ankur

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

Ankur, thanks for the quick and helpful reply. That business rule looks sweet and seems to work, but it's only running the glide lookup for one entry in the table and then stops. I added a couple log statements to see what was happening.  I put in 10.1.0.188 and saved the record, but only got one set of log statements.  If it was looping through the whole table until it found the right range then I should have gotten multiple sets, right?

gs.log("CDL: Start Script");
var gr = new GlideRecord("ip_address_range");
gr.query();
while(gr.next()) {

var start = gr.start_ip;
	gs.log("CDL: Start: " + start);
var end = gr.end_ip;
	gs.log("CDL: End: " + end);
var myIP = current.ip_address;
	gs.log("CDL: myIP: " + myIP);

if(isWithinRange(myIP,start,end))
current.u_ip_location = gr.u_site_name;
alert("CDL: Site: " +  gr.u_site_name);
}

function isWithinRange(ip, lowerBound, upperBound) {

  var ips = [ip.split('.'), lowerBound.split('.'), upperBound.split('.')];

  for(var i = 0; i < ips.length; i++) {
    for(var j = 0; j < ips[i].length; j++) {
      ips[i][j] = parseInt(ips[i][j]);
    }

    ips[i] = 
      (ips[i][0] << 24) + 
      (ips[i][1] << 16) + 
      (ips[i][2] << 8) + 
      (ips[i][3]);
  }

  if(ips[0] >= ips[1] && ips[0] <= ips[2])
    return true;
  else 
   return false;
}

The even better news is that it does populate the site name when i use an ip that falls into the only range it checks.  So all we need to figure out is how to make it cycle through all the ranges until it gets the correct one.