IP.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /* globals BigInteger */
  2. /**
  3. * Internet Protocol address operations.
  4. *
  5. * @author n1474335 [n1474335@gmail.com]
  6. * @copyright Crown Copyright 2016
  7. * @license Apache-2.0
  8. *
  9. * @namespace
  10. */
  11. var IP = {
  12. /**
  13. * @constant
  14. * @default
  15. */
  16. INCLUDE_NETWORK_INFO: true,
  17. /**
  18. * @constant
  19. * @default
  20. */
  21. ENUMERATE_ADDRESSES: true,
  22. /**
  23. * @constant
  24. * @default
  25. */
  26. ALLOW_LARGE_LIST: false,
  27. /**
  28. * Parse IP range operation.
  29. *
  30. * @param {string} input
  31. * @param {Object[]} args
  32. * @returns {string}
  33. */
  34. runParseIpRange: function (input, args) {
  35. var includeNetworkInfo = args[0],
  36. enumerateAddresses = args[1],
  37. allowLargeList = args[2];
  38. // Check what type of input we are looking at
  39. var ipv4CidrRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\/(\d\d?)\s*$/,
  40. ipv4RangeRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*-\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
  41. ipv6CidrRegex = /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\/(\d\d?\d?)\s*$/i,
  42. ipv6RangeRegex = /^\s*(((?=.*::)(?!.*::[^-]+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*-\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\17)::|:\b|(?![\dA-F])))|(?!\16\17)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
  43. match;
  44. if ((match = ipv4CidrRegex.exec(input))) {
  45. return IP._ipv4CidrRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
  46. } else if ((match = ipv4RangeRegex.exec(input))) {
  47. return IP._ipv4HyphenatedRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
  48. } else if ((match = ipv6CidrRegex.exec(input))) {
  49. return IP._ipv6CidrRange(match, includeNetworkInfo);
  50. } else if ((match = ipv6RangeRegex.exec(input))) {
  51. return IP._ipv6HyphenatedRange(match, includeNetworkInfo);
  52. } else {
  53. return "Invalid input.\n\nEnter either a CIDR range (e.g. 10.0.0.0/24) or a hyphenated range (e.g. 10.0.0.0 - 10.0.1.0). IPv6 also supported.";
  54. }
  55. },
  56. /**
  57. * @constant
  58. * @default
  59. */
  60. IPV4_REGEX: /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
  61. /**
  62. * @constant
  63. * @default
  64. */
  65. IPV6_REGEX: /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
  66. /**
  67. * Parse IPv6 address operation.
  68. *
  69. * @param {string} input
  70. * @param {Object[]} args
  71. * @returns {string}
  72. */
  73. runParseIpv6: function (input, args) {
  74. var match,
  75. output = "";
  76. if ((match = IP.IPV6_REGEX.exec(input))) {
  77. var ipv6 = IP._strToIpv6(match[1]),
  78. longhand = IP._ipv6ToStr(ipv6),
  79. shorthand = IP._ipv6ToStr(ipv6, true);
  80. output += "Longhand: " + longhand + "\nShorthand: " + shorthand + "\n";
  81. // Detect reserved addresses
  82. if (shorthand === "::") {
  83. // Unspecified address
  84. output += "\nUnspecified address corresponding to 0.0.0.0/32 in IPv4.";
  85. output += "\nUnspecified address range: ::/128";
  86. } else if (shorthand === "::1") {
  87. // Loopback address
  88. output += "\nLoopback address to the local host corresponding to 127.0.0.1/8 in IPv4.";
  89. output += "\nLoopback addresses range: ::1/128";
  90. } else if (ipv6[0] === 0 && ipv6[1] === 0 && ipv6[2] === 0 &&
  91. ipv6[3] === 0 && ipv6[4] === 0 && ipv6[5] === 0xffff) {
  92. // IPv4-mapped IPv6 address
  93. output += "\nIPv4-mapped IPv6 address detected. IPv6 clients will be handled natively by default, and IPv4 clients appear as IPv6 clients at their IPv4-mapped IPv6 address.";
  94. output += "\nMapped IPv4 address: " + IP._ipv4ToStr((ipv6[6] << 16) + ipv6[7]);
  95. output += "\nIPv4-mapped IPv6 addresses range: ::ffff:0:0/96";
  96. } else if (ipv6[0] === 0 && ipv6[1] === 0 && ipv6[2] === 0 &&
  97. ipv6[3] === 0 && ipv6[4] === 0xffff && ipv6[5] === 0) {
  98. // IPv4-translated address
  99. output += "\nIPv4-translated address detected. Used by Stateless IP/ICMP Translation (SIIT). See RFCs 6145 and 6052 for more details.";
  100. output += "\nTranslated IPv4 address: " + IP._ipv4ToStr((ipv6[6] << 16) + ipv6[7]);
  101. output += "\nIPv4-translated addresses range: ::ffff:0:0:0/96";
  102. } else if (ipv6[0] === 0x100) {
  103. // Discard prefix per RFC 6666
  104. output += "\nDiscard prefix detected. This is used when forwarding traffic to a sinkhole router to mitigate the effects of a denial-of-service attack. See RFC 6666 for more details.";
  105. output += "\nDiscard range: 100::/64";
  106. } else if (ipv6[0] === 0x64 && ipv6[1] === 0xff9b && ipv6[2] === 0 &&
  107. ipv6[3] === 0 && ipv6[4] === 0 && ipv6[5] === 0) {
  108. // IPv4/IPv6 translation per RFC 6052
  109. output += "\n'Well-Known' prefix for IPv4/IPv6 translation detected. See RFC 6052 for more details.";
  110. output += "\nTranslated IPv4 address: " + IP._ipv4ToStr((ipv6[6] << 16) + ipv6[7]);
  111. output += "\n'Well-Known' prefix range: 64:ff9b::/96";
  112. } else if (ipv6[0] === 0x2001 && ipv6[1] === 0) {
  113. // Teredo tunneling
  114. output += "\nTeredo tunneling IPv6 address detected\n";
  115. var serverIpv4 = (ipv6[2] << 16) + ipv6[3],
  116. udpPort = (~ipv6[5]) & 0xffff,
  117. clientIpv4 = ~((ipv6[6] << 16) + ipv6[7]),
  118. flagCone = (ipv6[4] >>> 15) & 1,
  119. flagR = (ipv6[4] >>> 14) & 1,
  120. flagRandom1 = (ipv6[4] >>> 10) & 15,
  121. flagUg = (ipv6[4] >>> 8) & 3,
  122. flagRandom2 = ipv6[4] & 255;
  123. output += "\nServer IPv4 address: " + IP._ipv4ToStr(serverIpv4) +
  124. "\nClient IPv4 address: " + IP._ipv4ToStr(clientIpv4) +
  125. "\nClient UDP port: " + udpPort +
  126. "\nFlags:" +
  127. "\n\tCone: " + flagCone;
  128. if (flagCone) {
  129. output += " (Client is behind a cone NAT)";
  130. } else {
  131. output += " (Client is not behind a cone NAT)";
  132. }
  133. output += "\n\tR: " + flagR;
  134. if (flagR) {
  135. output += " Error: This flag should be set to 0. See RFC 5991 and RFC 4380.";
  136. }
  137. output += "\n\tRandom1: " + Utils.bin(flagRandom1, 4) +
  138. "\n\tUG: " + Utils.bin(flagUg, 2);
  139. if (flagUg) {
  140. output += " Error: This flag should be set to 00. See RFC 4380.";
  141. }
  142. output += "\n\tRandom2: " + Utils.bin(flagRandom2, 8);
  143. if (!flagR && !flagUg && flagRandom1 && flagRandom2) {
  144. output += "\n\nThis is a valid Teredo address which complies with RFC 4380 and RFC 5991.";
  145. } else if (!flagR && !flagUg) {
  146. output += "\n\nThis is a valid Teredo address which complies with RFC 4380, however it does not comply with RFC 5991 (Teredo Security Updates) as there are no randomised bits in the flag field.";
  147. } else {
  148. output += "\n\nThis is an invalid Teredo address.";
  149. }
  150. output += "\n\nTeredo prefix range: 2001::/32";
  151. } else if (ipv6[0] === 0x2001 && ipv6[1] === 0x2 && ipv6[2] === 0) {
  152. // Benchmarking
  153. output += "\nAssigned to the Benchmarking Methodology Working Group (BMWG) for benchmarking IPv6. Corresponds to 198.18.0.0/15 for benchmarking IPv4. See RFC 5180 for more details.";
  154. output += "\nBMWG range: 2001:2::/48";
  155. } else if (ipv6[0] === 0x2001 && ipv6[1] >= 0x10 && ipv6[1] <= 0x1f) {
  156. // ORCHIDv1
  157. output += "\nDeprecated, previously ORCHIDv1 (Overlay Routable Cryptographic Hash Identifiers).\nORCHIDv1 range: 2001:10::/28\nORCHIDv2 now uses 2001:20::/28.";
  158. } else if (ipv6[0] === 0x2001 && ipv6[1] >= 0x20 && ipv6[1] <= 0x2f) {
  159. // ORCHIDv2
  160. output += "\nORCHIDv2 (Overlay Routable Cryptographic Hash Identifiers).\nThese are non-routed IPv6 addresses used for Cryptographic Hash Identifiers.";
  161. output += "\nORCHIDv2 range: 2001:20::/28";
  162. } else if (ipv6[0] === 0x2001 && ipv6[1] === 0xdb8) {
  163. // Documentation
  164. output += "\nThis is a documentation IPv6 address. This range should be used whenever an example IPv6 address is given or to model networking scenarios. Corresponds to 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 in IPv4.";
  165. output += "\nDocumentation range: 2001:db8::/32";
  166. } else if (ipv6[0] === 0x2002) {
  167. // 6to4
  168. output += "\n6to4 transition IPv6 address detected. See RFC 3056 for more details." +
  169. "\n6to4 prefix range: 2002::/16";
  170. var v4Addr = IP._ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
  171. slaId = ipv6[3],
  172. interfaceIdStr = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
  173. interfaceId = new BigInteger(interfaceIdStr, 16);
  174. output += "\n\nEncapsulated IPv4 address: " + v4Addr +
  175. "\nSLA ID: " + slaId +
  176. "\nInterface ID (base 16): " + interfaceIdStr +
  177. "\nInterface ID (base 10): " + interfaceId.toString();
  178. } else if (ipv6[0] >= 0xfc00 && ipv6[0] <= 0xfdff) {
  179. // Unique local address
  180. output += "\nThis is a unique local address comparable to the IPv4 private addresses 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. See RFC 4193 for more details.";
  181. output += "\nUnique local addresses range: fc00::/7";
  182. } else if (ipv6[0] >= 0xfe80 && ipv6[0] <= 0xfebf) {
  183. // Link-local address
  184. output += "\nThis is a link-local address comparable to the auto-configuration addresses 169.254.0.0/16 in IPv4.";
  185. output += "\nLink-local addresses range: fe80::/10";
  186. } else if (ipv6[0] >= 0xff00) {
  187. // Multicast
  188. output += "\nThis is a reserved multicast address.";
  189. output += "\nMulticast addresses range: ff00::/8";
  190. }
  191. } else {
  192. return "Invalid IPv6 address";
  193. }
  194. return output;
  195. },
  196. /**
  197. * @constant
  198. * @default
  199. */
  200. IP_FORMAT_LIST: ["Dotted Decimal", "Decimal", "Hex"],
  201. /**
  202. * Change IP format operation.
  203. *
  204. * @param {string} input
  205. * @param {Object[]} args
  206. * @returns {string}
  207. */
  208. runChangeIpFormat: function(input, args) {
  209. var inFormat = args[0],
  210. outFormat = args[1],
  211. lines = input.split("\n"),
  212. output = "",
  213. j = 0;
  214. for (var i = 0; i < lines.length; i++) {
  215. if (lines[i] === "") continue;
  216. var baIp = [];
  217. if (inFormat === outFormat) {
  218. output += lines[i] + "\n";
  219. continue;
  220. }
  221. // Convert to byte array IP from input format
  222. switch (inFormat) {
  223. case "Dotted Decimal":
  224. var octets = lines[i].split(".");
  225. for (j = 0; j < octets.length; j++) {
  226. baIp.push(parseInt(octets[j], 10));
  227. }
  228. break;
  229. case "Decimal":
  230. var decimal = lines[i].toString();
  231. baIp.push(decimal >> 24 & 255);
  232. baIp.push(decimal >> 16 & 255);
  233. baIp.push(decimal >> 8 & 255);
  234. baIp.push(decimal & 255);
  235. break;
  236. case "Hex":
  237. baIp = Utils.hexToByteArray(lines[i]);
  238. break;
  239. default:
  240. throw "Unsupported input IP format";
  241. }
  242. // Convert byte array IP to output format
  243. switch (outFormat) {
  244. case "Dotted Decimal":
  245. var ddIp = "";
  246. for (j = 0; j < baIp.length; j++) {
  247. ddIp += baIp[j] + ".";
  248. }
  249. output += ddIp.slice(0, ddIp.length-1) + "\n";
  250. break;
  251. case "Decimal":
  252. var decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
  253. output += decIp.toString() + "\n";
  254. break;
  255. case "Hex":
  256. var hexIp = "";
  257. for (j = 0; j < baIp.length; j++) {
  258. hexIp += Utils.hex(baIp[j]);
  259. }
  260. output += hexIp + "\n";
  261. break;
  262. default:
  263. throw "Unsupported output IP format";
  264. }
  265. }
  266. return output.slice(0, output.length-1);
  267. },
  268. /**
  269. * @constant
  270. * @default
  271. */
  272. DELIM_OPTIONS: ["Line feed", "CRLF", "Space", "Comma", "Semi-colon"],
  273. /**
  274. * @constant
  275. * @default
  276. */
  277. GROUP_CIDR: 24,
  278. /**
  279. * @constant
  280. * @default
  281. */
  282. GROUP_ONLY_SUBNET: false,
  283. /**
  284. * Group IP addresses operation.
  285. *
  286. * @param {string} input
  287. * @param {Object[]} args
  288. * @returns {string}
  289. */
  290. runGroupIps: function(input, args) {
  291. var delim = Utils.charRep[args[0]],
  292. cidr = args[1],
  293. onlySubnets = args[2],
  294. ipv4Mask = cidr < 32 ? ~(0xFFFFFFFF >>> cidr) : 0xFFFFFFFF,
  295. ipv6Mask = IP._genIpv6Mask(cidr),
  296. ips = input.split(delim),
  297. ipv4Networks = {},
  298. ipv6Networks = {},
  299. match = null,
  300. output = "",
  301. ip = null,
  302. network = null,
  303. networkStr = "";
  304. if (cidr < 0 || cidr > 127) {
  305. return "CIDR must be less than 32 for IPv4 or 128 for IPv6";
  306. }
  307. // Parse all IPs and add to network dictionary
  308. for (var i = 0; i < ips.length; i++) {
  309. if ((match = IP.IPV4_REGEX.exec(ips[i]))) {
  310. ip = IP._strToIpv4(match[1]) >>> 0;
  311. network = ip & ipv4Mask;
  312. if (ipv4Networks.hasOwnProperty(network)) {
  313. ipv4Networks[network].push(ip);
  314. } else {
  315. ipv4Networks[network] = [ip];
  316. }
  317. } else if ((match = IP.IPV6_REGEX.exec(ips[i]))) {
  318. ip = IP._strToIpv6(match[1]);
  319. network = [];
  320. networkStr = "";
  321. for (var j = 0; j < 8; j++) {
  322. network.push(ip[j] & ipv6Mask[j]);
  323. }
  324. networkStr = IP._ipv6ToStr(network, true);
  325. if (ipv6Networks.hasOwnProperty(networkStr)) {
  326. ipv6Networks[networkStr].push(ip);
  327. } else {
  328. ipv6Networks[networkStr] = [ip];
  329. }
  330. }
  331. }
  332. // Sort IPv4 network dictionaries and print
  333. for (network in ipv4Networks) {
  334. ipv4Networks[network] = ipv4Networks[network].sort();
  335. output += IP._ipv4ToStr(network) + "/" + cidr + "\n";
  336. if (!onlySubnets) {
  337. for (i = 0; i < ipv4Networks[network].length; i++) {
  338. output += " " + IP._ipv4ToStr(ipv4Networks[network][i]) + "\n";
  339. }
  340. output += "\n";
  341. }
  342. }
  343. // Sort IPv6 network dictionaries and print
  344. for (networkStr in ipv6Networks) {
  345. //ipv6Networks[networkStr] = ipv6Networks[networkStr].sort(); TODO
  346. output += networkStr + "/" + cidr + "\n";
  347. if (!onlySubnets) {
  348. for (i = 0; i < ipv6Networks[networkStr].length; i++) {
  349. output += " " + IP._ipv6ToStr(ipv6Networks[networkStr][i], true) + "\n";
  350. }
  351. output += "\n";
  352. }
  353. }
  354. return output;
  355. },
  356. /**
  357. * @constant
  358. * @default
  359. * @private
  360. */
  361. _LARGE_RANGE_ERROR: "The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the \"Allow large queries\" option. You are advised to turn off \"Auto Bake\" whilst editing large ranges.",
  362. /**
  363. * Parses an IPv4 CIDR range (e.g. 192.168.0.0/24) and displays information about it.
  364. *
  365. * @private
  366. * @param {RegExp} cidr
  367. * @param {boolean} includeNetworkInfo
  368. * @param {boolean} enumerateAddresses
  369. * @param {boolean} allowLargeList
  370. * @returns {string}
  371. */
  372. _ipv4CidrRange: function(cidr, includeNetworkInfo, enumerateAddresses, allowLargeList) {
  373. var output = "",
  374. network = IP._strToIpv4(cidr[1]),
  375. cidrRange = parseInt(cidr[2], 10);
  376. if (cidrRange < 0 || cidrRange > 31) {
  377. return "IPv4 CIDR must be less than 32";
  378. }
  379. var mask = ~(0xFFFFFFFF >>> cidrRange),
  380. ip1 = network & mask,
  381. ip2 = ip1 | ~mask;
  382. if (includeNetworkInfo) {
  383. output += "Network: " + IP._ipv4ToStr(network) + "\n";
  384. output += "CIDR: " + cidrRange + "\n";
  385. output += "Mask: " + IP._ipv4ToStr(mask) + "\n";
  386. output += "Range: " + IP._ipv4ToStr(ip1) + " - " + IP._ipv4ToStr(ip2) + "\n";
  387. output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
  388. }
  389. if (enumerateAddresses) {
  390. if (cidrRange >= 16 || allowLargeList) {
  391. output += IP._generateIpv4Range(ip1, ip2).join("\n");
  392. } else {
  393. output += IP._LARGE_RANGE_ERROR;
  394. }
  395. }
  396. return output;
  397. },
  398. /**
  399. * Parses an IPv6 CIDR range (e.g. ff00::/48) and displays information about it.
  400. *
  401. * @private
  402. * @param {RegExp} cidr
  403. * @param {boolean} includeNetworkInfo
  404. * @returns {string}
  405. */
  406. _ipv6CidrRange: function(cidr, includeNetworkInfo) {
  407. var output = "",
  408. network = IP._strToIpv6(cidr[1]),
  409. cidrRange = parseInt(cidr[cidr.length-1], 10);
  410. if (cidrRange < 0 || cidrRange > 127) {
  411. return "IPv6 CIDR must be less than 128";
  412. }
  413. var mask = IP._genIpv6Mask(cidrRange),
  414. ip1 = new Array(8),
  415. ip2 = new Array(8),
  416. totalDiff = "",
  417. total = new Array(128);
  418. for (var i = 0; i < 8; i++) {
  419. ip1[i] = network[i] & mask[i];
  420. ip2[i] = ip1[i] | (~mask[i] & 0x0000FFFF);
  421. totalDiff = (ip2[i] - ip1[i]).toString(2);
  422. if (totalDiff !== "0") {
  423. for (var n = 0; n < totalDiff.length; n++) {
  424. total[i*16 + 16-(totalDiff.length-n)] = totalDiff[n];
  425. }
  426. }
  427. }
  428. if (includeNetworkInfo) {
  429. output += "Network: " + IP._ipv6ToStr(network) + "\n";
  430. output += "Shorthand: " + IP._ipv6ToStr(network, true) + "\n";
  431. output += "CIDR: " + cidrRange + "\n";
  432. output += "Mask: " + IP._ipv6ToStr(mask) + "\n";
  433. output += "Range: " + IP._ipv6ToStr(ip1) + " - " + IP._ipv6ToStr(ip2) + "\n";
  434. output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
  435. }
  436. return output;
  437. },
  438. /**
  439. * Generates an IPv6 subnet mask given a CIDR value.
  440. *
  441. * @private
  442. * @param {number} cidr
  443. * @returns {number[]}
  444. */
  445. _genIpv6Mask: function(cidr) {
  446. var mask = new Array(8),
  447. shift;
  448. for (var i = 0; i < 8; i++) {
  449. if (cidr > ((i+1)*16)) {
  450. mask[i] = 0x0000FFFF;
  451. } else {
  452. shift = cidr-(i*16);
  453. if (shift < 0) shift = 0;
  454. mask[i] = ~((0x0000FFFF >>> shift) | 0xFFFF0000);
  455. }
  456. }
  457. return mask;
  458. },
  459. /**
  460. * Parses an IPv4 hyphenated range (e.g. 192.168.0.0 - 192.168.0.255) and displays information
  461. * about it.
  462. *
  463. * @private
  464. * @param {RegExp} range
  465. * @param {boolean} includeNetworkInfo
  466. * @param {boolean} enumerateAddresses
  467. * @param {boolean} allowLargeList
  468. * @returns {string}
  469. */
  470. _ipv4HyphenatedRange: function(range, includeNetworkInfo, enumerateAddresses, allowLargeList) {
  471. var output = "",
  472. ip1 = IP._strToIpv4(range[1]),
  473. ip2 = IP._strToIpv4(range[2]);
  474. // Calculate mask
  475. var diff = ip1 ^ ip2,
  476. cidr = 32,
  477. mask = 0;
  478. while (diff !== 0) {
  479. diff >>= 1;
  480. cidr--;
  481. mask = (mask << 1) | 1;
  482. }
  483. mask = ~mask >>> 0;
  484. var network = ip1 & mask,
  485. subIp1 = network & mask,
  486. subIp2 = subIp1 | ~mask;
  487. if (includeNetworkInfo) {
  488. output += "Minimum subnet required to hold this range:\n";
  489. output += "\tNetwork: " + IP._ipv4ToStr(network) + "\n";
  490. output += "\tCIDR: " + cidr + "\n";
  491. output += "\tMask: " + IP._ipv4ToStr(mask) + "\n";
  492. output += "\tSubnet range: " + IP._ipv4ToStr(subIp1) + " - " + IP._ipv4ToStr(subIp2) + "\n";
  493. output += "\tTotal addresses in subnet: " + (((subIp2 - subIp1) >>> 0) + 1) + "\n\n";
  494. output += "Range: " + IP._ipv4ToStr(ip1) + " - " + IP._ipv4ToStr(ip2) + "\n";
  495. output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
  496. }
  497. if (enumerateAddresses) {
  498. if (((ip2 - ip1) >>> 0) <= 65536 || allowLargeList) {
  499. output += IP._generateIpv4Range(ip1, ip2).join("\n");
  500. } else {
  501. output += IP._LARGE_RANGE_ERROR;
  502. }
  503. }
  504. return output;
  505. },
  506. /**
  507. * Parses an IPv6 hyphenated range (e.g. ff00:: - ffff::) and displays information about it.
  508. *
  509. * @private
  510. * @param {RegExp} range
  511. * @param {boolean} includeNetworkInfo
  512. * @returns {string}
  513. */
  514. _ipv6HyphenatedRange: function(range, includeNetworkInfo) {
  515. var output = "",
  516. ip1 = IP._strToIpv6(range[1]),
  517. ip2 = IP._strToIpv6(range[14]);
  518. var t = "",
  519. total = new Array(128);
  520. // Initialise total array to "0"
  521. for (var i = 0; i < 128; i++)
  522. total[i] = "0";
  523. for (i = 0; i < 8; i++) {
  524. t = (ip2[i] - ip1[i]).toString(2);
  525. if (t !== "0") {
  526. for (var n = 0; n < t.length; n++) {
  527. total[i*16 + 16-(t.length-n)] = t[n];
  528. }
  529. }
  530. }
  531. if (includeNetworkInfo) {
  532. output += "Range: " + IP._ipv6ToStr(ip1) + " - " + IP._ipv6ToStr(ip2) + "\n";
  533. output += "Shorthand range: " + IP._ipv6ToStr(ip1, true) + " - " + IP._ipv6ToStr(ip2, true) + "\n";
  534. output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
  535. }
  536. return output;
  537. },
  538. /**
  539. * Converts an IPv4 address from string format to numerical format.
  540. *
  541. * @private
  542. * @param {string} ipStr
  543. * @returns {number}
  544. *
  545. * @example
  546. * // returns 168427520
  547. * IP._strToIpv4("10.10.0.0");
  548. */
  549. _strToIpv4: function (ipStr) {
  550. var blocks = ipStr.split("."),
  551. numBlocks = parseBlocks(blocks),
  552. result = 0;
  553. result += numBlocks[0] << 24;
  554. result += numBlocks[1] << 16;
  555. result += numBlocks[2] << 8;
  556. result += numBlocks[3];
  557. return result;
  558. /**
  559. * Converts a list of 4 numeric strings in the range 0-255 to a list of numbers.
  560. */
  561. function parseBlocks(blocks) {
  562. if (blocks.length !== 4)
  563. throw "More than 4 blocks.";
  564. var numBlocks = [];
  565. for (var i = 0; i < 4; i++) {
  566. numBlocks[i] = parseInt(blocks[i], 10);
  567. if (numBlocks[i] < 0 || numBlocks[i] > 255)
  568. throw "Block out of range.";
  569. }
  570. return numBlocks;
  571. }
  572. },
  573. /**
  574. * Converts an IPv4 address from numerical format to string format.
  575. *
  576. * @private
  577. * @param {number} ipInt
  578. * @returns {string}
  579. *
  580. * @example
  581. * // returns "10.10.0.0"
  582. * IP._ipv4ToStr(168427520);
  583. */
  584. _ipv4ToStr: function(ipInt) {
  585. var blockA = (ipInt >> 24) & 255,
  586. blockB = (ipInt >> 16) & 255,
  587. blockC = (ipInt >> 8) & 255,
  588. blockD = ipInt & 255;
  589. return blockA + "." + blockB + "." + blockC + "." + blockD;
  590. },
  591. /**
  592. * Converts an IPv6 address from string format to numerical array format.
  593. *
  594. * @private
  595. * @param {string} ipStr
  596. * @returns {number[]}
  597. *
  598. * @example
  599. * // returns [65280, 0, 0, 0, 0, 0, 4369, 8738]
  600. * IP._strToIpv6("ff00::1111:2222");
  601. */
  602. _strToIpv6: function(ipStr) {
  603. var blocks = ipStr.split(":"),
  604. numBlocks = parseBlocks(blocks),
  605. j = 0,
  606. ipv6 = new Array(8);
  607. for (var i = 0; i < 8; i++) {
  608. if (isNaN(numBlocks[j])) {
  609. ipv6[i] = 0;
  610. if (i === (8-numBlocks.slice(j).length)) j++;
  611. } else {
  612. ipv6[i] = numBlocks[j];
  613. j++;
  614. }
  615. }
  616. return ipv6;
  617. /**
  618. * Converts a list of 3-8 numeric hex strings in the range 0-65535 to a list of numbers.
  619. */
  620. function parseBlocks(blocks) {
  621. if (blocks.length < 3 || blocks.length > 8)
  622. throw "Badly formatted IPv6 address.";
  623. var numBlocks = [];
  624. for (var i = 0; i < blocks.length; i++) {
  625. numBlocks[i] = parseInt(blocks[i], 16);
  626. if (numBlocks[i] < 0 || numBlocks[i] > 65535)
  627. throw "Block out of range.";
  628. }
  629. return numBlocks;
  630. }
  631. },
  632. /**
  633. * Converts an IPv6 address from numerical array format to string format.
  634. *
  635. * @private
  636. * @param {number[]} ipv6
  637. * @param {boolean} compact - Whether or not to return the address in shorthand or not
  638. * @returns {string}
  639. *
  640. * @example
  641. * // returns "ff00::1111:2222"
  642. * IP._ipv6ToStr([65280, 0, 0, 0, 0, 0, 4369, 8738], true);
  643. *
  644. * // returns "ff00:0000:0000:0000:0000:0000:1111:2222"
  645. * IP._ipv6ToStr([65280, 0, 0, 0, 0, 0, 4369, 8738], false);
  646. */
  647. _ipv6ToStr: function(ipv6, compact) {
  648. var output = "",
  649. i = 0;
  650. if (compact) {
  651. var start = -1,
  652. end = -1,
  653. s = 0,
  654. e = -1;
  655. for (i = 0; i < 8; i++) {
  656. if (ipv6[i] === 0 && e === (i-1)) {
  657. e = i;
  658. } else if (ipv6[i] === 0) {
  659. s = i; e = i;
  660. }
  661. if (e >= 0 && (e-s) > (end - start)) {
  662. start = s;
  663. end = e;
  664. }
  665. }
  666. for (i = 0; i < 8; i++) {
  667. if (i !== start) {
  668. output += Utils.hex(ipv6[i], 1) + ":";
  669. } else {
  670. output += ":";
  671. i = end;
  672. if (end === 7) output += ":";
  673. }
  674. }
  675. if (output[0] === ":")
  676. output = ":" + output;
  677. } else {
  678. for (i = 0; i < 8; i++) {
  679. output += Utils.hex(ipv6[i], 4) + ":";
  680. }
  681. }
  682. return output.slice(0, output.length-1);
  683. },
  684. /**
  685. * Generates a list of IPv4 addresses in string format between two given numerical values.
  686. *
  687. * @private
  688. * @param {number} ip
  689. * @param {number} endIp
  690. * @returns {string[]}
  691. *
  692. * @example
  693. * // returns ["0.0.0.1", "0.0.0.2", "0.0.0.3"]
  694. * IP._generateIpv4Range(1, 3);
  695. */
  696. _generateIpv4Range: function(ip, endIp) {
  697. var range = [];
  698. if (endIp >= ip) {
  699. for (; ip <= endIp; ip++) {
  700. range.push(IP._ipv4ToStr(ip));
  701. }
  702. } else {
  703. range[0] = "Second IP address smaller than first.";
  704. }
  705. return range;
  706. },
  707. };