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.
263 lines (192 loc) • 11.2 kB
JavaScript
var assert = require('assert'),
Matcher = require('../src/Matcher.js');
describe('Matcher', function() {
describe('contains()', function() {
it('should return false with a bad input address', function() {
var matcher = new Matcher([ '192.168.1.2/32', '2a05:d07c:2000::/40' ]);
assert.ok(!matcher.contains('0.0.0.192.168.1.2'));
assert.ok(!matcher.contains('xxx:d07c:2000::'));
});
it('should return true if an IPv4 matches a /32 network range', function() {
var matcher = new Matcher([ '192.168.1.2/32' ]);
assert.ok(!matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.2'));
assert.ok(!matcher.contains('192.168.1.3'));
});
it('should return true if an IPv4 matches a /30 network range', function() {
var matcher = new Matcher([ '192.168.1.0/30' ]);
assert.ok(!matcher.contains('192.168.0.1'));
assert.ok(matcher.contains('192.168.1.0'));
assert.ok(matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.2'));
assert.ok(matcher.contains('192.168.1.3'));
assert.ok(!matcher.contains('192.168.1.4'));
});
it('should return true if an IPv4 matches a /24 network range', function() {
var matcher = new Matcher([ '192.168.1.0/24' ]);
assert.ok(!matcher.contains('192.168.0.1'));
assert.ok(!matcher.contains('192.168.0.254'));
assert.ok(!matcher.contains('192.168.2.1'));
assert.ok(!matcher.contains('192.168.2.254'));
assert.ok(matcher.contains('192.168.1.0'));
assert.ok(matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.128'));
assert.ok(matcher.contains('192.168.1.254'));
assert.ok(matcher.contains('192.168.1.255'));
});
it('should return true if an IPv4 matches a /16 network range', function() {
var matcher = new Matcher([ '192.168.1.0/16' ]);
assert.ok(matcher.contains('192.168.0.0'));
assert.ok(matcher.contains('192.168.0.1'));
assert.ok(matcher.contains('192.168.0.254'));
assert.ok(matcher.contains('192.168.128.1'));
assert.ok(matcher.contains('192.168.128.254'));
assert.ok(matcher.contains('192.168.255.1'));
assert.ok(matcher.contains('192.168.255.254'));
assert.ok(matcher.contains('192.168.255.255'));
assert.ok(!matcher.contains('192.167.0.1'));
assert.ok(!matcher.contains('192.169.0.1'));
});
it('should return true if an IPv4 matches multiple /32 network ranges', function() {
var matcher = new Matcher([ '192.168.1.3/32', '192.168.1.2/32' ]);
assert.ok(!matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.2'));
assert.ok(matcher.contains('192.168.1.3'));
assert.ok(!matcher.contains('192.168.1.4'));
});
it('should return true if an IPv4 matches network ranges', function() {
var matcher = new Matcher([ '192.168.1.0/24', '192.168.2.3/32', '192.168.3.2/32' ]);
assert.ok(matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.2'));
assert.ok(matcher.contains('192.168.1.3'));
assert.ok(!matcher.contains('192.168.2.1'));
assert.ok(!matcher.contains('192.168.2.2'));
assert.ok(matcher.contains('192.168.2.3'));
assert.ok(!matcher.contains('192.168.3.1'));
assert.ok(matcher.contains('192.168.3.2'));
assert.ok(!matcher.contains('192.168.3.3'));
});
it('should return true if an IPv4 matches overlapping network ranges', function() {
var matcher = new Matcher([ '192.168.1.0/24', '192.168.1.3/32', '192.168.1.2/32' ]);
assert.ok(!matcher.contains('192.168.0.1'));
assert.ok(!matcher.contains('192.168.0.254'));
assert.ok(!matcher.contains('192.168.2.1'));
assert.ok(!matcher.contains('192.168.2.254'));
assert.ok(matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.2'));
assert.ok(matcher.contains('192.168.1.3'));
assert.ok(matcher.contains('192.168.1.128'));
assert.ok(matcher.contains('192.168.1.254'));
});
it('should return true if an IPv4 matches a 0.0.0.0 range', function() {
var matcher = new Matcher([ '0.0.0.0/24' ]);
assert.ok(!matcher.contains('192.168.2.1'));
assert.ok(!matcher.contains('192.168.2.254'));
assert.ok(matcher.contains('0.0.0.0'));
assert.ok(matcher.contains('0.0.0.10'));
assert.ok(matcher.contains('0.0.0.254'));
});
it('should return true if an IPv6 matches a /128 network range', function() {
var matcher = new Matcher([ '2a05:d07c:2000:0:0:0:0:1/128' ]);
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:0:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:1'));
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:0:2'));
});
it('should return true if an IPv6 matches a /120 network range', function() {
var matcher = new Matcher([ '2a05:d07c:2000:0:0:0:0:1/120' ]);
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:1'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:ff'));
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:0:ffff'));
});
it('should return true if an IPv6 matches multiple /128 network ranges', function() {
var matcher = new Matcher([ '2a05:d07c:2000:0:0:0:0:1/128', '2a05:d07c:2000:0:0:0:0:2/128' ]);
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:0:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:1'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:2'));
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:0:3'));
});
it('should return true if an IPv6 matches overlapping network ranges', function() {
var matcher = new Matcher([ '2a05:d07c:2000:0:0:0:0:0/120', '2a05:d07c:2000:0:0:0:0:0/110' ]);
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:4:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:ff'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:1:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:3:ffff'));
});
it('should support mixed IPv4 and IPv6 network ranges', function() {
var matcher = new Matcher([ '2a05:d07c:2000:0:0:0:0:0/120', '2a05:d07c:2000:0:0:0:0:0/110', '192.168.1.0/24', '192.168.2.3/32', '192.168.3.2/32' ]);
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:4:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:ff'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:1:0'));
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:3:ffff'));
assert.ok(matcher.contains('192.168.1.1'));
assert.ok(matcher.contains('192.168.1.2'));
assert.ok(matcher.contains('192.168.1.3'));
assert.ok(!matcher.contains('192.168.2.1'));
assert.ok(!matcher.contains('192.168.2.2'));
assert.ok(matcher.contains('192.168.2.3'));
assert.ok(!matcher.contains('192.168.3.1'));
assert.ok(matcher.contains('192.168.3.2'));
assert.ok(!matcher.contains('192.168.3.3'));
});
it('should support IPv4 detection in a IPv6 network range', function() {
var matcher = new Matcher([ '0:0:0:0:0:ffff:102:304/128' ]);
assert.ok(!matcher.contains('1.2.3.3'));
assert.ok(matcher.contains('1.2.3.4'));
assert.ok(!matcher.contains('1.2.3.5'));
});
it('should support IPv6 detection in a IPv4 network range', function() {
var matcher = new Matcher([ '1.2.3.4/32' ]);
assert.ok(!matcher.contains('0:0:0:0:0:ffff:102:303'));
assert.ok(matcher.contains('0:0:0:0:0:ffff:102:304'));
assert.ok(!matcher.contains('0:0:0:0:0:ffff:102:305'));
});
it('should support IPv4 detection in a IPv6 network range spanning outside the IPv4 space', function() {
var matcher = new Matcher([ '0:0:0:0:0:0:0:0/64' ]);
assert.ok(matcher.contains('0.0.0.0'));
assert.ok(matcher.contains('255.255.255.255'));
assert.ok(matcher.contains('0:0:0:0:0:0:0:0'));
assert.ok(matcher.contains('0:0:0:0:ffff:ffff:ffff:ffff'));
assert.ok(!matcher.contains('0:0:0:1000:ffff:ffff:ffff:ffff'));
});
});
describe('containsAny()', function() {
it('should return true if any of input IPv4 addresses matches ranges', function() {
var matcher = new Matcher([ '192.168.1.0/24', '192.168.2.3/32', '192.168.3.2/32' ]);
assert.ok(!matcher.containsAny([ '192.168.2.1' ]));
assert.ok(!matcher.containsAny([ '192.168.2.1', '192.168.3.3' ]));
assert.ok(matcher.containsAny([ '192.168.2.1', '192.168.3.3', '192.168.2.3' ]));
});
it('should return true if any of input IPv6 addresses matches ranges', function() {
var matcher = new Matcher([ '2a05:d07c:2000::/40' ]);
assert.ok(!matcher.containsAny([ '2a05:d07c:1000:0:0:0:0:0' ]));
assert.ok(!matcher.containsAny([ '2a05:d07c:1000:0:0:0:0:0', '2a05:d07c:3000:0:0:0:0:0' ]));
assert.ok(matcher.containsAny([ '2a05:d07c:1000:0:0:0:0:0', '2a05:d07c:2000:0:0:0:0:0', '2a05:d07c:3000:0:0:0:0:0' ]));
});
});
describe('addNetworkClass()', function() {
it('should add an IPv4 cidr to the matcher', function() {
var matcher = new Matcher();
assert.ok(!matcher.contains('192.168.1.3'));
matcher.addNetworkClass('192.168.1.1/24');
assert.ok(matcher.contains('192.168.1.3'));
});
it('should add an IPv6 cidr to the matcher', function() {
var matcher = new Matcher();
assert.ok(!matcher.contains('2a05:d07c:2000:0:0:0:0:1'));
matcher.addNetworkClass('2a05:d07c:2000::/40');
assert.ok(matcher.contains('2a05:d07c:2000:0:0:0:0:1'));
});
it('should throw an error if the input network class is not in the CIDR notation', function() {
var matcher = new Matcher();
try {
matcher.addNetworkClass('192.168.1.2');
fail("should throw an Error");
} catch(err) {
assert.equal("Invalid argument: <addr>/<prefix> expected", err.message);
}
});
});
});