diff --git a/lib/primitives/netaddress.js b/lib/primitives/netaddress.js index 9ec8b280..a58e74b1 100644 --- a/lib/primitives/netaddress.js +++ b/lib/primitives/netaddress.js @@ -168,6 +168,16 @@ NetAddress.prototype.isOnion = function isOnion() { return IP.isOnion(this.raw); }; +/** + * Get reachable score to destination. + * @param {NetAddress} dest + * @returns {Number} + */ + +NetAddress.prototype.getReachability = function getReachability(dest) { + return IP.getReachability(this.raw, dest.raw); +}; + /** * Set null host. */ diff --git a/lib/utils/ip.js b/lib/utils/ip.js index b332ef69..13f2ebcb 100644 --- a/lib/utils/ip.js +++ b/lib/utils/ip.js @@ -52,7 +52,8 @@ IP.types = { DNS: -1, IPV4: 4, IPV6: 6, - ONION: 10 + ONION: 10, + TEREDO: 11 }; /** @@ -493,6 +494,20 @@ IP.getType = function getType(raw) { assert(false, 'Unknown type.'); }; +/** + * Get addr network. Similar to + * type, but includes teredo. + * @param {Buffer} raw + * @returns {Number} + */ + +IP.getNetwork = function getNetwork(raw) { + if (IP.isRFC4380(raw)) + return IP.types.TEREDO; + + return IP.getType(raw); +}; + /** * Test whether the host is null. * @returns {Boolean} @@ -832,6 +847,94 @@ IP.isRoutable = function isRoutable(raw) { return true; }; +/** + * Calculate reachable score from source to destination. + * @param {Buffer} src + * @param {Buffer} dest + * @returns {Number} Ranges from 0-6. + */ + +IP.getReachability = function getReachability(src, dest) { + var srcNet = IP.getNetwork(src); + var destNet = IP.getNetwork(dest); + var types = IP.types; + var UNREACHABLE = 0; + var DEFAULT = 1; + var TEREDO = 2; + var IPV6_WEAK = 3; + var IPV4 = 4; + var IPV6_STRONG = 5; + var PRIVATE = 6; + + if (!IP.isRoutable(src)) + return UNREACHABLE; + + switch (destNet) { + case types.IPV4: + switch (srcNet) { + case types.IPV4: + return IPV4; + default: + return DEFAULT; + } + break; + case types.IPV6: + switch (srcNet) { + case types.TEREDO: + return TEREDO; + case types.IPV4: + return IPV4; + case types.IPV6: + if (IP.isRFC3964(src) + || IP.isRFC6052(src) + || IP.isRFC6145(src)) { + // tunnel + return IPV6_WEAK; + } + return IPV6_STRONG; + default: + return DEFAULT; + } + break; + case types.ONION: + switch (srcNet) { + case types.IPV4: + return IPV4; + case types.ONION: + return PRIVATE; + default: + return DEFAULT; + } + break; + case types.TEREDO: + switch (srcNet) { + case types.TEREDO: + return TEREDO; + case types.IPV6: + return IPV6_WEAK; + case types.IPV4: + return IPV4; + default: + return DEFAULT; + } + break; + default: + switch (srcNet) { + case types.TEREDO: + return TEREDO; + case types.IPV6: + return IPV6_WEAK; + case types.IPV4: + return IPV4; + case types.ONION: + return PRIVATE; + default: + return DEFAULT; + } + break; + } +}; + /** * Test whether an IP has a prefix. * @param {Buffer} raw