From 0799741749cbbffd0d759b80a92e7a63f96f6066 Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sat, 25 Dec 2021 20:27:44 +0400 Subject: [PATCH 1/6] ip: add ZERO_IPV4. --- lib/ip.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ip.js b/lib/ip.js index 26d0be3..63e6579 100644 --- a/lib/ip.js +++ b/lib/ip.js @@ -34,6 +34,7 @@ const binet = exports; */ const ZERO_IP = Buffer.from('00000000000000000000000000000000', 'hex'); +const ZERO_IPV4 = Buffer.from('00000000000000000000ffff00000000', 'hex'); const LOCAL_IP = Buffer.from('00000000000000000000000000000001', 'hex'); const RFC6052 = Buffer.from('0064ff9b0000000000000000', 'hex'); const RFC4862 = Buffer.from('fe80000000000000', 'hex'); @@ -1602,5 +1603,7 @@ binet.ip = binet; binet.types = types; binet.networks = networks; binet.ZERO_IP = ZERO_IP; +binet.ZERO_IPV6 = ZERO_IP; +binet.ZERO_IPV4 = ZERO_IPV4; binet.onion = onion; binet.inet = inet; From 599bbab66e33a8b5ef920a2a9a58eaada42aa679 Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sat, 25 Dec 2021 20:33:00 +0400 Subject: [PATCH 2/6] test: add several test vectors. - RFC 1918 - RFC 2544 - RFC 3927 - RFC 6598 - RFC 5737 - RFC 3849 - isValid - isNull - isBroadcast --- test/binet-test.js | 275 +++++++++++++++++++++++++++++++++++-------- test/data/vectors.js | 120 +++++++++++++++++++ 2 files changed, 349 insertions(+), 46 deletions(-) create mode 100644 test/data/vectors.js diff --git a/test/binet-test.js b/test/binet-test.js index 6ef8415..f73ab44 100644 --- a/test/binet-test.js +++ b/test/binet-test.js @@ -1,24 +1,10 @@ -/** - * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License). - * Copyright (c) 2019, Mark Tyneway (MIT License). - * Copyright (c) 2019, Sean Kilgarriff (MIT License). - * - * Parts of this software are based on bitcoin/bitcoin: - * Copyright (c) 2009-2019, The Bitcoin Core Developers (MIT License). - * Copyright (c) 2009-2019, The Bitcoin Developers (MIT License). - * https://github.com/bitcoin/bitcoin - * - * Resources: - * https://github.com/bitcoin/bitcoin/blob/master/src/test/netbase_tests.cpp - */ - -/* eslint-env mocha */ -/* eslint prefer-arrow-callback: "off" */ - 'use strict'; const assert = require('assert'); -const binet = require('../lib/binet'); +const binet = require('../lib/binet'); +const vectors = require('./data/vectors'); + +const allVectors = vectors.all; const { NONE, @@ -64,26 +50,19 @@ describe('binet', function() { } }); - it('should convert back and forth', () => { - const ip4 = '192.168.1.1'; - const ip6 = '2001:db8:85a3::8a2e:370:7334'; - - const raw4 = binet.decode(ip4); - const raw6 = binet.decode(ip6); - - assert.strictEqual(binet.encode(raw4), ip4); - assert.strictEqual(binet.encode(raw6), ip6); + it('should getNetwork', () => { + assert.equal(binet.getNetwork(binet.decode('127.0.0.1')), NONE); + assert.equal(binet.getNetwork(binet.decode('::1')), NONE); + assert.equal(binet.getNetwork(binet.decode('8.8.8.8')), INET4); + assert.equal(binet.getNetwork(binet.decode('8888::8888')), INET6); + assert.equal(binet.getNetwork(binet.decode('2001::')), TEREDO); + assert.equal(binet.getNetwork(binet.decode('FD87:D87E:EB43:edb1:8e4:3588:e546:35ca')), ONION); }); it('should return the correct property', () => { assert(binet.isIPv4(binet.decode('127.0.0.1'))); assert(binet.isIPv4(binet.decode('::FFFF:192.168.1.1'))); assert(binet.isIPv6(binet.decode('::1'))); - assert(binet.isRFC1918(binet.decode('10.0.0.1'))); - assert(binet.isRFC1918(binet.decode('192.168.1.1'))); - assert(binet.isRFC1918(binet.decode('172.31.255.255'))); - assert(binet.isRFC3849(binet.decode('2001:0DB8::'))); - assert(binet.isRFC3927(binet.decode('169.254.1.1'))); assert(binet.isRFC3964(binet.decode('2002::1'))); assert(binet.isRFC4193(binet.decode('FC00::'))); assert(binet.isRFC4843(binet.decode('2001:10::'))); @@ -93,13 +72,6 @@ describe('binet', function() { binet.isOnion(binet.decode('FD87:D87E:EB43:edb1:8e4:3588:e546:35ca')) ); - // isRFC2544 should return true for: - // - IPv4 inter-network communications (198.18.0.0/15) - assert(binet.isRFC2544(binet.decode('198.18.0.0'))); - assert(binet.isRFC2544(binet.decode('198.19.255.255'))); - assert(!binet.isRFC2544(binet.decode('198.17.255.255'))); - assert(!binet.isRFC2544(binet.decode('198.20.5.255'))); - // isLocal should return true for: // - IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8) // - IPv6 loopback (::1/128) @@ -128,12 +100,223 @@ describe('binet', function() { assert(binet.isValid(binet.decode('127.0.0.1'))); }); - it('should getNetwork', () => { - assert.equal(binet.getNetwork(binet.decode('127.0.0.1')), NONE); - assert.equal(binet.getNetwork(binet.decode('::1')), NONE); - assert.equal(binet.getNetwork(binet.decode('8.8.8.8')), INET4); - assert.equal(binet.getNetwork(binet.decode('8888::8888')), INET6); - assert.equal(binet.getNetwork(binet.decode('2001::')), TEREDO); - assert.equal(binet.getNetwork(binet.decode('FD87:D87E:EB43:edb1:8e4:3588:e546:35ca')), ONION); + it('should convert back and forth', () => { + for (const v of allVectors) { + const norm = binet.normalize(v); + const raw = binet.decode(v); + const encoded = binet.encode(raw); + + assert.strictEqual(encoded, norm); + } + }); + + describe('isNull', function() { + const notNull = subtract(allVectors, vectors.NULL); + + it('should determine null IPs', () => { + for (const v of vectors.NULL) { + const decoded = binet.decode(v); + + assert.strictEqual(binet.isNull(decoded), true, + `${v} is null.`); + } + }); + + it('should determine not-null IPs', () => { + for (const v of notNull) { + const decoded = binet.decode(v); + + assert.strictEqual(binet.isNull(decoded), false, + `${v} is not null.`); + } + }); + }); + + describe('isBroadcast', function() { + const notBroadcast = subtract(allVectors, vectors.BROADCAST); + + it('should determine broadcast IPs', () => { + for (const v of vectors.BROADCAST) { + const decoded = binet.decode(v); + + assert.strictEqual(binet.isBroadcast(decoded), true, + `${v} is broadcast.`); + } + }); + + it('should determine non-broadcast IPs', () => { + for (const v of notBroadcast) { + const decoded = binet.decode(v); + + assert.strictEqual(binet.isBroadcast(decoded), false, + `${v} is not a broadcast.`); + } + }); + }); + + describe('isRFC1918', function() { + const notRFC1918 = subtract(allVectors, vectors.RFC1918); + + it('should determine RFC1918 IPs', () => { + for (const v of vectors.RFC1918) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC1918(decoded), true, + `${v} is RFC1918.`); + } + }); + + it('should determine non-RFC1918 IPs', () => { + for (const v of notRFC1918) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC1918(decoded), false, + `${v} is not RFC1918.`); + } + }); + }); + + describe('isRFC2544', function() { + const notRFC2544 = subtract(allVectors, vectors.RFC2544); + + it('should determine RFC2544 IPs', () => { + for (const v of vectors.RFC2544) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC2544(decoded), true, + `${v} is RFC2544.`); + } + }); + + it('should determine non-RFC2544 IPs', () => { + for (const v of notRFC2544) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC2544(decoded), false, + `${v} is not RFC2544.`); + } + }); + }); + + describe('isRFC3927', function() { + const notRFC3927 = subtract(allVectors, vectors.RFC3927); + + it('should determine RFC3927 IPs', () => { + for (const v of vectors.RFC3927) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC3927(decoded), true, + `${v} is RFC3927.`); + } + }); + + it('should determine non-RFC3927 IPs', () => { + for (const v of notRFC3927) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC3927(decoded), false, + `${v} is not RFC3927.`); + } + }); + }); + + describe('isRFC6598', function() { + const notRFC6598 = subtract(allVectors, vectors.RFC6598); + + it('should determine RFC6598 IPs', () => { + for (const v of vectors.RFC6598) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC6598(decoded), true, + `${v} is RFC6598.`); + } + }); + + it('should determine non-RFC6598 IPs', () => { + for (const v of notRFC6598) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC6598(decoded), false, + `${v} is not RFC6598.`); + } + }); + }); + + describe('isRFC5737', function() { + const notRFC5737 = subtract(allVectors, vectors.RFC5737); + + it('should determine RFC5737 IPs', () => { + for (const v of vectors.RFC5737) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC5737(decoded), true, + `${v} is RFC5737.`); + } + }); + + it('should determine non-RFC5737 IPs', () => { + for (const v of notRFC5737) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC5737(decoded), false, + `${v} is not RFC5737.`); + } + }); + }); + + describe('isValid', function() { + const invalidVectors = [ + ...vectors.SHIFTED, + ...vectors.NULL, + ...vectors.BROADCAST, + ...vectors.RFC3849 + ]; + + const validVectors = subtract(allVectors, invalidVectors); + + it('should validate valid IPs', () => { + for (const v of validVectors) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isValid(decoded), true, + `${v} is valid.`); + } + }); + + it('should validate invalid IPs', () => { + for (const v of invalidVectors) { + const decoded = binet.decode(v); + + assert.strictEqual(binet.isValid(decoded), false, + `${v} is invalid.`); + } + }); + }); + + describe('isRFC3849', function() { + const notRFC3849 = subtract(allVectors, vectors.RFC3849); + + it('should determine RFC3849 IPs', () => { + for (const v of vectors.RFC3849) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC3849(decoded), true, + `${v} is valid RFC3849.`); + } + }); + + it('should determine non-RFC3849 IPs', () => { + for (const v of notRFC3849) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isRFC3849(decoded), false, + `${v} is not RFC3849.`); + } + }); }); }); + +function subtract(va, vb) { + const sa = new Set(va); + + for (const vector of vb) + sa.delete(vector); + + return Array.from(sa); +} + +function add(va, vb) { + const sa = new Set(va); + + for (const vector of vb) + sa.add(vector); + + return Array.from(sa); +} diff --git a/test/data/vectors.js b/test/data/vectors.js new file mode 100644 index 0000000..96be3ad --- /dev/null +++ b/test/data/vectors.js @@ -0,0 +1,120 @@ +'use strict'; + +const vectors = exports; + +// Invalid shifted. +vectors.SHIFTED = [ + '::ff:ff00:0:0:0', + '::ff:ff00:0:0:1', + '::ff:ffff:ffff:ffff:ffff' +]; + +// Null +vectors.NULL = [ + '::', + '0.0.0.0' +]; + +// Broadcast +vectors.BROADCAST = [ + '255.255.255.255' +]; + +// RFC 1918 - Private Internets +// - 10/8 +// - 172.16/12 +// - 192.168/16 +vectors.RFC1918 = [ + '192.168.0.0', + '192.168.1.1', + '192.168.255.255', + '10.0.0.0', + '10.0.0.1', + '10.255.255.255', + '172.16.0.0', + '172.16.255.255', + '172.31.255.255' +]; + +// RFC 2544 - IPv4 inter-network communications +// - 198.18.0.0/15 +vectors.RFC2544 = [ + '198.18.0.0', + '198.18.255.255', + '198.19.0.0', + '198.19.255.255' +]; + +// RFC 3927 - Dynamic Configuration of IPv4 Link-Local Addresses +// - 169.254/16 +vectors.RFC3927 = [ + '169.254.0.0', + '169.254.1.1', + '169.254.255.255' +]; + +// RFC 6598 - IANA-Reserved IPv4 Prefix for Shared Address Space +// - 100.64.0.0/10 +vectors.RFC6598 = [ + '100.64.0.0', + '100.64.255.255', + '100.100.100.100', + '100.100.200.200', + '100.127.255.255' +]; + +// RFC 5737 - IPv4 Address Blocks Reserved for Documentation +// - 192.0.2.0/24 (TEST-NET-1) +// - 198.51.100.0/24 (TEST-NET-2) +// - 203.0.113.0/24 (TEST-NET-3) +vectors.RFC5737 = [ + '192.0.2.0', + '192.0.2.1', + '192.0.2.255', + '198.51.100.0', + '198.51.100.1', + '198.51.100.255', + '203.0.113.0', + '203.0.113.1', + '203.0.113.255' +]; + +// RFC3849 - IPv6 Reserved prefix +// 2001:DB8::/32 +vectors.RFC3849 = [ + '2001:0db8::', + '2001:db8::', + '2001:db8::1:1', + '2001:db8:85a3::8a2e:370:7334', + '2001:0db8:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +// IPV4 +vectors.IPV4 = [ + '0.0.0.0', + '255.255.255.255', + ...vectors.RFC1918, + ...vectors.RFC2544, + ...vectors.RFC3927, + ...vectors.RFC6598, + ...vectors.RFC5737 +]; + +vectors.IPV6 = [ + '::', + ...vectors.RFC3849 +]; + +vectors.all = [ + ...vectors.SHIFTED, + ...vectors.NULL, + ...vectors.BROADCAST, + ...vectors.RFC1918, + ...vectors.RFC2544, + ...vectors.RFC3927, + ...vectors.RFC6598, + ...vectors.RFC5737, + ...vectors.RFC3849, + ...vectors.IPV4, + ...vectors.IPV6 +]; From 1a1fc84f1dcf99ffe1b1477d478f9e58bff95bbf Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sun, 26 Dec 2021 19:46:10 +0400 Subject: [PATCH 3/6] test: add test vectors. - RFC 3964 - RFC 6052 - RFC 4380 - RFC 4862 - RFC 4193 - RFC 6145 - RFC 4843 - RFC 7343 - IPv4 - IPv6 --- lib/inet.js | 7 ++ test/binet-test.js | 213 ++++++++--------------------------- test/data/vectors.js | 262 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 303 insertions(+), 179 deletions(-) diff --git a/lib/inet.js b/lib/inet.js index e3e0ccd..0293f1a 100644 --- a/lib/inet.js +++ b/lib/inet.js @@ -591,6 +591,13 @@ function family(str) { return 0; } +/** + * IPv4 Mapped - RFC 2765 + * @param {Buffer} raw + * @param {Number} off + * @returns {Boolean} + */ + function mapped(raw, off) { if (off == null) off = 0; diff --git a/test/binet-test.js b/test/binet-test.js index f73ab44..7f1962c 100644 --- a/test/binet-test.js +++ b/test/binet-test.js @@ -4,7 +4,7 @@ const assert = require('assert'); const binet = require('../lib/binet'); const vectors = require('./data/vectors'); -const allVectors = vectors.all; +const allVectors = vectors.all.reduce((p, c) => add(p, c)); const { NONE, @@ -110,149 +110,54 @@ describe('binet', function() { } }); - describe('isNull', function() { - const notNull = subtract(allVectors, vectors.NULL); - - it('should determine null IPs', () => { - for (const v of vectors.NULL) { - const decoded = binet.decode(v); - - assert.strictEqual(binet.isNull(decoded), true, - `${v} is null.`); - } - }); - - it('should determine not-null IPs', () => { - for (const v of notNull) { - const decoded = binet.decode(v); - - assert.strictEqual(binet.isNull(decoded), false, - `${v} is not null.`); - } - }); - }); - - describe('isBroadcast', function() { - const notBroadcast = subtract(allVectors, vectors.BROADCAST); - - it('should determine broadcast IPs', () => { - for (const v of vectors.BROADCAST) { - const decoded = binet.decode(v); - - assert.strictEqual(binet.isBroadcast(decoded), true, - `${v} is broadcast.`); - } - }); - - it('should determine non-broadcast IPs', () => { - for (const v of notBroadcast) { - const decoded = binet.decode(v); - - assert.strictEqual(binet.isBroadcast(decoded), false, - `${v} is not a broadcast.`); - } - }); - }); - - describe('isRFC1918', function() { - const notRFC1918 = subtract(allVectors, vectors.RFC1918); - - it('should determine RFC1918 IPs', () => { - for (const v of vectors.RFC1918) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC1918(decoded), true, - `${v} is RFC1918.`); - } - }); - - it('should determine non-RFC1918 IPs', () => { - for (const v of notRFC1918) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC1918(decoded), false, - `${v} is not RFC1918.`); - } - }); - }); - - describe('isRFC2544', function() { - const notRFC2544 = subtract(allVectors, vectors.RFC2544); - - it('should determine RFC2544 IPs', () => { - for (const v of vectors.RFC2544) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC2544(decoded), true, - `${v} is RFC2544.`); - } - }); - - it('should determine non-RFC2544 IPs', () => { - for (const v of notRFC2544) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC2544(decoded), false, - `${v} is not RFC2544.`); - } - }); - }); - - describe('isRFC3927', function() { - const notRFC3927 = subtract(allVectors, vectors.RFC3927); - - it('should determine RFC3927 IPs', () => { - for (const v of vectors.RFC3927) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC3927(decoded), true, - `${v} is RFC3927.`); - } - }); - - it('should determine non-RFC3927 IPs', () => { - for (const v of notRFC3927) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC3927(decoded), false, - `${v} is not RFC3927.`); - } - }); - }); - - describe('isRFC6598', function() { - const notRFC6598 = subtract(allVectors, vectors.RFC6598); - - it('should determine RFC6598 IPs', () => { - for (const v of vectors.RFC6598) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC6598(decoded), true, - `${v} is RFC6598.`); - } - }); - - it('should determine non-RFC6598 IPs', () => { - for (const v of notRFC6598) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC6598(decoded), false, - `${v} is not RFC6598.`); - } - }); - }); - - describe('isRFC5737', function() { - const notRFC5737 = subtract(allVectors, vectors.RFC5737); - - it('should determine RFC5737 IPs', () => { - for (const v of vectors.RFC5737) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC5737(decoded), true, - `${v} is RFC5737.`); - } - }); - - it('should determine non-RFC5737 IPs', () => { - for (const v of notRFC5737) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC5737(decoded), false, - `${v} is not RFC5737.`); - } - }); - }); + const vectorTests = [ + ['isNull', 'null', binet.isNull, vectors.NULL], + ['isBroadcast', 'broadcast', binet.isBroadcast, vectors.BROADCAST], + // IPv4 + ['isRFC1918', 'RFC 1918', binet.isRFC1918, vectors.RFC1918], + ['isRFC2544', 'RFC 2544', binet.isRFC2544, vectors.RFC2544], + ['isRFC3927', 'RFC 3927', binet.isRFC3927, vectors.RFC3927], + ['isRFC6598', 'RFC 6598', binet.isRFC6598, vectors.RFC6598], + ['isRFC5737', 'RFC 5737', binet.isRFC5737, vectors.RFC5737], + + // IPv6 + ['isRFC3849', 'RFC 3849', binet.isRFC3849, vectors.RFC3849], + ['isRFC3964', 'RFC 3964', binet.isRFC3964, vectors.RFC3964], + ['isRFC6052', 'RFC 6052', binet.isRFC6052, vectors.RFC6052], + ['isRFC4380', 'RFC 4380', binet.isRFC4380, vectors.RFC4380], + ['isRFC4862', 'RFC 4862', binet.isRFC4862, vectors.RFC4862], + ['isRFC4193', 'RFC 4193', binet.isRFC4193, vectors.RFC4193], + ['isRFC6145', 'RFC 6145', binet.isRFC6145, vectors.RFC6145], + ['isRFC4843', 'RFC 4843', binet.isRFC4843, vectors.RFC4843], + ['isRFC7343', 'RFC 7343', binet.isRFC7343, vectors.RFC7343], + + ['isIPV4', 'IPv4', binet.isIPv4, vectors.IPV4], + ['isIPV6', 'IPv6', binet.isIPv6, vectors.IPV6], + + // ['isValid', 'valid', vectors.VALID] + ]; + + for (const [desc, name, fn, vector] of vectorTests) { + describe(desc, function() { + const not = subtract(allVectors, vector); + + it(`should determine ${name} IPs`, () => { + for (const v of vector) { + const decoded = binet.decode(v); + assert.strictEqual(fn(decoded), true, + `${v} is ${name}.`); + } + }); + + it(`should determine non-${name} IPs`, () => { + for (const v of not) { + const decoded = binet.decode(v); + assert.strictEqual(fn(decoded), false, + `${v} is not ${name}.`); + } + }); + }); + } describe('isValid', function() { const invalidVectors = [ @@ -281,26 +186,6 @@ describe('binet', function() { } }); }); - - describe('isRFC3849', function() { - const notRFC3849 = subtract(allVectors, vectors.RFC3849); - - it('should determine RFC3849 IPs', () => { - for (const v of vectors.RFC3849) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC3849(decoded), true, - `${v} is valid RFC3849.`); - } - }); - - it('should determine non-RFC3849 IPs', () => { - for (const v of notRFC3849) { - const decoded = binet.decode(v); - assert.strictEqual(binet.isRFC3849(decoded), false, - `${v} is not RFC3849.`); - } - }); - }); }); function subtract(va, vb) { diff --git a/test/data/vectors.js b/test/data/vectors.js index 96be3ad..1e02f57 100644 --- a/test/data/vectors.js +++ b/test/data/vectors.js @@ -36,6 +36,16 @@ vectors.RFC1918 = [ '172.31.255.255' ]; +// RFC 1918 +1/-1 +vectors.RFC1918_BORDERS = [ + '9.255.255.255', + '11.0.0.0', + '172.15.255.255', + '172.32.0.0', + '192.167.255.255', + '192.169.0.0' +]; + // RFC 2544 - IPv4 inter-network communications // - 198.18.0.0/15 vectors.RFC2544 = [ @@ -45,6 +55,12 @@ vectors.RFC2544 = [ '198.19.255.255' ]; +// RFC 2544 +/- 1. +vectors.RFC2544_BORDERS = [ + '192.17.255.255', + '192.20.0.0' +]; + // RFC 3927 - Dynamic Configuration of IPv4 Link-Local Addresses // - 169.254/16 vectors.RFC3927 = [ @@ -53,6 +69,11 @@ vectors.RFC3927 = [ '169.254.255.255' ]; +vectors.RFC3927_BORDERS = [ + '169.243.255.255', + '169.255.0.0' +]; + // RFC 6598 - IANA-Reserved IPv4 Prefix for Shared Address Space // - 100.64.0.0/10 vectors.RFC6598 = [ @@ -63,6 +84,11 @@ vectors.RFC6598 = [ '100.127.255.255' ]; +vectors.RFC6598_BORDERS = [ + '100.64.255.255', + '100.128.0.0' +]; + // RFC 5737 - IPv4 Address Blocks Reserved for Documentation // - 192.0.2.0/24 (TEST-NET-1) // - 198.51.100.0/24 (TEST-NET-2) @@ -79,7 +105,16 @@ vectors.RFC5737 = [ '203.0.113.255' ]; -// RFC3849 - IPv6 Reserved prefix +vectors.RFC5737_BORDERS = [ + '192.0.1.255', + '192.0.3.0', + '198.51.99.255', + '198.51.101.0', + '203.0.112.255', + '203.0.114.0' +]; + +// RFC 3849 - IPv6 Reserved prefix // 2001:DB8::/32 vectors.RFC3849 = [ '2001:0db8::', @@ -89,32 +124,229 @@ vectors.RFC3849 = [ '2001:0db8:ffff:ffff:ffff:ffff:ffff:ffff' ]; +vectors.RFC3849_BORDERS = [ + '2001:db9::', + '2001:db7:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +// RFC 3964 - Security Considerations for 6to4 +// 2002::/16 +vectors.RFC3964 = [ + '2002::', + '2002::1', + '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.RFC3964_BORDERS = [ + '2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + '2003::' +]; + +// RFC 6052 - IPv6 Addressing of IPv4/IPv6 Translators +// 64:ff9b::/96 +vectors.RFC6052 = [ + '64:ff9b::', + '0064:ff9b::ffff:ffff' +]; + +vectors.RFC6052_BORDERS = [ + '64:ff9b::1:0:0', + '64:ff9a:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +// RFC 4380 - Teredo: Tunneling IPv6 over UDP +// through Network Address Translations (NATs) +// 2001:0000:/32 +vectors.RFC4380 = [ + '2001::', + '2001::1', + '2001:0:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.RFC4380_BORDERS = [ + '2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + '2001:1::' +]; + +// RFC 4862 - IPv6 Stateless Address Autoconfiguration +// fe80::/64 +vectors.RFC4862 = [ + 'fe80::', + 'fe80::1', + 'fe80::ffff:ffff:ffff:ffff' +]; + +vectors.RFC4862_BORDER = [ + 'fe79:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + 'fe80:0:0:1::' +]; + +// RFC 4193 - Unique Local IPv6 Unicast Addresses +// fc00::/7 +vectors.RFC4193 = [ + 'fc00::', + 'fc00::1', + 'fcff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + 'fd00::', + 'fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.RFC4193_BORDERS = [ + 'fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', + 'fe00::' +]; + +// RFC 6145 - IP/ICMP Translation Algorithm +// updates RFC 2765 for IPv4 translated. +// 0::ffff:0:0:0/96 + +vectors.RFC6145 = [ + '0::ffff:0:0:0', + '0::ffff:0:0:1', + '0::ffff:0:ffff:ffff' +]; + +vectors.RFC6145_BORDERS = [ + '0::fffe:ffff:ffff:ffff', + '0::ffff:1:0:0' +]; + +// RFC 4843 - An IPv6 Prefix for +// Overlay Routable Cryptographic Hash Identifiers (ORCHID) +// 2001:10::/28 + +vectors.RFC4843 = [ + '2001:10::', + '2001:10::1', + '2001:1f:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.RFC4843_BORDERS = [ + '2001:f:ffff:ffff:ffff:ffff:ffff:ffff', + '2001:20::' // ORCHIDv2 - should match with RFC7343 test below +]; + +// RFC 7343 - An IPv6 Prefix for +// Overlay Routable Cryptographic Hash Identifiers Version 2 +// (ORCHIDv2) +// 2001:20::/28 +vectors.RFC7343 = [ + '2001:20::', + '2001:20::1', + '2001:002f:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.RFC7343_BORDERS = [ + '2001:1f:ffff:ffff:ffff:ffff:ffff:ffff', // ORCHID v1 + '2001:30::' +]; + // IPV4 vectors.IPV4 = [ '0.0.0.0', - '255.255.255.255', + ...vectors.BROADCAST, + + // RFC 1918 ...vectors.RFC1918, + ...vectors.RFC1918_BORDERS, + // RFC 2544 ...vectors.RFC2544, + ...vectors.RFC2544_BORDERS, + + // RFC 3927 ...vectors.RFC3927, + ...vectors.RFC3927_BORDERS, + + // RFC 6598 ...vectors.RFC6598, - ...vectors.RFC5737 + ...vectors.RFC6598_BORDERS, + + ...vectors.RFC5737, + ...vectors.RFC5737_BORDERS ]; vectors.IPV6 = [ '::', - ...vectors.RFC3849 + // this is still IPv6? + ...vectors.SHIFTED, + + ...vectors.RFC3849, + ...vectors.RFC3849_BORDERS, + + ...vectors.RFC3964, + ...vectors.RFC3964_BORDERS, + + ...vectors.RFC6052, + ...vectors.RFC6052_BORDERS, + + ...vectors.RFC4380, + ...vectors.RFC4380_BORDERS, + + ...vectors.RFC4862, + ...vectors.RFC4862_BORDER, + + ...vectors.RFC4193, + ...vectors.RFC4193_BORDERS, + + ...vectors.RFC6145, + ...vectors.RFC6145_BORDERS, + + ...vectors.RFC4843, + ...vectors.RFC4843_BORDERS, + + ...vectors.RFC7343, + ...vectors.RFC7343_BORDERS ]; vectors.all = [ - ...vectors.SHIFTED, - ...vectors.NULL, - ...vectors.BROADCAST, - ...vectors.RFC1918, - ...vectors.RFC2544, - ...vectors.RFC3927, - ...vectors.RFC6598, - ...vectors.RFC5737, - ...vectors.RFC3849, - ...vectors.IPV4, - ...vectors.IPV6 + vectors.SHIFTED, + vectors.NULL, + vectors.BROADCAST, + + // IPv4 + vectors.RFC1918, + vectors.RFC1918_BORDERS, + + vectors.RFC2544, + vectors.RFC2544_BORDERS, + + vectors.RFC3927, + vectors.RFC3927_BORDERS, + + vectors.RFC6598, + vectors.RFC6598_BORDERS, + + vectors.RFC5737, + vectors.RFC5737_BORDERS, + + // IPv6 + vectors.RFC3849, + vectors.RFC3849_BORDERS, + + vectors.RFC3964, + vectors.RFC3964_BORDERS, + + vectors.RFC6052, + vectors.RFC6052_BORDERS, + + vectors.RFC4380, + vectors.RFC4380_BORDERS, + + vectors.RFC4862, + vectors.RFC4862_BORDER, + + vectors.RFC4193, + vectors.RFC4193_BORDERS, + + vectors.RFC6145, + vectors.RFC6145_BORDERS, + + vectors.RFC4843, + vectors.RFC4843_BORDERS, + + vectors.RFC7343, + vectors.RFC7343_BORDERS, + + vectors.IPV4, + vectors.IPV6 ]; From 1f33c5e3f4b1342b75749ca8a7f65d4162f77ffe Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sun, 26 Dec 2021 23:19:45 +0400 Subject: [PATCH 4/6] test: add method vectors. - isLocal - isMulticast - isValid - isRoutable - isOnion - getNetwork --- test/binet-test.js | 155 +++++++++++++++++++------------------------ test/data/vectors.js | 139 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 200 insertions(+), 94 deletions(-) diff --git a/test/binet-test.js b/test/binet-test.js index 7f1962c..158cb13 100644 --- a/test/binet-test.js +++ b/test/binet-test.js @@ -4,15 +4,7 @@ const assert = require('assert'); const binet = require('../lib/binet'); const vectors = require('./data/vectors'); -const allVectors = vectors.all.reduce((p, c) => add(p, c)); - -const { - NONE, - INET4, - INET6, - ONION, - TEREDO -} = binet.networks; +const allVectors = vectors.ALL.reduce((p, c) => add(p, c)); describe('binet', function() { it('should convert binary addresses to string addresses', () => { @@ -50,56 +42,6 @@ describe('binet', function() { } }); - it('should getNetwork', () => { - assert.equal(binet.getNetwork(binet.decode('127.0.0.1')), NONE); - assert.equal(binet.getNetwork(binet.decode('::1')), NONE); - assert.equal(binet.getNetwork(binet.decode('8.8.8.8')), INET4); - assert.equal(binet.getNetwork(binet.decode('8888::8888')), INET6); - assert.equal(binet.getNetwork(binet.decode('2001::')), TEREDO); - assert.equal(binet.getNetwork(binet.decode('FD87:D87E:EB43:edb1:8e4:3588:e546:35ca')), ONION); - }); - - it('should return the correct property', () => { - assert(binet.isIPv4(binet.decode('127.0.0.1'))); - assert(binet.isIPv4(binet.decode('::FFFF:192.168.1.1'))); - assert(binet.isIPv6(binet.decode('::1'))); - assert(binet.isRFC3964(binet.decode('2002::1'))); - assert(binet.isRFC4193(binet.decode('FC00::'))); - assert(binet.isRFC4843(binet.decode('2001:10::'))); - assert(binet.isRFC4862(binet.decode('FE80::'))); - assert(binet.isRFC6052(binet.decode('64:FF9B::'))); - assert( - binet.isOnion(binet.decode('FD87:D87E:EB43:edb1:8e4:3588:e546:35ca')) - ); - - // isLocal should return true for: - // - IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8) - // - IPv6 loopback (::1/128) - assert(binet.isLocal(binet.decode('127.0.0.1'))); - assert(binet.isLocal(binet.decode('::1'))); - assert(binet.isLocal(binet.decode('0.1.0.0'))); - assert(!binet.isLocal(binet.decode('1.0.0.0'))); - assert(!binet.isLocal(binet.decode('::2'))); - - // isRFC7343 should return true for: - // - IPv6 ORCHIDv2 (2001:20::/28) - assert(binet.isRFC7343(binet.decode('2001:20::'))); - assert( - binet.isRFC7343(binet.decode('2001:2f:ffff:ffff:ffff:ffff:ffff:ffff')) - ); - assert(!binet.isRFC7343(binet.decode('2002:20::'))); - assert(!binet.isRFC7343(binet.decode('0.0.0.0'))); - // isRFC4380 should return true for: - // - IPv6 Teredo tunnelling (2001::/32) - assert(binet.isRFC4380(binet.decode('2001::2'))); - assert(binet.isRFC4380(binet.decode('2001:0:ffff:ffff:ffff:ffff:ffff:ffff'))); - assert(!binet.isRFC4380(binet.decode('2002::'))); - assert(!binet.isRFC4380(binet.decode('2001:1:ffff:ffff:ffff:ffff:ffff:ffff'))); - assert(binet.isRoutable(binet.decode('8.8.8.8'))); - assert(binet.isRoutable(binet.decode('2001::1'))); - assert(binet.isValid(binet.decode('127.0.0.1'))); - }); - it('should convert back and forth', () => { for (const v of allVectors) { const norm = binet.normalize(v); @@ -113,6 +55,8 @@ describe('binet', function() { const vectorTests = [ ['isNull', 'null', binet.isNull, vectors.NULL], ['isBroadcast', 'broadcast', binet.isBroadcast, vectors.BROADCAST], + ['isLocal', 'local', binet.isLocal, vectors.LOCAL], + // IPv4 ['isRFC1918', 'RFC 1918', binet.isRFC1918, vectors.RFC1918], ['isRFC2544', 'RFC 2544', binet.isRFC2544, vectors.RFC2544], @@ -134,74 +78,109 @@ describe('binet', function() { ['isIPV4', 'IPv4', binet.isIPv4, vectors.IPV4], ['isIPV6', 'IPv6', binet.isIPv6, vectors.IPV6], - // ['isValid', 'valid', vectors.VALID] + ['isMulticast', 'multicast', binet.isMulticast, vectors.MULTICAST], + ['isValid', 'invalid', v => !binet.isValid(v), vectors.INVALID], + ['isRoutable', 'non-routable', + v => !binet.isRoutable(v), vectors.UNROUTABLE] ]; for (const [desc, name, fn, vector] of vectorTests) { describe(desc, function() { - const not = subtract(allVectors, vector); + const not = sub(allVectors, vector); it(`should determine ${name} IPs`, () => { for (const v of vector) { const decoded = binet.decode(v); - assert.strictEqual(fn(decoded), true, - `${v} is ${name}.`); + assert.strictEqual(fn(decoded), true, `${v} is ${name}.`); } }); it(`should determine non-${name} IPs`, () => { for (const v of not) { const decoded = binet.decode(v); - assert.strictEqual(fn(decoded), false, - `${v} is not ${name}.`); + assert.strictEqual(fn(decoded), false, `${v} is not ${name}.`); } }); }); } - describe('isValid', function() { - const invalidVectors = [ - ...vectors.SHIFTED, - ...vectors.NULL, - ...vectors.BROADCAST, - ...vectors.RFC3849 - ]; - - const validVectors = subtract(allVectors, invalidVectors); + describe('isOnion', function() { + const notOnion = add( + sub(allVectors, vectors.ONION), + vectors.ONION_BORDERS + ); - it('should validate valid IPs', () => { - for (const v of validVectors) { + it('should determine onion IPs', () => { + for (const v of vectors.ONION) { const decoded = binet.decode(v); - assert.strictEqual(binet.isValid(decoded), true, - `${v} is valid.`); + assert.strictEqual(binet.isOnion(decoded), true, `${v} is Onion.`); } }); - it('should validate invalid IPs', () => { - for (const v of invalidVectors) { + // This is special case for Routable, RFC4193 is not while Onion is routable. + it('should be routable', () => { + for (const v of vectors.ONION) { const decoded = binet.decode(v); + assert.strictEqual(binet.isRoutable(decoded), true, + `${v} is Routable.`); + } + }); - assert.strictEqual(binet.isValid(decoded), false, - `${v} is invalid.`); + it('should determine non-onion IPs', () => { + for (const v of notOnion) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isOnion(decoded), false, `${v} is not Onion.`); } }); }); + + describe('getNetwork', function() { + const gnVectors = { + NONE: add(vectors.UNROUTABLE), + INET4: sub(vectors.IPV4, vectors.UNROUTABLE), + TEREDO: vectors.RFC4380, + ONION: vectors.ONION, + INET6: sub( + allVectors, + vectors.UNROUTABLE, + vectors.IPV4, + vectors.RFC4380, + vectors.ONION + ) + }; + + for (const [id, gnVector] of Object.entries(gnVectors)) { + it(`should get ${id}`, () => { + for (const v of gnVector) { + const d = binet.decode(v); + assert.strictEqual(binet.getNetwork(d), binet.networks[id], + `network of ${v} is ${id}.`); + } + }); + } + }); }); -function subtract(va, vb) { +function sub(va, ...args) { + assert(args.length > 0); const sa = new Set(va); - for (const vector of vb) - sa.delete(vector); + for (const vb of args) { + for (const vector of vb) + sa.delete(vector); + } return Array.from(sa); } -function add(va, vb) { +function add(va, ...args) { + assert(args.length >= 0); const sa = new Set(va); - for (const vector of vb) - sa.add(vector); + for (const vb of args) { + for (const vector of vb) + sa.add(vector); + } return Array.from(sa); } diff --git a/test/data/vectors.js b/test/data/vectors.js index 1e02f57..a23e2c8 100644 --- a/test/data/vectors.js +++ b/test/data/vectors.js @@ -20,6 +20,67 @@ vectors.BROADCAST = [ '255.255.255.255' ]; +// Local +// 127.0.0.0/8 +// 0.0.0.0/8 +vectors.LOCAL_IPV4 = [ + '127.0.0.0', + '127.0.0.1', + '127.255.255.255', + '0.0.0.0', + '0.0.0.1', + '0.1.0.1', + '0.255.255.255' +]; + +// ::1/128 +vectors.LOCAL_IPV6 = [ + '::1' +]; + +vectors.LOCAL = [ + ...vectors.LOCAL_IPV4, + ...vectors.LOCAL_IPV6 +]; + +// Multicast +// IPv4 - RFC3171 +// 224.0.0.0/4 +vectors.MULTICAST_IPV4 = [ + '224.0.0.0', + '224.0.0.1', + '230.100.100.100', + '239.255.255.255' +]; + +vectors.MULTICAST_IPV4_BORDERS = [ + '223.255.255.255', + '240.0.0.0' +]; + +// IPv6 - RFC4291 +// ff00::/8 +vectors.MULTICAST_IPV6 = [ + 'ff00::', + 'ff00::1', + 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.MULTICAST_IPV6_BORDERS = [ + 'feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +// Multicast combined +vectors.MULTICAST = [ + ...vectors.MULTICAST_IPV4, + ...vectors.MULTICAST_IPV6 +]; + +vectors.MULTICAST_BORDERS = [ + ...vectors.MULTICAST_IPV4_BORDERS, + ...vectors.MULTICAST_IPV6_BORDERS +]; + // RFC 1918 - Private Internets // - 10/8 // - 172.16/12 @@ -134,6 +195,7 @@ vectors.RFC3849_BORDERS = [ vectors.RFC3964 = [ '2002::', '2002::1', + '2002:20::', '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff' ]; @@ -165,7 +227,9 @@ vectors.RFC4380 = [ vectors.RFC4380_BORDERS = [ '2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff', - '2001:1::' + '2001:1::', + '2002::', + '2001:1:ffff:ffff:ffff:ffff:ffff:ffff' ]; // RFC 4862 - IPv6 Stateless Address Autoconfiguration @@ -182,6 +246,7 @@ vectors.RFC4862_BORDER = [ ]; // RFC 4193 - Unique Local IPv6 Unicast Addresses +// NOTE: Make sure these tests do not include Onion // fc00::/7 vectors.RFC4193 = [ 'fc00::', @@ -199,7 +264,6 @@ vectors.RFC4193_BORDERS = [ // RFC 6145 - IP/ICMP Translation Algorithm // updates RFC 2765 for IPv4 translated. // 0::ffff:0:0:0/96 - vectors.RFC6145 = [ '0::ffff:0:0:0', '0::ffff:0:0:1', @@ -214,7 +278,6 @@ vectors.RFC6145_BORDERS = [ // RFC 4843 - An IPv6 Prefix for // Overlay Routable Cryptographic Hash Identifiers (ORCHID) // 2001:10::/28 - vectors.RFC4843 = [ '2001:10::', '2001:10::1', @@ -233,19 +296,42 @@ vectors.RFC4843_BORDERS = [ vectors.RFC7343 = [ '2001:20::', '2001:20::1', - '2001:002f:ffff:ffff:ffff:ffff:ffff:ffff' + '2001:2f:ffff:ffff:ffff:ffff:ffff:ffff' ]; vectors.RFC7343_BORDERS = [ '2001:1f:ffff:ffff:ffff:ffff:ffff:ffff', // ORCHID v1 - '2001:30::' + '2001:30::', + '2002:20::' // RFC 3964 +]; + +// Onion +// fd87:d87e:eb43::/48 +vectors.ONION = [ + 'fd87:d87e:eb43::', + 'fd87:d87e:eb43::1', + 'fd87:d87e:eb43:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.ONION_BORDERS = [ + 'fd87:d87e:eb42:ffff:ffff:ffff:ffff:ffff', + 'fd87:d87e:eb44::' ]; // IPV4 vectors.IPV4 = [ '0.0.0.0', + '::ffff:199.200.201.202', + ...vectors.BROADCAST, + // local and IPv4 + ...vectors.LOCAL_IPV4, + + // Multicast + ...vectors.MULTICAST_IPV4, + ...vectors.MULTICAST_IPV4_BORDERS, + // RFC 1918 ...vectors.RFC1918, ...vectors.RFC1918_BORDERS, @@ -267,9 +353,17 @@ vectors.IPV4 = [ vectors.IPV6 = [ '::', + // this is still IPv6? ...vectors.SHIFTED, + // local but IPv6 + ...vectors.LOCAL_IPV6, + + // Multicast + ...vectors.MULTICAST_IPV6, + ...vectors.MULTICAST_IPV6_BORDERS, + ...vectors.RFC3849, ...vectors.RFC3849_BORDERS, @@ -296,12 +390,41 @@ vectors.IPV6 = [ ...vectors.RFC7343, ...vectors.RFC7343_BORDERS + + // Because it's also part of RFC4193, we will test them separately. + // ...vectors.ONION, + // ...vectors.ONION_BORDERS +]; + +vectors.INVALID = [ + ...vectors.SHIFTED, + ...vectors.NULL, + ...vectors.BROADCAST, + ...vectors.RFC3849 ]; -vectors.all = [ +vectors.UNROUTABLE = [ + ...vectors.INVALID, + ...vectors.RFC1918, + ...vectors.RFC2544, + ...vectors.RFC3927, + ...vectors.RFC4862, + ...vectors.RFC6598, + ...vectors.RFC5737, + ...vectors.RFC4193, + ...vectors.RFC4843, + ...vectors.RFC7343, + ...vectors.LOCAL +]; + +vectors.ALL = [ vectors.SHIFTED, vectors.NULL, vectors.BROADCAST, + vectors.LOCAL, + + vectors.MULTICAST, + vectors.MULTICAST_BORDERS, // IPv4 vectors.RFC1918, @@ -347,6 +470,10 @@ vectors.all = [ vectors.RFC7343, vectors.RFC7343_BORDERS, + // Because it's also part of RFC4193, we will test them separately. + // vectors.ONION, + // vectors.ONION_BORDERS, + vectors.IPV4, vectors.IPV6 ]; From 9108d8d3f828ea80a5660b1466daeb8198787eea Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sun, 26 Dec 2021 23:21:27 +0400 Subject: [PATCH 5/6] ci: fix linter. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5cc157f..5a14673 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "author": "Christopher Jeffrey ", "main": "./lib/binet.js", "scripts": { - "lint": "eslint lib/ test/ || exit 0", + "lint": "eslint lib/ test/", "test": "bmocha --reporter spec test/*-test.js", "test-ci": "nyc --reporter lcov bmocha -- --reporter spec test/*.js" }, From d05072d9a775e2243881ea5dce448bdc6f035932 Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Mon, 27 Dec 2021 16:16:33 +0400 Subject: [PATCH 6/6] ip: fix getReachability bugs and add tests. --- lib/ip.js | 12 +++--- test/binet-test.js | 88 ++++++++++++++++++++++++++++++++++++++++++++ test/data/vectors.js | 1 + 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/lib/ip.js b/lib/ip.js index 63e6579..63f458e 100644 --- a/lib/ip.js +++ b/lib/ip.js @@ -1301,9 +1301,9 @@ binet.getReachability = function getReachability(src, dest) { const destNet = binet.getNetwork(dest); switch (destNet) { - case networks.IPV4: + case networks.INET4: switch (srcNet) { - case networks.IPV4: + case networks.INET4: return IPV4; default: return DEFAULT; @@ -1313,7 +1313,7 @@ binet.getReachability = function getReachability(src, dest) { switch (srcNet) { case networks.TEREDO: return TEREDO; - case networks.IPV4: + case networks.INET4: return IPV4; case networks.INET6: if (binet.isRFC3964(src) @@ -1329,7 +1329,7 @@ binet.getReachability = function getReachability(src, dest) { break; case networks.ONION: switch (srcNet) { - case networks.IPV4: + case networks.INET4: return IPV4; case networks.ONION: return PRIVATE; @@ -1343,7 +1343,7 @@ binet.getReachability = function getReachability(src, dest) { return TEREDO; case networks.INET6: return IPV6_WEAK; - case networks.IPV4: + case networks.INET4: return IPV4; default: return DEFAULT; @@ -1355,7 +1355,7 @@ binet.getReachability = function getReachability(src, dest) { return TEREDO; case networks.INET6: return IPV6_WEAK; - case networks.IPV4: + case networks.INET4: return IPV4; case networks.ONION: return PRIVATE; diff --git a/test/binet-test.js b/test/binet-test.js index 158cb13..ef748ec 100644 --- a/test/binet-test.js +++ b/test/binet-test.js @@ -159,6 +159,94 @@ describe('binet', function() { }); } }); + + describe('getReachability', function() { + const scores = { + UNREACHABLE: 0, + DEFAULT: 1, + TEREDO: 2, + IPV6_WEAK: 3, + IPV4: 4, + IPV6_STRONG: 5, + PRIVATE: 6 + }; + + const IPV4s = sub(vectors.IPV4, vectors.UNROUTABLE); + const TEREDOs = vectors.RFC4380; + const ONIONs = vectors.ONION; + const IPV6s = sub(allVectors, + vectors.UNROUTABLE, + vectors.IPV4, + vectors.RFC4380, + vectors.RFC3964, + vectors.RFC6052, + vectors.RFC6145, + vectors.ONION + ); + + const testVectors = [ + {destName: 'IPv4', destStr: IPV4s[0], srcVector: [ + [IPV4s[1], 'IPV4', 'IPv4'], + [TEREDOs[0], 'DEFAULT', 'TEREDO'], + [ONIONs[0], 'DEFAULT', 'ONION'], + [IPV6s[0], 'DEFAULT', 'IPv6'] + ]}, + {destName: 'IPv6', destStr: IPV6s[0], srcVector: [ + [IPV4s[0], 'IPV4', 'IPv4'], + [TEREDOs[0], 'TEREDO', 'TEREDO'], + [vectors.RFC3964[0], 'IPV6_WEAK', 'RFC3964'], + [vectors.RFC6052[0], 'IPV6_WEAK', 'RFC6052'], + [vectors.RFC6145[0], 'IPV6_WEAK', 'RFC6145'], + [IPV6s[0], 'IPV6_STRONG', 'IPv6'], + [ONIONs[0], 'DEFAULT', 'ONION'] + ]}, + {destName: 'ONION', destStr: ONIONs[0], srcVector: [ + [IPV4s[0], 'IPV4', 'IPv4'], + [ONIONs[1], 'PRIVATE', 'ONION'], + [TEREDOs[0], 'DEFAULT', 'TEREDO'], + [IPV6s[0], 'DEFAULT', 'IPv6'] + ]}, + {destName: 'TEREDO', destStr: TEREDOs[0], srcVector: [ + [TEREDOs[1], 'TEREDO', 'TEREDO'], + [IPV6s[0], 'IPV6_WEAK', 'IPv6'], + [IPV4s[0], 'IPV4', 'IPv4'], + [ONIONs[0], 'DEFAULT', 'ONION'] + ]}, + {destName: 'UNREACHABLE', destStr: vectors.UNROUTABLE[0], srcVector: [ + [TEREDOs[1], 'TEREDO', 'TEREDO'], + [IPV6s[0], 'IPV6_WEAK', 'IPv6'], + [IPV4s[0], 'IPV4', 'IPv4'], + [ONIONs[0], 'PRIVATE', 'ONION'] + ]} + ]; + + it('should return UNREACHABLE when source is not routable', () => { + for (const v of vectors.UNROUTABLE) { + const src = binet.decode(v); + + // For this test, destination does not matter + const score = binet.getReachability(src, null); + + assert.strictEqual(score, scores.UNREACHABLE, + `destination is UNREACHABLE from ${src}.`); + } + }); + + for (const {destName, destStr, srcVector} of testVectors) { + it(`should work with ${destName} as destionaion`, () => { + const dest = binet.decode(destStr); + + for (const [srcStr, expected, srcName] of srcVector) { + const src = binet.decode(srcStr); + const score = binet.getReachability(src, dest); + + assert.strictEqual(score, scores[expected], + `${srcName} to ${destName} must have ${expected} score` + + ` for ${srcStr}->${destStr}.`); + } + }); + } + }); }); function sub(va, ...args) { diff --git a/test/data/vectors.js b/test/data/vectors.js index a23e2c8..f780a62 100644 --- a/test/data/vectors.js +++ b/test/data/vectors.js @@ -404,6 +404,7 @@ vectors.INVALID = [ ]; vectors.UNROUTABLE = [ + '::', ...vectors.INVALID, ...vectors.RFC1918, ...vectors.RFC2544,