- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on ‎03-07-2022 10:23 AM
If you have a little bit of familiarity with networking, you've probably seen network ranges displayed using what's called CIDR notation. For example, a subnet might be described as 192.168.1.0/24. You'll commonly see /8, /16, and /24 covering an IP range and those are easy to determine. If your network is 192.168.1.0/24, you can quickly check if a valid IP address belongs to that range by checking if it starts with "192.168.1." Easy peasy!
But, if you have larger ranges like 10.0.0.0/14, whose range goes from 10.0.0.0 to 10.3.255.255, a startsWith() will no longer be helpful. Instead you need to enter the confusing depths of bit-wise operations.
I've created the the following script include to take CIDR masked IP ranges from a system property and determine if the input belongs to one of those ranges. If it matches, it will also let you know the range that it belongs to.
Sample System Property: ip_tools.network_ranges
10.3.0.0/21
10.10.32.0/20
10.10.64.0/18
10.10.128.0/17
10.12.0.0/15
10.30.0.0/21
10.32.0.0/15
10.34.0.0/22
10.36.0.0/16
Script Include: IPRangeUtil
var IPRangeUtil = Class.create();
IPRangeUtil .prototype = Object.extendsObject(AbstractAjaxProcessor, {
checkIP: function(ip) {
ip = ip ? ip : this.getParameter('sysparm_ip');
ip = String(ip);
var range_obj = {
within_range: false,
range: ''
};
rangeArray = gs.getProperty('ip_tools.network_ranges')
.split('\r\n')
.filter(function(x) {
return x;
});
for (var i = 0; i < rangeArray.length; i++) {
if (this._isIp4InCidr(ip, rangeArray[i])) {
range_obj.within_range = true;
range_obj.range = rangeArray[i];
break;
}
}
return JSON.stringify(range_obj);
},
_ip4ToInt: function(ip) {
return ip.split('.').reduce(function(integer, oct) {
return (integer << 8) + parseInt(oct, 10);
}, 0) >>> 0;
},
_isIp4InCidr: function(ip, cidr) {
var split = cidr.split('/');
var range = split[0];
var bits = split[1];
var mask = -1 << (32 - bits);
// check if the masked IP is the same as the range
return (this._ip4ToInt(ip) & mask) == (this._ip4ToInt(range));
},
type: 'IPRangeUtil '
});
You can then use this script include on catalog items that might require an IP address to fall within a specific range or subnet.
For example, an onChange Client Catalog Script might contain the following:
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading || newValue == '') {
return;
}
var ga = new GlideAjax('IPRangeUtil');
ga.addParam('sysparm_name', 'checkIP');
ga.addParam('sysparm_ip', newValue);
ga.getXMLAnswer(validateIP);
function validateIP(answer) {
var response = JSON.parse(answer);
if (response.within_range == false) {
g_form.clearValue('ip_address');
g_form.showFieldMsg('ip_address', newValue + ' does not fall within one of the allowed subnets.', 'error');
} else {
g_form.hideFieldMsg('ip_address');
}
}
}
You can also do the inverse and protect specific IP ranges, displaying the response.range value to show which range an IP address falls within.
- 7,217 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
What is that emoji😎 in the code?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
@pratiksha5 that line should read
return (integer << 😎 + parseInt(oct, 10);
it won't let me edit the post though.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I am again seeing an emoji. Is it 8)?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
sigh. yes.
return (integer << 8 ) + parseInt(oct, 10);
will it work with a space? let's see...
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
The code is working if we use the property. But it is not working if I try to take the range's value from the table. I have a subnet table (prefix) It has values like 63.247.112.0/20,158.224.68.0/24
var rangeArray = [];
/* var rangeArray = gs.getProperty('ip_tools.network_ranges')
.split('\r\n')
.filter(function(x) {
return x;
});*/
var gr = new GlideRecord("u_prefixes");
gr.query();
while (gr.next()) {
rangeArray.push(gr.name);
}
When I put the logs, I can see the values are comma-separated. But the result is not correct. Am I doing anything wrong?