aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>2026-05-08 03:46:02 +0000
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>2026-05-08 03:46:02 +0000
commitf08627448d96ce07cac829c4192349c5077d2dfc (patch)
tree15af7840a3d104095136285673e1763a103c19ab
parentbump dependencies (diff)
downloadwireguard-config-f08627448d96ce07cac829c4192349c5077d2dfc.tar.gz
wireguard-config-f08627448d96ce07cac829c4192349c5077d2dfc.zip
bump dependencies
-rw-r--r--Gemfile.lock2
-rw-r--r--assets/js/bundle.js747
-rw-r--r--package-lock.json14
3 files changed, 560 insertions, 203 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index f7cb9f9..f3edf9d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -67,7 +67,7 @@ GEM
jekyll
jekyll-watch (2.2.1)
listen (~> 3.0)
- json (2.19.4)
+ json (2.19.5)
kramdown (2.5.2)
rexml (>= 3.4.4)
kramdown-parser-gfm (1.1.0)
diff --git a/assets/js/bundle.js b/assets/js/bundle.js
index d0138ed..da8f679 100644
--- a/assets/js/bundle.js
+++ b/assets/js/bundle.js
@@ -16,9 +16,11 @@ exports.AddressError = AddressError;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isInSubnet = isInSubnet;
exports.isCorrect = isCorrect;
+exports.prefixLengthFromMask = prefixLengthFromMask;
exports.numberToPaddedHex = numberToPaddedHex;
exports.stringToPaddedHex = stringToPaddedHex;
exports.testBit = testBit;
+const address_error_1 = require("./address-error");
function isInSubnet(address) {
if (this.subnetMask < address.subnetMask) {
return false;
@@ -39,6 +41,25 @@ function isCorrect(defaultBits) {
return this.parsedSubnet === String(this.subnetMask);
};
}
+/**
+ * Returns the prefix length (number of leading 1 bits) of a contiguous
+ * subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g.
+ * `255.0.255.0`).
+ */
+function prefixLengthFromMask(value, totalBits) {
+ const binary = value.toString(2).padStart(totalBits, '0');
+ if (binary.length > totalBits) {
+ throw new address_error_1.AddressError('Invalid subnet mask.');
+ }
+ const firstZero = binary.indexOf('0');
+ if (firstZero === -1) {
+ return totalBits;
+ }
+ if (binary.slice(firstZero).includes('1')) {
+ throw new address_error_1.AddressError('Invalid subnet mask.');
+ }
+ return firstZero;
+}
function numberToPaddedHex(number) {
return number.toString(16).padStart(2, '0');
}
@@ -58,7 +79,7 @@ function testBit(binaryValue, position) {
return binaryValue.substring(positionInString, positionInString + 1) === '1';
}
-},{}],3:[function(require,module,exports){
+},{"./address-error":1}],3:[function(require,module,exports){
"use strict";
/* eslint-disable no-param-reassign */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
@@ -89,9 +110,9 @@ exports.Address4 = void 0;
const common = __importStar(require("./common"));
const constants = __importStar(require("./v4/constants"));
const address_error_1 = require("./address-error");
+const isCorrect4 = common.isCorrect(constants.BITS);
/**
* Represents an IPv4 address
- * @class Address4
* @param {string} address - An IPv4 address string
*/
class Address4 {
@@ -104,15 +125,11 @@ class Address4 {
this.v4 = true;
/**
* Returns true if the address is correct, false otherwise
- * @memberof Address4
- * @instance
* @returns {Boolean}
*/
- this.isCorrect = common.isCorrect(constants.BITS);
+ this.isCorrect = isCorrect4;
/**
* Returns true if the given address is in the subnet of the current address
- * @memberof Address4
- * @instance
* @returns {boolean}
*/
this.isInSubnet = common.isInSubnet;
@@ -130,6 +147,13 @@ class Address4 {
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(address);
}
+ /**
+ * Returns true if the given string is a valid IPv4 address (with optional
+ * CIDR subnet), false otherwise. Host bits in the subnet portion are
+ * allowed (e.g. `192.168.1.5/24` is valid); for strict network-address
+ * validation compare `correctForm()` to `startAddress().correctForm()`,
+ * or use `networkForm()`.
+ */
static isValid(address) {
try {
// eslint-disable-next-line no-new
@@ -140,8 +164,11 @@ class Address4 {
return false;
}
}
- /*
- * Parses a v4 address
+ /**
+ * Parses an IPv4 address string into its four octet groups and stores the
+ * result on `this.parsedAddress`. Called automatically by the constructor;
+ * you typically don't need to call it directly. Throws `AddressError` if
+ * the input is not a valid IPv4 address.
*/
parse(address) {
const groups = address.split('.');
@@ -151,45 +178,110 @@ class Address4 {
return groups;
}
/**
- * Returns the correct form of an address
- * @memberof Address4
- * @instance
- * @returns {String}
+ * Returns the address in correct form: octets joined with `.` and any
+ * leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
+ * canonical dotted-decimal representation.
*/
correctForm() {
return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
}
/**
- * Converts a hex string to an IPv4 address object
- * @memberof Address4
- * @static
+ * Construct an `Address4` from an address and a dotted-decimal subnet
+ * mask given as separate strings (e.g. as returned by Node's
+ * `os.networkInterfaces()`). Throws `AddressError` if the mask is
+ * non-contiguous (e.g. `255.0.255.0`).
+ * @example
+ * var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
+ * address.subnetMask; // 24
+ */
+ static fromAddressAndMask(address, mask) {
+ const bits = common.prefixLengthFromMask(new Address4(mask).bigInt(), constants.BITS);
+ return new Address4(`${address}/${bits}`);
+ }
+ /**
+ * Construct an `Address4` from an address and a Cisco-style wildcard mask
+ * given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard
+ * mask is the bitwise inverse of the subnet mask. Throws `AddressError`
+ * if the mask is non-contiguous (e.g. `0.255.0.255`).
+ * @example
+ * var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255');
+ * address.subnetMask; // 24
+ */
+ static fromAddressAndWildcardMask(address, wildcardMask) {
+ const wildcard = new Address4(wildcardMask).bigInt();
+ const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
+ // eslint-disable-next-line no-bitwise
+ const mask = wildcard ^ allOnes;
+ const bits = common.prefixLengthFromMask(mask, constants.BITS);
+ return new Address4(`${address}/${bits}`);
+ }
+ /**
+ * Construct an `Address4` from a wildcard pattern with trailing `*`
+ * octets. The number of trailing wildcards determines the prefix
+ * length: each `*` represents 8 bits.
+ *
+ * Only trailing whole-octet wildcards are supported. Partial-octet
+ * wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g.
+ * `192.*.0.1`) throw `AddressError`.
+ * @example
+ * Address4.fromWildcard('192.168.0.*').subnet; // '/24'
+ * Address4.fromWildcard('192.168.*.*').subnet; // '/16'
+ * Address4.fromWildcard('*.*.*.*').subnet; // '/0'
+ */
+ static fromWildcard(input) {
+ const groups = input.split('.');
+ if (groups.length !== constants.GROUPS) {
+ throw new address_error_1.AddressError('Wildcard pattern must have 4 octets');
+ }
+ let firstWildcard = -1;
+ for (let i = 0; i < groups.length; i++) {
+ if (groups[i] === '*') {
+ if (firstWildcard === -1) {
+ firstWildcard = i;
+ }
+ }
+ else if (firstWildcard !== -1) {
+ throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)');
+ }
+ }
+ const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
+ const replaced = groups.map((g) => (g === '*' ? '0' : g));
+ const subnetBits = constants.BITS - trailing * 8;
+ return new Address4(`${replaced.join('.')}/${subnetBits}`);
+ }
+ /**
+ * Converts a hex string to an IPv4 address object. Accepts 8 hex digits
+ * with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`).
+ * Throws `AddressError` for any other length or for non-hex characters.
* @param {string} hex - a hex string to convert
* @returns {Address4}
*/
static fromHex(hex) {
- const padded = hex.replace(/:/g, '').padStart(8, '0');
+ const stripped = hex.replace(/:/g, '');
+ if (!/^[0-9a-fA-F]{8}$/.test(stripped)) {
+ throw new address_error_1.AddressError('IPv4 hex must be exactly 8 hex digits');
+ }
const groups = [];
- let i;
- for (i = 0; i < 8; i += 2) {
- const h = padded.slice(i, i + 2);
- groups.push(parseInt(h, 16));
+ for (let i = 0; i < 8; i += 2) {
+ groups.push(parseInt(stripped.slice(i, i + 2), 16));
}
return new Address4(groups.join('.'));
}
/**
- * Converts an integer into a IPv4 address object
- * @memberof Address4
- * @static
+ * Converts an integer into a IPv4 address object. The integer must be a
+ * non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
+ * `AddressError` is thrown.
* @param {integer} integer - a number to convert
* @returns {Address4}
*/
static fromInteger(integer) {
- return Address4.fromHex(integer.toString(16));
+ if (!Number.isInteger(integer) || integer < 0 || integer > 0xffffffff) {
+ throw new address_error_1.AddressError('IPv4 integer must be in the range 0 to 2**32 - 1');
+ }
+ return Address4.fromHex(integer.toString(16).padStart(8, '0'));
}
/**
* Return an address from in-addr.arpa form
- * @memberof Address4
- * @static
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
* @returns {Adress4}
* @example
@@ -204,17 +296,15 @@ class Address4 {
}
/**
* Converts an IPv4 address object to a hex string
- * @memberof Address4
- * @instance
* @returns {String}
*/
toHex() {
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
}
/**
- * Converts an IPv4 address object to an array of bytes
- * @memberof Address4
- * @instance
+ * Converts an IPv4 address object to an array of bytes.
+ *
+ * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
* @returns {Array}
*/
toArray() {
@@ -222,8 +312,6 @@ class Address4 {
}
/**
* Converts an IPv4 address object to an IPv6 address group
- * @memberof Address4
- * @instance
* @returns {String}
*/
toGroup6() {
@@ -236,8 +324,6 @@ class Address4 {
}
/**
* Returns the address as a `bigint`
- * @memberof Address4
- * @instance
* @returns {bigint}
*/
bigInt() {
@@ -245,8 +331,6 @@ class Address4 {
}
/**
* Helper function getting start address.
- * @memberof Address4
- * @instance
* @returns {bigint}
*/
_startAddress() {
@@ -255,8 +339,6 @@ class Address4 {
/**
* The first address in the range given by this address' subnet.
* Often referred to as the Network Address.
- * @memberof Address4
- * @instance
* @returns {Address4}
*/
startAddress() {
@@ -265,8 +347,6 @@ class Address4 {
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
- * @memberof Address4
- * @instance
* @returns {Address4}
*/
startAddressExclusive() {
@@ -275,8 +355,6 @@ class Address4 {
}
/**
* Helper function getting end address.
- * @memberof Address4
- * @instance
* @returns {bigint}
*/
_endAddress() {
@@ -285,8 +363,6 @@ class Address4 {
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
- * @memberof Address4
- * @instance
* @returns {Address4}
*/
endAddress() {
@@ -295,8 +371,6 @@ class Address4 {
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
- * @memberof Address4
- * @instance
* @returns {Address4}
*/
endAddressExclusive() {
@@ -304,19 +378,47 @@ class Address4 {
return Address4.fromBigInt(this._endAddress() - adjust);
}
/**
- * Converts a BigInt to a v4 address object
- * @memberof Address4
- * @static
+ * The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
+ * a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
+ * @returns {Address4}
+ */
+ subnetMaskAddress() {
+ return Address4.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants.BITS - this.subnetMask)}`));
+ }
+ /**
+ * The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
+ * the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`;
+ * call `.correctForm()` for the string.
+ * @returns {Address4}
+ */
+ wildcardMask() {
+ return Address4.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants.BITS - this.subnetMask)}`));
+ }
+ /**
+ * The network address in CIDR string form, e.g. `192.168.1.0/24` for
+ * `192.168.1.5/24`. For an address with no explicit subnet the prefix is
+ * `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`.
+ * @returns {string}
+ */
+ networkForm() {
+ return `${this.startAddress().correctForm()}/${this.subnetMask}`;
+ }
+ /**
+ * Converts a BigInt to a v4 address object. The value must be in the
+ * range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address4}
*/
static fromBigInt(bigInt) {
- return Address4.fromHex(bigInt.toString(16));
+ if (bigInt < 0n || bigInt > 0xffffffffn) {
+ throw new address_error_1.AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
+ }
+ return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
}
/**
- * Convert a byte array to an Address4 object
- * @memberof Address4
- * @static
+ * Convert a byte array to an Address4 object.
+ *
+ * To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
* @returns {Address4}
*/
@@ -334,8 +436,6 @@ class Address4 {
}
/**
* Convert an unsigned byte array to an Address4 object
- * @memberof Address4
- * @static
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
* @returns {Address4}
*/
@@ -349,8 +449,6 @@ class Address4 {
/**
* Returns the first n bits of the address, defaulting to the
* subnet mask
- * @memberof Address4
- * @instance
* @returns {String}
*/
mask(mask) {
@@ -361,8 +459,6 @@ class Address4 {
}
/**
* Returns the bits in the given range as a base-2 string
- * @memberof Address4
- * @instance
* @returns {string}
*/
getBitsBase2(start, end) {
@@ -370,10 +466,8 @@ class Address4 {
}
/**
* Return the reversed ip6.arpa form of the address
- * @memberof Address4
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
- * @instance
* @returns {String}
*/
reverseForm(options) {
@@ -388,21 +482,62 @@ class Address4 {
}
/**
* Returns true if the given address is a multicast address
- * @memberof Address4
- * @instance
* @returns {boolean}
*/
isMulticast() {
- return this.isInSubnet(new Address4('224.0.0.0/4'));
+ return this.isInSubnet(MULTICAST_V4);
+ }
+ /**
+ * Returns true if the address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private address ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`).
+ * @returns {boolean}
+ */
+ isPrivate() {
+ return PRIVATE_V4.some((subnet) => this.isInSubnet(subnet));
+ }
+ /**
+ * Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
+ * @returns {boolean}
+ */
+ isLoopback() {
+ return this.isInSubnet(LOOPBACK_V4);
+ }
+ /**
+ * Returns true if the address is in the link-local range `169.254.0.0/16` ([RFC 3927](https://datatracker.ietf.org/doc/html/rfc3927)).
+ * @returns {boolean}
+ */
+ isLinkLocal() {
+ return this.isInSubnet(LINK_LOCAL_V4);
+ }
+ /**
+ * Returns true if the address is the unspecified address `0.0.0.0`.
+ * @returns {boolean}
+ */
+ isUnspecified() {
+ return this.isInSubnet(UNSPECIFIED_V4);
+ }
+ /**
+ * Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
+ * @returns {boolean}
+ */
+ isBroadcast() {
+ return this.isInSubnet(BROADCAST_V4);
+ }
+ /**
+ * Returns true if the address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)).
+ * @returns {boolean}
+ */
+ isCGNAT() {
+ return this.isInSubnet(CGNAT_V4);
}
/**
* Returns a zero-padded base-2 string representation of the address
- * @memberof Address4
- * @instance
* @returns {string}
*/
binaryZeroPad() {
- return this.bigInt().toString(2).padStart(constants.BITS, '0');
+ if (this._binaryZeroPad === undefined) {
+ this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, '0');
+ }
+ return this._binaryZeroPad;
}
/**
* Groups an IPv4 address for inclusion at the end of an IPv6 address
@@ -418,6 +553,17 @@ class Address4 {
}
}
exports.Address4 = Address4;
+const MULTICAST_V4 = new Address4('224.0.0.0/4');
+const PRIVATE_V4 = [
+ new Address4('10.0.0.0/8'),
+ new Address4('172.16.0.0/12'),
+ new Address4('192.168.0.0/16'),
+];
+const LOOPBACK_V4 = new Address4('127.0.0.0/8');
+const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
+const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
+const BROADCAST_V4 = new Address4('255.255.255.255/32');
+const CGNAT_V4 = new Address4('100.64.0.0/10');
},{"./address-error":1,"./common":2,"./v4/constants":5}],4:[function(require,module,exports){
"use strict";
@@ -456,6 +602,7 @@ const ipv4_1 = require("./ipv4");
const regular_expressions_1 = require("./v6/regular-expressions");
const address_error_1 = require("./address-error");
const common_1 = require("./common");
+const isCorrect6 = common.isCorrect(constants6.BITS);
function assert(condition) {
if (!condition) {
throw new Error('Assertion failed.');
@@ -499,7 +646,6 @@ function unsignByte(b) {
}
/**
* Represents an IPv6 address
- * @class Address6
* @param {string} address - An IPv6 address string
* @param {number} [groups=8] - How many octets to parse
* @example
@@ -516,18 +662,14 @@ class Address6 {
// #region Attributes
/**
* Returns true if the given address is in the subnet of the current address
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
this.isInSubnet = common.isInSubnet;
/**
* Returns true if the address is correct, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
- this.isCorrect = common.isCorrect(constants6.BITS);
+ this.isCorrect = isCorrect6;
if (optionalGroups === undefined) {
this.groups = constants6.GROUPS;
}
@@ -558,6 +700,13 @@ class Address6 {
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(this.addressMinusSuffix);
}
+ /**
+ * Returns true if the given string is a valid IPv6 address (with optional
+ * CIDR subnet and zone identifier), false otherwise. Host bits in the
+ * subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict
+ * network-address validation compare `correctForm()` to
+ * `startAddress().correctForm()`, or use `networkForm()`.
+ */
static isValid(address) {
try {
// eslint-disable-next-line no-new
@@ -569,9 +718,8 @@ class Address6 {
}
}
/**
- * Convert a BigInt to a v6 address object
- * @memberof Address6
- * @static
+ * Convert a BigInt to a v6 address object. The value must be in the
+ * range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address6}
* @example
@@ -580,19 +728,21 @@ class Address6 {
* address.correctForm(); // '::e8:d4a5:1000'
*/
static fromBigInt(bigInt) {
+ if (bigInt < 0n || bigInt > (1n << BigInt(constants6.BITS)) - 1n) {
+ throw new address_error_1.AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
+ }
const hex = bigInt.toString(16).padStart(32, '0');
const groups = [];
- let i;
- for (i = 0; i < constants6.GROUPS; i++) {
+ for (let i = 0; i < constants6.GROUPS; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
- * Convert a URL (with optional port number) to an address object
- * @memberof Address6
- * @static
- * @param {string} url - a URL with optional port number
+ * Parse a URL (with optional bracketed host and port) into an address and
+ * port. Returns either `{ address, port }` on success or
+ * `{ error, address: null, port: null }` if the URL could not be parsed.
+ * Ports are returned as numbers (or `null` if absent or out of range).
* @example
* var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
* addressAndPort.address.correctForm(); // 'ffff::'
@@ -652,9 +802,91 @@ class Address6 {
};
}
/**
+ * Construct an `Address6` from an address and a hex subnet mask given as
+ * separate strings (e.g. as returned by Node's `os.networkInterfaces()`).
+ * Throws `AddressError` if the mask is non-contiguous (e.g.
+ * `ffff::ffff`).
+ * @example
+ * var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::');
+ * address.subnetMask; // 64
+ */
+ static fromAddressAndMask(address, mask) {
+ const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
+ return new Address6(`${address}/${bits}`);
+ }
+ /**
+ * Construct an `Address6` from an address and a Cisco-style wildcard mask
+ * given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`).
+ * The wildcard mask is the bitwise inverse of the subnet mask. Throws
+ * `AddressError` if the mask is non-contiguous.
+ * @example
+ * var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff');
+ * address.subnetMask; // 64
+ */
+ static fromAddressAndWildcardMask(address, wildcardMask) {
+ const wildcard = new Address6(wildcardMask).bigInt();
+ const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
+ // eslint-disable-next-line no-bitwise
+ const mask = wildcard ^ allOnes;
+ const bits = common.prefixLengthFromMask(mask, constants6.BITS);
+ return new Address6(`${address}/${bits}`);
+ }
+ /**
+ * Construct an `Address6` from a wildcard pattern with trailing `*`
+ * groups. The number of trailing wildcards determines the prefix
+ * length: each `*` represents 16 bits. `::` is expanded to zero groups
+ * (not wildcards) before evaluating trailing wildcards.
+ *
+ * Only trailing whole-group wildcards are supported. Partial-group
+ * wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g.
+ * `*::1`) throw `AddressError`.
+ * @example
+ * Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32'
+ * Address6.fromWildcard('2001:db8::*').subnet; // '/112'
+ * Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0'
+ */
+ static fromWildcard(input) {
+ if (input.includes('%') || input.includes('/')) {
+ throw new address_error_1.AddressError('Wildcard pattern must not include a zone or CIDR suffix');
+ }
+ const halves = input.split('::');
+ if (halves.length > 2) {
+ throw new address_error_1.AddressError("Wildcard pattern cannot contain more than one '::'");
+ }
+ let groups;
+ if (halves.length === 2) {
+ const left = halves[0] === '' ? [] : halves[0].split(':');
+ const right = halves[1] === '' ? [] : halves[1].split(':');
+ const remaining = constants6.GROUPS - left.length - right.length;
+ if (remaining < 1) {
+ throw new address_error_1.AddressError("Wildcard pattern with '::' has too many groups");
+ }
+ groups = [...left, ...new Array(remaining).fill('0'), ...right];
+ }
+ else {
+ groups = input.split(':');
+ }
+ if (groups.length !== constants6.GROUPS) {
+ throw new address_error_1.AddressError('Wildcard pattern must have 8 groups');
+ }
+ let firstWildcard = -1;
+ for (let i = 0; i < groups.length; i++) {
+ if (groups[i] === '*') {
+ if (firstWildcard === -1) {
+ firstWildcard = i;
+ }
+ }
+ else if (firstWildcard !== -1) {
+ throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)');
+ }
+ }
+ const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
+ const replaced = groups.map((g) => (g === '*' ? '0' : g));
+ const subnetBits = constants6.BITS - trailing * 16;
+ return new Address6(`${replaced.join(':')}/${subnetBits}`);
+ }
+ /**
* Create an IPv6-mapped address given an IPv4 address
- * @memberof Address6
- * @static
* @param {string} address - An IPv4 address string
* @returns {Address6}
* @example
@@ -669,8 +901,6 @@ class Address6 {
}
/**
* Return an address from ip6.arpa form
- * @memberof Address6
- * @static
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
* @returns {Adress6}
* @example
@@ -695,8 +925,6 @@ class Address6 {
}
/**
* Return the Microsoft UNC transcription of the address
- * @memberof Address6
- * @instance
* @returns {String} the Microsoft UNC transcription of the address
*/
microsoftTranscription() {
@@ -704,8 +932,6 @@ class Address6 {
}
/**
* Return the first n bits of the address, defaulting to the subnet mask
- * @memberof Address6
- * @instance
* @param {number} [mask=subnet] - the number of bits to mask
* @returns {String} the first n bits of the address as a string
*/
@@ -714,8 +940,6 @@ class Address6 {
}
/**
* Return the number of possible subnets of a given size in the address
- * @memberof Address6
- * @instance
* @param {number} [subnetSize=128] - the subnet size
* @returns {String}
*/
@@ -731,8 +955,6 @@ class Address6 {
}
/**
* Helper function getting start address.
- * @memberof Address6
- * @instance
* @returns {bigint}
*/
_startAddress() {
@@ -741,8 +963,6 @@ class Address6 {
/**
* The first address in the range given by this address' subnet
* Often referred to as the Network Address.
- * @memberof Address6
- * @instance
* @returns {Address6}
*/
startAddress() {
@@ -751,8 +971,6 @@ class Address6 {
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
- * @memberof Address6
- * @instance
* @returns {Address6}
*/
startAddressExclusive() {
@@ -761,8 +979,6 @@ class Address6 {
}
/**
* Helper function getting end address.
- * @memberof Address6
- * @instance
* @returns {bigint}
*/
_endAddress() {
@@ -771,8 +987,6 @@ class Address6 {
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
- * @memberof Address6
- * @instance
* @returns {Address6}
*/
endAddress() {
@@ -781,8 +995,6 @@ class Address6 {
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
- * @memberof Address6
- * @instance
* @returns {Address6}
*/
endAddressExclusive() {
@@ -790,36 +1002,73 @@ class Address6 {
return Address6.fromBigInt(this._endAddress() - adjust);
}
/**
- * Return the scope of the address
- * @memberof Address6
- * @instance
+ * The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
+ * `/64`. Returns an `Address6`; call `.correctForm()` for the string.
+ * @returns {Address6}
+ */
+ subnetMaskAddress() {
+ return Address6.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`));
+ }
+ /**
+ * The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a
+ * `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns
+ * an `Address6`; call `.correctForm()` for the string.
+ * @returns {Address6}
+ */
+ wildcardMask() {
+ return Address6.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`));
+ }
+ /**
+ * The network address in CIDR string form, e.g. `2001:db8::/32` for
+ * `2001:db8::1/32`. For an address with no explicit subnet the prefix
+ * is `/128`, e.g. `networkForm()` on `2001:db8::1` returns
+ * `2001:db8::1/128`.
+ * @returns {string}
+ */
+ networkForm() {
+ return `${this.startAddress().correctForm()}/${this.subnetMask}`;
+ }
+ /**
+ * Return the scope of the address. The 4-bit scope field
+ * ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7))
+ * is only defined for multicast addresses; for unicast addresses the scope
+ * is derived from the address type per
+ * [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6).
* @returns {String}
*/
getScope() {
- let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
- if (this.getType() === 'Global unicast' && scope !== 'Link local') {
- scope = 'Global';
+ const type = this.getType();
+ if (type === 'Multicast' || type.startsWith('Multicast ')) {
+ const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
+ return scope || 'Unknown';
+ }
+ // RFC 4291 §2.5.3: the loopback address is treated as having Link-Local
+ // scope. (Multicast scope 1, "Interface-Local", is a different concept
+ // used only for loopback transmission of multicast.)
+ if (type === 'Link-local unicast' || type === 'Loopback') {
+ return 'Link local';
+ }
+ // RFC 4007 §6: the unspecified address has no scope.
+ if (type === 'Unspecified') {
+ return 'Unknown';
}
- return scope || 'Unknown';
+ return 'Global';
}
/**
* Return the type of the address
- * @memberof Address6
- * @instance
* @returns {String}
*/
getType() {
- for (const subnet of Object.keys(constants6.TYPES)) {
- if (this.isInSubnet(new Address6(subnet))) {
- return constants6.TYPES[subnet];
+ for (let i = 0; i < TYPE_SUBNETS.length; i++) {
+ const entry = TYPE_SUBNETS[i];
+ if (this.isInSubnet(entry[0])) {
+ return entry[1];
}
}
return 'Global unicast';
}
/**
* Return the bits in the given range as a BigInt
- * @memberof Address6
- * @instance
* @returns {bigint}
*/
getBits(start, end) {
@@ -827,8 +1076,6 @@ class Address6 {
}
/**
* Return the bits in the given range as a base-2 string
- * @memberof Address6
- * @instance
* @returns {String}
*/
getBitsBase2(start, end) {
@@ -836,8 +1083,6 @@ class Address6 {
}
/**
* Return the bits in the given range as a base-16 string
- * @memberof Address6
- * @instance
* @returns {String}
*/
getBitsBase16(start, end) {
@@ -851,8 +1096,6 @@ class Address6 {
}
/**
* Return the bits that are set past the subnet mask length
- * @memberof Address6
- * @instance
* @returns {String}
*/
getBitsPastSubnet() {
@@ -860,10 +1103,8 @@ class Address6 {
}
/**
* Return the reversed ip6.arpa form of the address
- * @memberof Address6
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
- * @instance
* @returns {String}
*/
reverseForm(options) {
@@ -889,10 +1130,10 @@ class Address6 {
return 'ip6.arpa.';
}
/**
- * Return the correct form of the address
- * @memberof Address6
- * @instance
- * @returns {String}
+ * Returns the address in correct form, per
+ * [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
+ * stripped, the longest run of zero groups collapsed to `::`, and hex digits
+ * lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
*/
correctForm() {
let i;
@@ -936,8 +1177,6 @@ class Address6 {
}
/**
* Return a zero-padded base-2 string representation of the address
- * @memberof Address6
- * @instance
* @returns {String}
* @example
* var address = new Address6('2001:4860:4001:803::1011');
@@ -946,10 +1185,22 @@ class Address6 {
* // 0000000000000000000000000000000000000000000000000001000000010001'
*/
binaryZeroPad() {
- return this.bigInt().toString(2).padStart(constants6.BITS, '0');
+ if (this._binaryZeroPad === undefined) {
+ this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
+ }
+ return this._binaryZeroPad;
}
+ /**
+ * Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the
+ * trailing IPv4 address into `this.address4` / `this.parsedAddress4` and
+ * returning the address with the v4 portion converted to two v6 groups.
+ * Used internally by `parse()`.
+ */
// TODO: Improve the semantics of this helper function
parse4in6(address) {
+ if (address.indexOf('.') === -1) {
+ return address;
+ }
const groups = address.split(':');
const lastGroup = groups.slice(-1)[0];
const address4 = lastGroup.match(constants4.RE_ADDRESS);
@@ -972,6 +1223,13 @@ class Address6 {
}
return address;
}
+ /**
+ * Parses an IPv6 address string into its 8 hexadecimal groups (expanding
+ * any `::` elision and any trailing v4-in-v6 portion) and stores the result
+ * on `this.parsedAddress`. Called automatically by the constructor; you
+ * typically don't need to call it directly. Throws `AddressError` if the
+ * input is malformed.
+ */
// TODO: Make private?
parse(address) {
address = this.parse4in6(address);
@@ -1021,18 +1279,16 @@ class Address6 {
return groups;
}
/**
- * Return the canonical form of the address
- * @memberof Address6
- * @instance
- * @returns {String}
+ * Returns the canonical (fully expanded) form of the address: all 8 groups,
+ * each padded to 4 hex digits, with no `::` collapsing
+ * (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
+ * byte-exact comparison.
*/
canonicalForm() {
return this.parsedAddress.map(paddedHex).join(':');
}
/**
* Return the decimal form of the address
- * @memberof Address6
- * @instance
* @returns {String}
*/
decimal() {
@@ -1040,8 +1296,6 @@ class Address6 {
}
/**
* Return the address as a BigInt
- * @memberof Address6
- * @instance
* @returns {bigint}
*/
bigInt() {
@@ -1049,8 +1303,6 @@ class Address6 {
}
/**
* Return the last two groups of this address as an IPv4 address string
- * @memberof Address6
- * @instance
* @returns {Address4}
* @example
* var address = new Address6('2001:4860:4001::1825:bf11');
@@ -1058,12 +1310,10 @@ class Address6 {
*/
to4() {
const binary = this.binaryZeroPad().split('');
- return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16));
+ return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16).padStart(8, '0'));
}
/**
* Return the v4-in-v6 form of the address
- * @memberof Address6
- * @instance
* @returns {String}
*/
to4in6() {
@@ -1077,10 +1327,10 @@ class Address6 {
return correct + infix + address4.address;
}
/**
- * Return an object containing the Teredo properties of the address
- * @memberof Address6
- * @instance
- * @returns {Object}
+ * Decodes the Teredo tunneling fields embedded in this address. Returns the
+ * Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
+ * UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
+ * group/individual, nonce). Only meaningful for addresses in `2001::/32`.
*/
inspectTeredo() {
/*
@@ -1111,7 +1361,7 @@ class Address6 {
const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
const bitsForClient4 = this.getBits(96, 128);
// eslint-disable-next-line no-bitwise
- const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16));
+ const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'));
const flagsBase2 = this.getBitsBase2(64, 80);
const coneNat = (0, common_1.testBit)(flagsBase2, 15);
const reserved = (0, common_1.testBit)(flagsBase2, 14);
@@ -1134,10 +1384,9 @@ class Address6 {
};
}
/**
- * Return an object containing the 6to4 properties of the address
- * @memberof Address6
- * @instance
- * @returns {Object}
+ * Decodes the 6to4 tunneling fields embedded in this address. Returns the
+ * 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
+ * addresses in `2002::/16`.
*/
inspect6to4() {
/*
@@ -1153,8 +1402,6 @@ class Address6 {
}
/**
* Return a v6 6to4 address from a v6 v4inv6 address
- * @memberof Address6
- * @instance
* @returns {Address6}
*/
to6to4() {
@@ -1171,9 +1418,80 @@ class Address6 {
return new Address6(addr6to4);
}
/**
- * Return a byte array
- * @memberof Address6
- * @instance
+ * Embed an IPv4 address into a NAT64 IPv6 address using the encoding
+ * defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
+ * The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
+ * length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
+ * than /64 the IPv4 octets are split around the reserved bits 64–71.
+ * @example
+ * Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221'
+ * Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::'
+ */
+ static fromAddress4Nat64(address, prefix = '64:ff9b::/96') {
+ const v4 = new ipv4_1.Address4(address);
+ const prefix6 = new Address6(prefix);
+ const pl = prefix6.subnetMask;
+ if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
+ throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
+ }
+ const prefixBits = prefix6.binaryZeroPad();
+ const v4Bits = v4.binaryZeroPad();
+ let bits;
+ if (pl === 96) {
+ bits = prefixBits.slice(0, 96) + v4Bits;
+ }
+ else {
+ const beforeU = 64 - pl;
+ bits =
+ prefixBits.slice(0, pl) +
+ v4Bits.slice(0, beforeU) +
+ '00000000' +
+ v4Bits.slice(beforeU) +
+ '0'.repeat(128 - 72 - (32 - beforeU));
+ }
+ const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
+ const groups = [];
+ for (let i = 0; i < 8; i++) {
+ groups.push(hex.slice(i * 4, (i + 1) * 4));
+ }
+ return new Address6(groups.join(':'));
+ }
+ /**
+ * Extract the embedded IPv4 address from a NAT64 IPv6 address using the
+ * encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
+ * The default prefix is the well-known prefix `64:ff9b::/96`. Returns
+ * `null` if this address is not contained within the given prefix.
+ * @example
+ * new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33'
+ */
+ toAddress4Nat64(prefix = '64:ff9b::/96') {
+ const prefix6 = new Address6(prefix);
+ const pl = prefix6.subnetMask;
+ if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
+ throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
+ }
+ if (!this.isInSubnet(prefix6)) {
+ return null;
+ }
+ const bits = this.binaryZeroPad();
+ let v4Bits;
+ if (pl === 96) {
+ v4Bits = bits.slice(96, 128);
+ }
+ else {
+ const beforeU = 64 - pl;
+ v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU));
+ }
+ const octets = [];
+ for (let i = 0; i < 4; i++) {
+ octets.push(parseInt(v4Bits.slice(i * 8, (i + 1) * 8), 2).toString());
+ }
+ return new ipv4_1.Address4(octets.join('.'));
+ }
+ /**
+ * Return a byte array.
+ *
+ * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
* @returns {Array}
*/
toByteArray() {
@@ -1187,27 +1505,27 @@ class Address6 {
return bytes;
}
/**
- * Return an unsigned byte array
- * @memberof Address6
- * @instance
+ * Return an unsigned byte array.
+ *
+ * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
* @returns {Array}
*/
toUnsignedByteArray() {
return this.toByteArray().map(unsignByte);
}
/**
- * Convert a byte array to an Address6 object
- * @memberof Address6
- * @static
+ * Convert a byte array to an Address6 object.
+ *
+ * To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
* @returns {Address6}
*/
static fromByteArray(bytes) {
return this.fromUnsignedByteArray(bytes.map(unsignByte));
}
/**
- * Convert an unsigned byte array to an Address6 object
- * @memberof Address6
- * @static
+ * Convert an unsigned byte array to an Address6 object.
+ *
+ * To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
* @returns {Address6}
*/
static fromUnsignedByteArray(bytes) {
@@ -1222,8 +1540,6 @@ class Address6 {
}
/**
* Returns true if the address is in the canonical form, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
isCanonical() {
@@ -1231,8 +1547,6 @@ class Address6 {
}
/**
* Returns true if the address is a link local address, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
isLinkLocal() {
@@ -1245,53 +1559,81 @@ class Address6 {
}
/**
* Returns true if the address is a multicast address, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
isMulticast() {
- return this.getType() === 'Multicast';
+ const type = this.getType();
+ return type === 'Multicast' || type.startsWith('Multicast ');
}
/**
- * Returns true if the address is a v4-in-v6 address, false otherwise
- * @memberof Address6
- * @instance
+ * Returns true if the address was written in v4-in-v6 dotted-quad notation
+ * (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
+ * and does not reflect whether the address bits lie in the IPv4-mapped
+ * (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
* @returns {boolean}
*/
is4() {
return this.v4;
}
/**
+ * Returns true if the address is an IPv4-mapped IPv6 address in
+ * `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)),
+ * false otherwise. Unlike {@link is4}, this checks the underlying address
+ * bits rather than the textual notation, so `::ffff:127.0.0.1` and
+ * `::ffff:7f00:1` both return true.
+ * @returns {boolean}
+ */
+ isMapped4() {
+ return this.isInSubnet(IPV4_MAPPED_SUBNET);
+ }
+ /**
* Returns true if the address is a Teredo address, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
isTeredo() {
- return this.isInSubnet(new Address6('2001::/32'));
+ return this.isInSubnet(TEREDO_SUBNET);
}
/**
* Returns true if the address is a 6to4 address, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
is6to4() {
- return this.isInSubnet(new Address6('2002::/16'));
+ return this.isInSubnet(SIX_TO_FOUR_SUBNET);
}
/**
* Returns true if the address is a loopback address, false otherwise
- * @memberof Address6
- * @instance
* @returns {boolean}
*/
isLoopback() {
return this.getType() === 'Loopback';
}
+ /**
+ * Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses.
+ * @returns {boolean}
+ */
+ isULA() {
+ return this.isInSubnet(ULA_SUBNET);
+ }
+ /**
+ * Returns true if the address is the unspecified address `::`.
+ * @returns {boolean}
+ */
+ isUnspecified() {
+ return this.getType() === 'Unspecified';
+ }
+ /**
+ * Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)).
+ * @returns {boolean}
+ */
+ isDocumentation() {
+ return this.isInSubnet(DOCUMENTATION_SUBNET);
+ }
// #endregion
// #region HTML
/**
- * @returns {String} the address in link form with a default port of 80
+ * Returns the address as an HTTP URL with the host bracketed, e.g.
+ * `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended,
+ * e.g. `http://[2001:db8::1]:8080/`.
*/
href(optionalPort) {
if (optionalPort === undefined) {
@@ -1303,7 +1645,12 @@ class Address6 {
return `http://[${this.correctForm()}]${optionalPort}/`;
}
/**
- * @returns {String} a link suitable for conveying the address via a URL hash
+ * Returns an HTML `<a>` element whose `href` encodes the address in a URL
+ * hash fragment (default prefix `/#address=`). Useful for linking between
+ * pages of an address-inspector UI.
+ * @param options.className - CSS class for the rendered `<a>` element
+ * @param options.prefix - hash prefix prepended to the address (default `/#address=`)
+ * @param options.v4 - when true, render the address in v4-in-v6 form
*/
link(options) {
if (!options) {
@@ -1374,8 +1721,6 @@ class Address6 {
/**
* Generate a regular expression string that can be used to find or validate
* all variations of this address
- * @memberof Address6
- * @instance
* @param {boolean} substringSearch
* @returns {string}
*/
@@ -1420,8 +1765,6 @@ class Address6 {
/**
* Generate a regular expression that can be used to find or validate all
* variations of this address.
- * @memberof Address6
- * @instance
* @param {boolean} substringSearch
* @returns {RegExp}
*/
@@ -1430,6 +1773,15 @@ class Address6 {
}
}
exports.Address6 = Address6;
+const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [
+ new Address6(subnet),
+ constants6.TYPES[subnet],
+]);
+const TEREDO_SUBNET = new Address6('2001::/32');
+const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
+const ULA_SUBNET = new Address6('fc00::/7');
+const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
+const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
},{"./address-error":1,"./common":2,"./ipv4":3,"./v4/constants":5,"./v6/constants":6,"./v6/helpers":7,"./v6/regular-expressions":8}],5:[function(require,module,exports){
"use strict";
@@ -1489,6 +1841,11 @@ exports.TYPES = {
'::1/128': 'Loopback',
'ff00::/8': 'Multicast',
'fe80::/10': 'Link-local unicast',
+ 'fc00::/7': 'Unique local',
+ '2002::/16': '6to4',
+ '2001:db8::/32': 'Documentation',
+ '64:ff9b::/96': 'NAT64 (well-known)',
+ '64:ff9b:1::/48': 'NAT64 (local-use)',
};
/**
* A regular expression that matches bad characters in an IPv6 address
diff --git a/package-lock.json b/package-lock.json
index e5043cd..b02bac4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1034,9 +1034,9 @@
}
},
"node_modules/ip-address": {
- "version": "10.1.1",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.1.tgz",
- "integrity": "sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
+ "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -1077,12 +1077,12 @@
}
},
"node_modules/is-core-module": {
- "version": "2.16.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
- "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
"license": "MIT",
"dependencies": {
- "hasown": "^2.0.2"
+ "hasown": "^2.0.3"
},
"engines": {
"node": ">= 0.4"