/*! * netaddress.js - network address object for bcoin * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; var assert = require('assert'); var common = require('../net/common'); var Network = require('../protocol/network'); var util = require('../utils/util'); var IP = require('../utils/ip'); var StaticWriter = require('../utils/staticwriter'); var BufferReader = require('../utils/reader'); /** * Represents a network address. * @alias module:primitives.NetAddress * @constructor * @param {Object} options * @param {Number?} options.ts - Timestamp. * @param {Number?} options.services - Service bits. * @param {String?} options.host - IP address (IPv6 or IPv4). * @param {Number?} options.port - Port. * @property {Host} host * @property {Number} port * @property {Number} services * @property {Number} ts */ function NetAddress(options) { if (!(this instanceof NetAddress)) return new NetAddress(options); this.host = '0.0.0.0'; this.port = 0; this.services = 0; this.ts = 0; this.hostname = '0.0.0.0:0'; this.raw = IP.ZERO_IP; if (options) this.fromOptions(options); } /** * Default services for * unknown outbound peers. * @const {Number} * @default */ NetAddress.DEFAULT_SERVICES = 0 | common.services.NETWORK | common.services.WITNESS | common.services.BLOOM; /** * Inject properties from options object. * @private * @param {Object} options */ NetAddress.prototype.fromOptions = function fromOptions(options) { assert(typeof options.host === 'string'); assert(typeof options.port === 'number'); this.raw = IP.toBuffer(options.host); this.host = IP.toString(this.raw); this.port = options.port; if (options.services) { assert(typeof options.services === 'number'); this.services = options.services; } if (options.ts) { assert(typeof options.ts === 'number'); this.ts = options.ts; } this.hostname = IP.toHostname(this.host, this.port); return this; }; /** * Instantiate network address from options. * @param {Object} options * @returns {NetAddress} */ NetAddress.fromOptions = function fromOptions(options) { return new NetAddress().fromOptions(options); }; /** * Test whether required services are available. * @param {Number} services * @returns {Boolean} */ NetAddress.prototype.hasServices = function hasServices(services) { return (this.services & services) === services; }; /** * Test whether the address is IPv4. * @returns {Boolean} */ NetAddress.isIPv4 = function isIPv4() { return IP.isIPv4(this.raw); }; /** * Test whether the address is IPv6. * @returns {Boolean} */ NetAddress.isIPv6 = function isIPv6() { return IP.isIPv6(this.raw); }; /** * Test whether the host is null. * @returns {Boolean} */ NetAddress.prototype.isNull = function isNull() { return IP.isNull(this.raw); }; /** * Test whether the host is a local address. * @returns {Boolean} */ NetAddress.prototype.isLocal = function isLocal() { return IP.isLocal(this.raw); }; /** * Test whether the host is valid. * @returns {Boolean} */ NetAddress.prototype.isValid = function isValid() { return IP.isValid(this.raw); }; /** * Test whether the host is routable. * @returns {Boolean} */ NetAddress.prototype.isRoutable = function isRoutable() { return IP.isRoutable(this.raw); }; /** * Test whether the host is an onion address. * @returns {Boolean} */ NetAddress.prototype.isOnion = function isOnion() { return IP.isOnion(this.raw); }; /** * Compare against another network address. * @returns {Boolean} */ NetAddress.prototype.equal = function equal(addr) { return this.compare(addr) === 0; }; /** * Compare against another network address. * @returns {Number} */ NetAddress.prototype.compare = function compare(addr) { var cmp = util.cmp(this.raw, addr.raw); if (cmp !== 0) return cmp; return this.port - addr.port; }; /** * 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. */ NetAddress.prototype.setNull = function setNull() { this.raw = IP.ZERO_IP; this.host = '0.0.0.0'; this.hostname = IP.toHostname(this.host, this.port); }; /** * Set host. * @param {String} host */ NetAddress.prototype.setHost = function setHost(host) { this.raw = IP.toBuffer(host); this.host = IP.toString(this.raw); this.hostname = IP.toHostname(this.host, this.port); }; /** * Set port. * @param {Number} port */ NetAddress.prototype.setPort = function setPort(port) { assert(port >= 0 && port <= 0xffff); this.port = port; this.hostname = IP.toHostname(this.host, port); }; /** * Inject properties from host, port, and network. * @private * @param {String} host * @param {Number} port * @param {(Network|NetworkType)?} network */ NetAddress.prototype.fromHost = function fromHost(host, port, network) { network = Network.get(network); assert(port >= 0 && port <= 0xffff); this.raw = IP.toBuffer(host); this.host = IP.toString(this.raw); this.port = port; this.services = NetAddress.DEFAULT_SERVICES; this.ts = network.now(); this.hostname = IP.toHostname(this.host, this.port); return this; }; /** * Instantiate a network address * from a host and port. * @param {String} host * @param {Number} port * @param {(Network|NetworkType)?} network * @returns {NetAddress} */ NetAddress.fromHost = function fromHost(host, port, network) { return new NetAddress().fromHost(host, port, network); }; /** * Inject properties from hostname and network. * @private * @param {String} hostname * @param {(Network|NetworkType)?} network */ NetAddress.prototype.fromHostname = function fromHostname(hostname, network) { var addr; network = Network.get(network); addr = IP.fromHostname(hostname, network.port); return this.fromHost(addr.host, addr.port, network); }; /** * Instantiate a network address * from a hostname (i.e. 127.0.0.1:8333). * @param {String} hostname * @param {(Network|NetworkType)?} network * @returns {NetAddress} */ NetAddress.fromHostname = function fromHostname(hostname, network) { return new NetAddress().fromHostname(hostname, network); }; /** * Inject properties from socket. * @private * @param {net.Socket} socket */ NetAddress.prototype.fromSocket = function fromSocket(socket, network) { var host = socket.remoteAddress; var port = socket.remotePort; assert(typeof host === 'string'); assert(typeof port === 'number'); return this.fromHost(IP.normalize(host), port, network); }; /** * Instantiate a network address * from a socket. * @param {net.Socket} socket * @returns {NetAddress} */ NetAddress.fromSocket = function fromSocket(hostname, network) { return new NetAddress().fromSocket(hostname, network); }; /** * Inject properties from buffer reader. * @private * @param {BufferReader} br * @param {Boolean?} full - Include timestamp. */ NetAddress.prototype.fromReader = function fromReader(br, full) { this.ts = full ? br.readU32() : 0; this.services = br.readU32(); // Note: hi service bits // are currently unused. br.readU32(); this.raw = br.readBytes(16); this.host = IP.toString(this.raw); this.port = br.readU16BE(); this.hostname = IP.toHostname(this.host, this.port); return this; }; /** * Inject properties from serialized data. * @private * @param {Buffer} data * @param {Boolean?} full - Include timestamp. */ NetAddress.prototype.fromRaw = function fromRaw(data, full) { return this.fromReader(new BufferReader(data), full); }; /** * Insantiate a network address from buffer reader. * @param {BufferReader} br * @param {Boolean?} full - Include timestamp. * @returns {NetAddress} */ NetAddress.fromReader = function fromReader(br, full) { return new NetAddress().fromReader(br, full); }; /** * Insantiate a network address from serialized data. * @param {Buffer} data * @param {Boolean?} full - Include timestamp. * @returns {NetAddress} */ NetAddress.fromRaw = function fromRaw(data, full) { return new NetAddress().fromRaw(data, full); }; /** * Write network address to a buffer writer. * @param {BufferWriter} bw * @param {Boolean?} full - Include timestamp. * @returns {Buffer} */ NetAddress.prototype.toWriter = function toWriter(bw, full) { if (full) bw.writeU32(this.ts); bw.writeU32(this.services); bw.writeU32(0); bw.writeBytes(this.raw); bw.writeU16BE(this.port); return bw; }; /** * Calculate serialization size of address. * @returns {Number} */ NetAddress.prototype.getSize = function getSize(full) { return 26 + (full ? 4 : 0); }; /** * Serialize network address. * @param {Boolean?} full - Include timestamp. * @returns {Buffer} */ NetAddress.prototype.toRaw = function toRaw(full) { var size = this.getSize(full); return this.toWriter(new StaticWriter(size), full).render(); }; /** * Convert net address to json-friendly object. * @returns {Object} */ NetAddress.prototype.toJSON = function toJSON() { return { host: this.host, port: this.port, services: this.services, ts: this.ts }; }; /** * Inject properties from json object. * @private * @param {Object} json * @returns {NetAddress} */ NetAddress.prototype.fromJSON = function fromJSON(json) { assert(util.isNumber(json.port)); assert(json.port >= 0 && json.port <= 0xffff); assert(util.isNumber(json.services)); assert(util.isNumber(json.ts)); this.raw = IP.toBuffer(json.host); this.host = json.host; this.port = json.port; this.services = json.services; this.ts = json.ts; this.hostname = IP.toHostname(this.host, this.port); return this; }; /** * Instantiate net address from json object. * @param {Object} json * @returns {NetAddress} */ NetAddress.fromJSON = function fromJSON(json) { return new NetAddress().fromJSON(json); }; /** * Inspect the network address. * @returns {Object} */ NetAddress.prototype.inspect = function inspect() { return ''; }; /* * Expose */ module.exports = NetAddress;