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/lib/ip.js b/lib/ip.js index 26d0be3..63f458e 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'); @@ -1300,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; @@ -1312,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) @@ -1328,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; @@ -1342,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; @@ -1354,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; @@ -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; 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" }, diff --git a/test/binet-test.js b/test/binet-test.js index 6ef8415..ef748ec 100644 --- a/test/binet-test.js +++ b/test/binet-test.js @@ -1,32 +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 { - 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', () => { @@ -65,75 +43,232 @@ 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); + for (const v of allVectors) { + const norm = binet.normalize(v); + const raw = binet.decode(v); + const encoded = binet.encode(raw); - assert.strictEqual(binet.encode(raw4), ip4); - assert.strictEqual(binet.encode(raw6), ip6); + assert.strictEqual(encoded, norm); + } }); - 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::'))); - 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')) - ); + 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], + ['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], + + ['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 = sub(allVectors, vector); - // 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) - 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')) + 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('isOnion', function() { + const notOnion = add( + sub(allVectors, vectors.ONION), + vectors.ONION_BORDERS ); - 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 determine onion IPs', () => { + for (const v of vectors.ONION) { + const decoded = binet.decode(v); + assert.strictEqual(binet.isOnion(decoded), true, `${v} is Onion.`); + } + }); + + // 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.`); + } + }); + + 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}.`); + } + }); + } }); - 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); + 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) { + assert(args.length > 0); + const sa = new Set(va); + + for (const vb of args) { + for (const vector of vb) + sa.delete(vector); + } + + return Array.from(sa); +} + +function add(va, ...args) { + assert(args.length >= 0); + const sa = new Set(va); + + 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 new file mode 100644 index 0000000..f780a62 --- /dev/null +++ b/test/data/vectors.js @@ -0,0 +1,480 @@ +'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' +]; + +// 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 +// - 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 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 = [ + '198.18.0.0', + '198.18.255.255', + '198.19.0.0', + '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 = [ + '169.254.0.0', + '169.254.1.1', + '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 = [ + '100.64.0.0', + '100.64.255.255', + '100.100.100.100', + '100.100.200.200', + '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) +// - 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' +]; + +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::', + '2001:db8::', + '2001:db8::1:1', + '2001:db8:85a3::8a2e:370:7334', + '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:20::', + '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::', + '2002::', + '2001:1:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +// 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 +// NOTE: Make sure these tests do not include Onion +// 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:2f:ffff:ffff:ffff:ffff:ffff:ffff' +]; + +vectors.RFC7343_BORDERS = [ + '2001:1f:ffff:ffff:ffff:ffff:ffff:ffff', // ORCHID v1 + '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, + // RFC 2544 + ...vectors.RFC2544, + ...vectors.RFC2544_BORDERS, + + // RFC 3927 + ...vectors.RFC3927, + ...vectors.RFC3927_BORDERS, + + // RFC 6598 + ...vectors.RFC6598, + ...vectors.RFC6598_BORDERS, + + ...vectors.RFC5737, + ...vectors.RFC5737_BORDERS +]; + +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, + + ...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 + + // 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.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, + 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, + + // Because it's also part of RFC4193, we will test them separately. + // vectors.ONION, + // vectors.ONION_BORDERS, + + vectors.IPV4, + vectors.IPV6 +];