cidr-matcher
Version:
Fast CIDR matcher. Given an input IPv4 address, it checks if it's inside a set of IP ranges, expressed in CIDR notation.
98 lines (81 loc) • 2.69 kB
JavaScript
var ip6addr = require('ip6addr');
var Matcher = function(classes) {
classes = classes || [];
// Init
this.ranges = {
"ipv4": [],
"ipv6": [],
};
// Import network classes
for (var i = 0; i < classes.length; i++) {
this.addNetworkClass(classes[i]);
}
};
Matcher.prototype.addNetworkClass = function(input) {
var cidr = ip6addr.createCIDR(input);
// Detect if the input network class fits in the IPv4 address space.
// If it doesn't an Error will be thrown and we'll add it to the IPv6
// ranges in the catch block.
try {
var firstNumericAddr = cidr.address().toLong();
var lastNumericAddr = cidr.broadcast().toLong();
this.ranges["ipv4"].push({
cidr: cidr,
first: firstNumericAddr,
last: lastNumericAddr,
});
} catch(err) {
// We've been unable to convert first/last address it to Long,
// so it means it spans over the IPv6 address space
this.ranges["ipv6"].push({
cidr: cidr
});
}
};
Matcher.prototype.contains = function(addr) {
// Parse input address
try {
addr = ip6addr.parse(addr);
} catch(err) {
return false;
}
var ipv4Ranges = this.ranges["ipv4"];
var ipv6Ranges = this.ranges["ipv6"];
// Check if the input address is within any IPv4 network range.
// We detect if the input address is an IPv4. If yes, we can run an optimized
// version which compares the IPv4 network ranges by numeric comparison.
if (ipv4Ranges.length > 0) {
if (addr.kind() === "ipv4") {
var numericAddr = addr.toLong();
for (var i = 0, length = ipv4Ranges.length; i < length; i++) {
if (ipv4Ranges[i].first <= numericAddr && ipv4Ranges[i].last >= numericAddr) {
return true;
}
}
} else {
for (var i = 0, length = ipv4Ranges.length; i < length; i++) {
if (ipv4Ranges[i].cidr.contains(addr)) {
return true;
}
}
}
}
// Check if the input address is within any IPv6 network range
if (ipv6Ranges.length > 0) {
for (var i = 0, length = ipv6Ranges.length; i < length; i++) {
if (ipv6Ranges[i].cidr.contains(addr)) {
return true;
}
}
}
return false;
};
Matcher.prototype.containsAny = function(addrs) {
for (var i in addrs) {
if (addrs.hasOwnProperty(i) && this.contains(addrs[i])) {
return true;
}
}
return false;
};
module.exports = Matcher;