PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ipv4.js

http://github.com/beaugunderson/javascript-ipv6
JavaScript | 320 lines | 133 code | 45 blank | 142 comment | 9 complexity | c8ba315cdb450d615cf046adca1e199b MD5 | raw file
  1. 'use strict';
  2. var BigInteger = require('jsbn').BigInteger;
  3. var common = require('./common.js');
  4. var sprintf = require('sprintf-js').sprintf;
  5. var padStart = require('lodash.padstart');
  6. var repeat = require('lodash.repeat');
  7. var constants = require('./v4/constants.js');
  8. /**
  9. * Represents an IPv4 address
  10. * @class Address4
  11. * @param {string} address - An IPv4 address string
  12. */
  13. function Address4(address) {
  14. this.valid = false;
  15. this.address = address;
  16. this.groups = constants.GROUPS;
  17. this.v4 = true;
  18. this.subnet = '/32';
  19. this.subnetMask = 32;
  20. var subnet = constants.RE_SUBNET_STRING.exec(address);
  21. if (subnet) {
  22. this.parsedSubnet = subnet[0].replace('/', '');
  23. this.subnetMask = parseInt(this.parsedSubnet, 10);
  24. this.subnet = '/' + this.subnetMask;
  25. if (this.subnetMask < 0 || this.subnetMask > constants.BITS) {
  26. this.valid = false;
  27. this.error = 'Invalid subnet mask.';
  28. return;
  29. }
  30. address = address.replace(constants.RE_SUBNET_STRING, '');
  31. }
  32. this.addressMinusSuffix = address;
  33. this.parsedAddress = this.parse(address);
  34. }
  35. /*
  36. * Parses a v4 address
  37. */
  38. Address4.prototype.parse = function (address) {
  39. var groups = address.split('.');
  40. if (address.match(constants.RE_ADDRESS)) {
  41. this.valid = true;
  42. } else {
  43. this.error = 'Invalid IPv4 address.';
  44. }
  45. return groups;
  46. };
  47. /**
  48. * Return true if the address is valid
  49. * @memberof Address4
  50. * @instance
  51. * @returns {Boolean}
  52. */
  53. Address4.prototype.isValid = function () {
  54. return this.valid;
  55. };
  56. /**
  57. * Returns the correct form of an address
  58. * @memberof Address4
  59. * @instance
  60. * @returns {String}
  61. */
  62. Address4.prototype.correctForm = function () {
  63. return this.parsedAddress.map(function (part) {
  64. return parseInt(part, 10);
  65. }).join('.');
  66. };
  67. /**
  68. * Returns true if the address is correct, false otherwise
  69. * @memberof Address4
  70. * @instance
  71. * @returns {Boolean}
  72. */
  73. Address4.prototype.isCorrect = common.isCorrect(constants.BITS);
  74. /**
  75. * Converts a hex string to an IPv4 address object
  76. * @memberof Address4
  77. * @static
  78. * @param {string} hex - a hex string to convert
  79. * @returns {Address4}
  80. */
  81. Address4.fromHex = function (hex) {
  82. var padded = padStart(hex.replace(/:/g, ''), 8, '0');
  83. var groups = [];
  84. var i;
  85. for (i = 0; i < 8; i += 2) {
  86. var h = padded.slice(i, i + 2);
  87. groups.push(parseInt(h, 16));
  88. }
  89. return new Address4(groups.join('.'));
  90. };
  91. /**
  92. * Converts an integer into a IPv4 address object
  93. * @memberof Address4
  94. * @static
  95. * @param {integer} integer - a number to convert
  96. * @returns {Address4}
  97. */
  98. Address4.fromInteger = function (integer) {
  99. return Address4.fromHex(integer.toString(16));
  100. };
  101. /**
  102. * Converts an IPv4 address object to a hex string
  103. * @memberof Address4
  104. * @instance
  105. * @returns {String}
  106. */
  107. Address4.prototype.toHex = function () {
  108. return this.parsedAddress.map(function (part) {
  109. return sprintf('%02x', parseInt(part, 10));
  110. }).join(':');
  111. };
  112. /**
  113. * Converts an IPv4 address object to an array of bytes
  114. * @memberof Address4
  115. * @instance
  116. * @returns {Array}
  117. */
  118. Address4.prototype.toArray = function () {
  119. return this.parsedAddress.map(function (part) {
  120. return parseInt(part, 10);
  121. });
  122. };
  123. /**
  124. * Converts an IPv4 address object to an IPv6 address group
  125. * @memberof Address4
  126. * @instance
  127. * @returns {String}
  128. */
  129. Address4.prototype.toGroup6 = function () {
  130. var output = [];
  131. var i;
  132. for (i = 0; i < constants.GROUPS; i += 2) {
  133. var hex = sprintf('%02x%02x',
  134. parseInt(this.parsedAddress[i], 10),
  135. parseInt(this.parsedAddress[i + 1], 10));
  136. output.push(sprintf('%x', parseInt(hex, 16)));
  137. }
  138. return output.join(':');
  139. };
  140. /**
  141. * Returns the address as a BigInteger
  142. * @memberof Address4
  143. * @instance
  144. * @returns {BigInteger}
  145. */
  146. Address4.prototype.bigInteger = function () {
  147. if (!this.valid) {
  148. return null;
  149. }
  150. return new BigInteger(this.parsedAddress.map(function (n) {
  151. return sprintf('%02x', parseInt(n, 10));
  152. }).join(''), 16);
  153. };
  154. /**
  155. * Helper function getting start address.
  156. * @memberof Address4
  157. * @instance
  158. * @returns {BigInteger}
  159. */
  160. Address4.prototype._startAddress = function () {
  161. return new BigInteger(
  162. this.mask() + repeat('0', constants.BITS - this.subnetMask), 2
  163. );
  164. };
  165. /**
  166. * The first address in the range given by this address' subnet.
  167. * Often referred to as the Network Address.
  168. * @memberof Address4
  169. * @instance
  170. * @returns {Address4}
  171. */
  172. Address4.prototype.startAddress = function () {
  173. return Address4.fromBigInteger(this._startAddress());
  174. };
  175. /**
  176. * The first host address in the range given by this address's subnet ie
  177. * the first address after the Network Address
  178. * @memberof Address4
  179. * @instance
  180. * @returns {Address4}
  181. */
  182. Address4.prototype.startAddressExclusive = function () {
  183. var adjust = new BigInteger('1');
  184. return Address4.fromBigInteger(this._startAddress().add(adjust));
  185. };
  186. /**
  187. * Helper function getting end address.
  188. * @memberof Address4
  189. * @instance
  190. * @returns {BigInteger}
  191. */
  192. Address4.prototype._endAddress = function () {
  193. return new BigInteger(
  194. this.mask() + repeat('1', constants.BITS - this.subnetMask), 2
  195. );
  196. };
  197. /**
  198. * The last address in the range given by this address' subnet
  199. * Often referred to as the Broadcast
  200. * @memberof Address4
  201. * @instance
  202. * @returns {Address4}
  203. */
  204. Address4.prototype.endAddress = function () {
  205. return Address4.fromBigInteger(this._endAddress());
  206. };
  207. /**
  208. * The last host address in the range given by this address's subnet ie
  209. * the last address prior to the Broadcast Address
  210. * @memberof Address4
  211. * @instance
  212. * @returns {Address4}
  213. */
  214. Address4.prototype.endAddressExclusive = function () {
  215. var adjust = new BigInteger('1');
  216. return Address4.fromBigInteger(this._endAddress().subtract(adjust));
  217. };
  218. /**
  219. * Converts a BigInteger to a v4 address object
  220. * @memberof Address4
  221. * @static
  222. * @param {BigInteger} bigInteger - a BigInteger to convert
  223. * @returns {Address4}
  224. */
  225. Address4.fromBigInteger = function (bigInteger) {
  226. return Address4.fromInteger(parseInt(bigInteger.toString(), 10));
  227. };
  228. /**
  229. * Returns the first n bits of the address, defaulting to the
  230. * subnet mask
  231. * @memberof Address4
  232. * @instance
  233. * @returns {String}
  234. */
  235. Address4.prototype.mask = function (optionalMask) {
  236. if (optionalMask === undefined) {
  237. optionalMask = this.subnetMask;
  238. }
  239. return this.getBitsBase2(0, optionalMask);
  240. };
  241. /**
  242. * Returns the bits in the given range as a base-2 string
  243. * @memberof Address4
  244. * @instance
  245. * @returns {string}
  246. */
  247. Address4.prototype.getBitsBase2 = function (start, end) {
  248. return this.binaryZeroPad().slice(start, end);
  249. };
  250. /**
  251. * Returns true if the given address is in the subnet of the current address
  252. * @memberof Address4
  253. * @instance
  254. * @returns {boolean}
  255. */
  256. Address4.prototype.isInSubnet = common.isInSubnet;
  257. /**
  258. * Returns true if the given address is a multicast address
  259. * @memberof Address4
  260. * @instance
  261. * @returns {boolean}
  262. */
  263. Address4.prototype.isMulticast = function () {
  264. return this.isInSubnet(new Address4('224.0.0.0/4'));
  265. };
  266. /**
  267. * Returns a zero-padded base-2 string representation of the address
  268. * @memberof Address4
  269. * @instance
  270. * @returns {string}
  271. */
  272. Address4.prototype.binaryZeroPad = function () {
  273. return padStart(this.bigInteger().toString(2), constants.BITS, '0');
  274. };
  275. module.exports = Address4;