Source: net/netaddress.js

  1. /*!
  2. * netaddress.js - network address object for bcoin
  3. * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
  4. * https://github.com/bcoin-org/bcoin
  5. */
  6. 'use strict';
  7. const assert = require('bsert');
  8. const bio = require('bufio');
  9. const IP = require('binet');
  10. const Network = require('../protocol/network');
  11. const util = require('../utils/util');
  12. const common = require('./common');
  13. const {inspectSymbol} = require('../utils');
  14. /**
  15. * Net Address
  16. * Represents a network address.
  17. * @alias module:net.NetAddress
  18. * @property {Host} host
  19. * @property {Number} port
  20. * @property {Number} services
  21. * @property {Number} time
  22. */
  23. class NetAddress {
  24. /**
  25. * Create a network address.
  26. * @constructor
  27. * @param {Object} options
  28. * @param {Number?} options.time - Timestamp.
  29. * @param {Number?} options.services - Service bits.
  30. * @param {String?} options.host - IP address (IPv6 or IPv4).
  31. * @param {Number?} options.port - Port.
  32. */
  33. constructor(options) {
  34. this.host = '0.0.0.0';
  35. this.port = 0;
  36. this.services = 0;
  37. this.time = 0;
  38. this.hostname = '0.0.0.0:0';
  39. this.raw = IP.ZERO_IP;
  40. if (options)
  41. this.fromOptions(options);
  42. }
  43. /**
  44. * Inject properties from options object.
  45. * @private
  46. * @param {Object} options
  47. */
  48. fromOptions(options) {
  49. assert(typeof options.host === 'string');
  50. assert(typeof options.port === 'number');
  51. this.raw = IP.toBuffer(options.host);
  52. this.host = IP.toString(this.raw);
  53. this.port = options.port;
  54. if (options.services) {
  55. assert(typeof options.services === 'number');
  56. this.services = options.services;
  57. }
  58. if (options.time) {
  59. assert(typeof options.time === 'number');
  60. this.time = options.time;
  61. }
  62. this.hostname = IP.toHostname(this.host, this.port);
  63. return this;
  64. }
  65. /**
  66. * Instantiate network address from options.
  67. * @param {Object} options
  68. * @returns {NetAddress}
  69. */
  70. static fromOptions(options) {
  71. return new this().fromOptions(options);
  72. }
  73. /**
  74. * Test whether required services are available.
  75. * @param {Number} services
  76. * @returns {Boolean}
  77. */
  78. hasServices(services) {
  79. return (this.services & services) === services;
  80. }
  81. /**
  82. * Test whether the address is IPv4.
  83. * @returns {Boolean}
  84. */
  85. isIPv4() {
  86. return IP.isIPv4(this.raw);
  87. }
  88. /**
  89. * Test whether the address is IPv6.
  90. * @returns {Boolean}
  91. */
  92. isIPv6() {
  93. return IP.isIPv6(this.raw);
  94. }
  95. /**
  96. * Test whether the host is null.
  97. * @returns {Boolean}
  98. */
  99. isNull() {
  100. return IP.isNull(this.raw);
  101. }
  102. /**
  103. * Test whether the host is a local address.
  104. * @returns {Boolean}
  105. */
  106. isLocal() {
  107. return IP.isLocal(this.raw);
  108. }
  109. /**
  110. * Test whether the host is valid.
  111. * @returns {Boolean}
  112. */
  113. isValid() {
  114. return IP.isValid(this.raw);
  115. }
  116. /**
  117. * Test whether the host is routable.
  118. * @returns {Boolean}
  119. */
  120. isRoutable() {
  121. return IP.isRoutable(this.raw);
  122. }
  123. /**
  124. * Test whether the host is an onion address.
  125. * @returns {Boolean}
  126. */
  127. isOnion() {
  128. return IP.isOnion(this.raw);
  129. }
  130. /**
  131. * Compare against another network address.
  132. * @returns {Boolean}
  133. */
  134. equal(addr) {
  135. return this.compare(addr) === 0;
  136. }
  137. /**
  138. * Compare against another network address.
  139. * @returns {Number}
  140. */
  141. compare(addr) {
  142. const cmp = this.raw.compare(addr.raw);
  143. if (cmp !== 0)
  144. return cmp;
  145. return this.port - addr.port;
  146. }
  147. /**
  148. * Get reachable score to destination.
  149. * @param {NetAddress} dest
  150. * @returns {Number}
  151. */
  152. getReachability(dest) {
  153. return IP.getReachability(this.raw, dest.raw);
  154. }
  155. /**
  156. * Set null host.
  157. */
  158. setNull() {
  159. this.raw = IP.ZERO_IP;
  160. this.host = '0.0.0.0';
  161. this.hostname = IP.toHostname(this.host, this.port);
  162. }
  163. /**
  164. * Set host.
  165. * @param {String} host
  166. */
  167. setHost(host) {
  168. this.raw = IP.toBuffer(host);
  169. this.host = IP.toString(this.raw);
  170. this.hostname = IP.toHostname(this.host, this.port);
  171. }
  172. /**
  173. * Set port.
  174. * @param {Number} port
  175. */
  176. setPort(port) {
  177. assert(port >= 0 && port <= 0xffff);
  178. this.port = port;
  179. this.hostname = IP.toHostname(this.host, port);
  180. }
  181. /**
  182. * Inject properties from host, port, and network.
  183. * @private
  184. * @param {String} host
  185. * @param {Number} port
  186. * @param {(Network|NetworkType)?} network
  187. */
  188. fromHost(host, port, network) {
  189. network = Network.get(network);
  190. assert(port >= 0 && port <= 0xffff);
  191. this.raw = IP.toBuffer(host);
  192. this.host = IP.toString(this.raw);
  193. this.port = port;
  194. this.services = NetAddress.DEFAULT_SERVICES;
  195. this.time = network.now();
  196. this.hostname = IP.toHostname(this.host, this.port);
  197. return this;
  198. }
  199. /**
  200. * Instantiate a network address
  201. * from a host and port.
  202. * @param {String} host
  203. * @param {Number} port
  204. * @param {(Network|NetworkType)?} network
  205. * @returns {NetAddress}
  206. */
  207. static fromHost(host, port, network) {
  208. return new this().fromHost(host, port, network);
  209. }
  210. /**
  211. * Inject properties from hostname and network.
  212. * @private
  213. * @param {String} hostname
  214. * @param {(Network|NetworkType)?} network
  215. */
  216. fromHostname(hostname, network) {
  217. network = Network.get(network);
  218. const addr = IP.fromHostname(hostname, network.port);
  219. return this.fromHost(addr.host, addr.port, network);
  220. }
  221. /**
  222. * Instantiate a network address
  223. * from a hostname (i.e. 127.0.0.1:8333).
  224. * @param {String} hostname
  225. * @param {(Network|NetworkType)?} network
  226. * @returns {NetAddress}
  227. */
  228. static fromHostname(hostname, network) {
  229. return new this().fromHostname(hostname, network);
  230. }
  231. /**
  232. * Inject properties from socket.
  233. * @private
  234. * @param {net.Socket} socket
  235. */
  236. fromSocket(socket, network) {
  237. const host = socket.remoteAddress;
  238. const port = socket.remotePort;
  239. assert(typeof host === 'string');
  240. assert(typeof port === 'number');
  241. return this.fromHost(IP.normalize(host), port, network);
  242. }
  243. /**
  244. * Instantiate a network address
  245. * from a socket.
  246. * @param {net.Socket} socket
  247. * @returns {NetAddress}
  248. */
  249. static fromSocket(hostname, network) {
  250. return new this().fromSocket(hostname, network);
  251. }
  252. /**
  253. * Inject properties from buffer reader.
  254. * @private
  255. * @param {BufferReader} br
  256. * @param {Boolean?} full - Include timestamp.
  257. */
  258. fromReader(br, full) {
  259. this.time = full ? br.readU32() : 0;
  260. this.services = br.readU32();
  261. // Note: hi service bits
  262. // are currently unused.
  263. br.readU32();
  264. this.raw = br.readBytes(16);
  265. this.host = IP.toString(this.raw);
  266. this.port = br.readU16BE();
  267. this.hostname = IP.toHostname(this.host, this.port);
  268. return this;
  269. }
  270. /**
  271. * Inject properties from serialized data.
  272. * @private
  273. * @param {Buffer} data
  274. * @param {Boolean?} full - Include timestamp.
  275. */
  276. fromRaw(data, full) {
  277. return this.fromReader(bio.read(data), full);
  278. }
  279. /**
  280. * Insantiate a network address from buffer reader.
  281. * @param {BufferReader} br
  282. * @param {Boolean?} full - Include timestamp.
  283. * @returns {NetAddress}
  284. */
  285. static fromReader(br, full) {
  286. return new this().fromReader(br, full);
  287. }
  288. /**
  289. * Insantiate a network address from serialized data.
  290. * @param {Buffer} data
  291. * @param {Boolean?} full - Include timestamp.
  292. * @returns {NetAddress}
  293. */
  294. static fromRaw(data, full) {
  295. return new this().fromRaw(data, full);
  296. }
  297. /**
  298. * Write network address to a buffer writer.
  299. * @param {BufferWriter} bw
  300. * @param {Boolean?} full - Include timestamp.
  301. * @returns {Buffer}
  302. */
  303. toWriter(bw, full) {
  304. if (full)
  305. bw.writeU32(this.time);
  306. bw.writeU32(this.services);
  307. bw.writeU32(0);
  308. bw.writeBytes(this.raw);
  309. bw.writeU16BE(this.port);
  310. return bw;
  311. }
  312. /**
  313. * Calculate serialization size of address.
  314. * @returns {Number}
  315. */
  316. getSize(full) {
  317. return 26 + (full ? 4 : 0);
  318. }
  319. /**
  320. * Serialize network address.
  321. * @param {Boolean?} full - Include timestamp.
  322. * @returns {Buffer}
  323. */
  324. toRaw(full) {
  325. const size = this.getSize(full);
  326. return this.toWriter(bio.write(size), full).render();
  327. }
  328. /**
  329. * Convert net address to json-friendly object.
  330. * @returns {Object}
  331. */
  332. toJSON() {
  333. return {
  334. host: this.host,
  335. port: this.port,
  336. services: this.services,
  337. time: this.time
  338. };
  339. }
  340. /**
  341. * Inject properties from json object.
  342. * @private
  343. * @param {Object} json
  344. * @returns {NetAddress}
  345. */
  346. fromJSON(json) {
  347. assert((json.port & 0xffff) === json.port);
  348. assert((json.services >>> 0) === json.services);
  349. assert((json.time >>> 0) === json.time);
  350. this.raw = IP.toBuffer(json.host);
  351. this.host = json.host;
  352. this.port = json.port;
  353. this.services = json.services;
  354. this.time = json.time;
  355. this.hostname = IP.toHostname(this.host, this.port);
  356. return this;
  357. }
  358. /**
  359. * Instantiate net address from json object.
  360. * @param {Object} json
  361. * @returns {NetAddress}
  362. */
  363. static fromJSON(json) {
  364. return new this().fromJSON(json);
  365. }
  366. /**
  367. * Inspect the network address.
  368. * @returns {Object}
  369. */
  370. [inspectSymbol]() {
  371. return '<NetAddress:'
  372. + ` hostname=${this.hostname}`
  373. + ` services=${this.services.toString(2)}`
  374. + ` date=${util.date(this.time)}`
  375. + '>';
  376. }
  377. }
  378. /**
  379. * Default services for
  380. * unknown outbound peers.
  381. * @const {Number}
  382. * @default
  383. */
  384. NetAddress.DEFAULT_SERVICES = 0
  385. | common.services.NETWORK
  386. | common.services.WITNESS
  387. | common.services.BLOOM;
  388. /*
  389. * Expose
  390. */
  391. module.exports = NetAddress;