v2
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2011 by Beau Gunderson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
[](https://github.com/beaugunderson/ip-address/actions/workflows/ci.yml)
|
||||
[![codecov]](https://codecov.io/github/beaugunderson/ip-address?branch=main)
|
||||
[![downloads]](https://www.npmjs.com/package/ip-address)
|
||||
[![npm]](https://www.npmjs.com/package/ip-address)
|
||||
|
||||
[codecov]: https://codecov.io/github/beaugunderson/ip-address/coverage.svg?branch=main
|
||||
[downloads]: https://img.shields.io/npm/dm/ip-address.svg
|
||||
[npm]: https://img.shields.io/npm/v/ip-address.svg
|
||||
|
||||
## ip-address
|
||||
|
||||
`ip-address` is a library for validating and manipulating IPv4 and IPv6 addresses in JavaScript and TypeScript.
|
||||
|
||||
### Install
|
||||
|
||||
```sh
|
||||
npm install ip-address
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
import { Address4, Address6 } from 'ip-address';
|
||||
|
||||
// Validation
|
||||
Address4.isValid('192.168.1.1'); // true
|
||||
Address6.isValid('2001:db8::1'); // true
|
||||
Address6.isValid('not an address'); // false
|
||||
|
||||
// Parsing (throws AddressError on invalid input)
|
||||
const v4 = new Address4('192.168.1.1/24');
|
||||
const v6 = new Address6('2001:db8::1/64');
|
||||
|
||||
// Subnet membership
|
||||
const host = new Address4('192.168.1.42');
|
||||
const network = new Address4('192.168.1.0/24');
|
||||
host.isInSubnet(network); // true
|
||||
|
||||
// Subnet range
|
||||
network.startAddress().correctForm(); // '192.168.1.0'
|
||||
network.endAddress().correctForm(); // '192.168.1.255'
|
||||
|
||||
// Strict network-address check (host bits must be zero).
|
||||
// isValid() accepts CIDRs with host bits set — '192.168.1.5/24' is a valid
|
||||
// host-with-subnet, but it isn't a network address.
|
||||
const cidr = new Address4('192.168.1.5/24');
|
||||
Address4.isValid('192.168.1.5/24'); // true
|
||||
cidr.correctForm() === cidr.startAddress().correctForm(); // false
|
||||
|
||||
// Address properties
|
||||
const link = new Address6('fe80::1');
|
||||
link.isLinkLocal(); // true
|
||||
link.isMulticast(); // false
|
||||
link.isLoopback(); // false
|
||||
|
||||
new Address4('192.168.1.1').isPrivate(); // true (RFC 1918)
|
||||
new Address6('fc00::1').isULA(); // true (RFC 4193)
|
||||
|
||||
// Numeric and byte representations
|
||||
v4.bigInt(); // 3232235777n
|
||||
v4.toArray(); // [192, 168, 1, 1]
|
||||
v6.canonicalForm(); // '2001:0db8:0000:0000:0000:0000:0000:0001'
|
||||
|
||||
// Embedded IPv4 + Teredo
|
||||
const teredo = new Address6('2001:0:ce49:7601:e866:efff:62c3:fffe');
|
||||
teredo.inspectTeredo().client4; // '157.60.0.1'
|
||||
|
||||
// Parse host + port from a URL
|
||||
Address6.fromURL('http://[2001:db8::1]:8080/').port; // 8080
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
- Written in TypeScript with full type definitions; usable from CommonJS and ESM
|
||||
- Zero runtime dependencies
|
||||
- Parses dotted-quad IPv4 and [RFC 4291](https://datatracker.ietf.org/doc/html/rfc4291) IPv6 notation, including subnets and zones. The `inet_aton` forms (`2130706433`, `0x7f000001`, `127.1`) and leading-zero octets are rejected by design — see [SECURITY.md](./SECURITY.md#classifiers-are-not-an-ssrf-defense)
|
||||
- Parses IPv6 hosts (and ports) from URLs via `Address6.fromURL(url)`
|
||||
- Subnet membership checks (`isInSubnet`) and range queries (`startAddress` / `endAddress`)
|
||||
- Special-property checks: private (RFC 1918) / ULA (RFC 4193), loopback, link-local, multicast, broadcast, unspecified, CGNAT, documentation, Teredo, 6to4, v4-in-v6
|
||||
- Decodes [Teredo](http://en.wikipedia.org/wiki/Teredo_tunneling#IPv6_addressing) and 6to4 tunneling information
|
||||
- Conversions: canonical/correct form, hex, binary, decimal, byte arrays, BigInt, `in-addr.arpa` / `ip6.arpa`
|
||||
- Runs in Node.js and the browser
|
||||
- Thousands of test cases
|
||||
|
||||
### Terminology
|
||||
|
||||
A few terms used throughout the API can be confusing if you haven't worked deeply with IPv6 before:
|
||||
|
||||
- **Correct form** — the shortest valid representation, 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 what most software displays.
|
||||
- **Canonical form** — the fully expanded representation: all 8 groups, each padded to 4 hex digits, no `::` collapsing (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and byte-exact comparison.
|
||||
- **Subnet** — the network portion of an address expressed as a CIDR prefix length (e.g. `/24` for IPv4, `/64` for IPv6). `startAddress()` / `endAddress()` return the bounds of the subnet's range.
|
||||
- **Zone** — the IPv6 scope identifier appended after `%`, used to disambiguate link-local addresses across interfaces (e.g. `fe80::1%eth0`).
|
||||
- **v4-in-v6** — mixed notation that embeds an IPv4 address as the last 32 bits of an IPv6 address, e.g. `::ffff:192.168.0.1`. Used for IPv4-mapped IPv6 addresses.
|
||||
- **Teredo** — a tunneling protocol that encodes an IPv4 endpoint, port, and flags inside a `2001::/32` IPv6 address. `inspectTeredo()` decodes those fields.
|
||||
- **6to4** — a tunneling protocol that embeds a full 32-bit IPv4 address in bits 16–47 of a `2002::/16` IPv6 address, i.e. the second and third groups (`192.0.2.4` becomes `2002:c000:204::`). `inspect6to4()` decodes the embedded v4 address.
|
||||
|
||||
### API
|
||||
|
||||
<!-- API:START -->
|
||||
|
||||
<details>
|
||||
<summary><a id="address4"></a><strong>Address4</strong> — Represents an IPv4 address</summary>
|
||||
|
||||
**Constructor**
|
||||
|
||||
- `new Address4(address: string): Address4`
|
||||
|
||||
**Static methods**
|
||||
|
||||
- `static isValid(address: string): boolean` — 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()`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L62)
|
||||
- `static fromAddressAndMask(address: string, mask: string): Address4` — 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`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L119)
|
||||
- `static fromAddressAndWildcardMask(address: string, wildcardMask: string): Address4` — 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`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L133)
|
||||
- `static fromWildcard(input: string): Address4` — 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`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L154)
|
||||
- `static fromHex(hex: string): Address4` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L189)
|
||||
- `static fromInteger(integer: number): Address4` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L212)
|
||||
- `static fromArpa(arpaFormAddress: string): Address4` — Return an address from in-addr.arpa form: the four octets reversed, with or without the `.in-addr.arpa` suffix and root dot, in any case. Throws `AddressError` unless the reversed labels form a valid IPv4 address, so `fromArpa(x.reverseForm())` round-trips reverseForm. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L231)
|
||||
- `static fromBigInt(bigInt: bigint): Address4` — Converts a BigInt to a v4 address object. The value must be in the range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L422)
|
||||
- `static fromByteArray(bytes: number[]): Address4` — Convert a byte array to an Address4 object. Throws `AddressError` unless given exactly 4 integers from 0 to 255. Signed bytes are rejected, so this differs from `Address6.fromByteArray`, which folds them; the two contracts converge on this stricter form in the next major version. To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L440)
|
||||
- `static fromUnsignedByteArray(bytes: number[]): Address4` — Convert an unsigned byte array to an Address4 object. Throws `AddressError` unless given exactly 4 bytes, and rejects values outside 0 to 255 when parsing the resulting address. To convert from a Node.js `Buffer`, spread it: `Address4.fromUnsignedByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L456)
|
||||
|
||||
**Instance methods**
|
||||
|
||||
- `parse(address: string): string[]` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L79)
|
||||
- `correctForm(): 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L100)
|
||||
- `toHex(): string` — Converts an IPv4 address object to a hex string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L254)
|
||||
- `toArray(): number[]` — Converts an IPv4 address object to an array of bytes. To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L264)
|
||||
- `toGroup6(): string` — Converts an IPv4 address object to an IPv6 address group [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L272)
|
||||
- `bigInt(): bigint` — Returns the address as a `bigint` [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L291)
|
||||
- `startAddress(): Address4` — The first address in the range given by this address' subnet. Often referred to as the Network Address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L308)
|
||||
- `startAddressExclusive(): Address4` — The first host address in the range given by this address's subnet ie the first address after the Network Address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L317)
|
||||
- `offset(n: number | bigint): Address4` — Returns the address `n` addresses after this one (or before, when `n` is negative), keeping this address's subnet mask. Throws `AddressError` when the result would fall outside the IPv4 address space or `n` is not an integer. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L332)
|
||||
- `nextNetwork(): Address4` — Returns the network that follows this address's network: the address after endAddress, with the same subnet mask. Throws `AddressError` when this network is the last one in the address space. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L346)
|
||||
- `endAddress(): Address4` — The last address in the range given by this address' subnet Often referred to as the Broadcast [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L369)
|
||||
- `endAddressExclusive(): Address4` — The last host address in the range given by this address's subnet ie the last address prior to the Broadcast Address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L378)
|
||||
- `subnetMaskAddress(): Address4` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L388)
|
||||
- `wildcardMask(): Address4` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L400)
|
||||
- `networkForm(): string` — 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`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L412)
|
||||
- `mask(mask?: number): string` — Returns the first n bits of the address, defaulting to the subnet mask [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L470)
|
||||
- `getBitsBase2(start: number, end: number): string` — Returns the bits in the given range as a base-2 string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L482)
|
||||
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed in-addr.arpa form of the address, e.g. `42.2.0.192.in-addr.arpa.` for `192.0.2.42`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L493)
|
||||
- `isMulticast(): boolean` — Returns true if the given address is a multicast address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L531)
|
||||
- `isPrivate(): boolean` — 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`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L539)
|
||||
- `isLoopback(): boolean` — Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L547)
|
||||
- `isLinkLocal(): boolean` — 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)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L555)
|
||||
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `0.0.0.0`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L563)
|
||||
- `isBroadcast(): boolean` — Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L571)
|
||||
- `isCGNAT(): boolean` — 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)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L579)
|
||||
- `isDocumentation(): boolean` — Returns true if the address is in one of the documentation ranges `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L588)
|
||||
- `isBenchmarking(): boolean` — Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L596)
|
||||
- `isReserved(): boolean` — Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)), which includes the limited broadcast address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L605)
|
||||
- `isGlobal(): boolean` — Returns true if the address is globally reachable: not multicast, and not in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/) marks as not globally reachable. That covers everything the individual classifiers name (private, loopback, link-local, CGNAT, unspecified, broadcast, documentation, benchmarking, reserved) and the blocks they do not, such as `0.0.0.0/8` and the IETF protocol assignments in `192.0.0.0/24`. This is the single predicate to use where a request must not reach an internal or special-purpose destination; see SECURITY.md. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L620)
|
||||
- `binaryZeroPad(): string` — Returns a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L628)
|
||||
- `groupForV6(): string` — Groups an IPv4 address for inclusion at the end of an IPv6 address. Returns an HTML fragment: each half of the address is wrapped in a `<span>` carrying the group classes an address-inspector UI hovers on. The address content is HTML-escaped; anything you concatenate around it is your responsibility. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L644)
|
||||
|
||||
**Properties**
|
||||
|
||||
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L14)
|
||||
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L15)
|
||||
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L16)
|
||||
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L17)
|
||||
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L18)
|
||||
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L19)
|
||||
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L20)
|
||||
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L21)
|
||||
- `isCorrect: () => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L108)
|
||||
- `isInSubnet: (address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address. An `Address6` is never in the subnet of an `Address4`; convert with `to4()` or `Address6.fromAddress4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L513)
|
||||
- `isHostInSubnet: (address: Address4 | Address6) => boolean` — Returns true if this address's host bits fall inside the given subnet, ignoring this address's own subnet mask. Prefer this over `isInSubnet` when classifying a single address, so the answer doesn't change with the CIDR suffix the caller happened to write — notably when the address came from untrusted input and the result backs a trust-boundary decision. An `Address6` is never in the subnet of an `Address4`; convert with `to4()` or `Address6.fromAddress4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv4.ts#L525)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><a id="address6"></a><strong>Address6</strong> — Represents an IPv6 address</summary>
|
||||
|
||||
**Constructor**
|
||||
|
||||
- `new Address6(address: string, optionalGroups?: number): Address6`
|
||||
|
||||
**Static methods**
|
||||
|
||||
- `static isValid(address: string): boolean` — 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()`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L182)
|
||||
- `static fromBigInt(bigInt: bigint): Address6` — Convert a BigInt to a v6 address object. The value must be in the range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L203)
|
||||
- `static fromURL(url: string): { error: string; address: null; port: null } | { error?: undefined; address: Address6; port: number | null }` — 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). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L228)
|
||||
- `static fromAddressAndMask(address: string, mask: string): 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`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L295)
|
||||
- `static fromAddressAndWildcardMask(address: string, wildcardMask: string): Address6` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L309)
|
||||
- `static fromWildcard(input: string): Address6` — 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`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L331)
|
||||
- `static fromAddress4(address: string): Address6` — Create an IPv6-mapped address given an IPv4 address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L392)
|
||||
- `static fromArpa(arpaFormAddress: string): Address6` — Return an address from ip6.arpa form. A full 32-nibble name gives a /128 address; a shorter name, as used for a delegated reverse zone, gives the network it covers, with a subnet mask of four bits per nibble, so `fromArpa(x.reverseForm())` round-trips reverseForm for any prefix. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L412)
|
||||
- `static fromAddress4Nat64(address: string, prefix?: string): Address6` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1119)
|
||||
- `static fromByteArray(bytes: number[]): Address6` — Convert a byte array to an Address6 object. Accepts unsigned bytes (0 to 255) or signed bytes (-128 to 127, as an `Int8Array` or a Java `byte[]` holds them), folding signed values to their unsigned equivalent. Throws `AddressError` unless given exactly 16 integers from -128 to 255. To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1234)
|
||||
- `static fromUnsignedByteArray(bytes: number[]): Address6` — Convert an unsigned byte array to an Address6 object. Throws `AddressError` unless given exactly 16 integers from 0 to 255. To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1251)
|
||||
|
||||
**Instance methods**
|
||||
|
||||
- `microsoftTranscription(): string` — Return the Microsoft UNC transcription of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L437)
|
||||
- `mask(mask?: number): string` — Return the first n bits of the address, defaulting to the subnet mask [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L446)
|
||||
- `possibleSubnets(subnetSize?: number): string` — Return the number of possible subnets of a given size in the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L456)
|
||||
- `startAddress(): Address6` — The first address in the range given by this address' subnet Often referred to as the Network Address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L481)
|
||||
- `startAddressExclusive(): Address6` — The first host address in the range given by this address's subnet ie the first address after the Network Address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L490)
|
||||
- `endAddress(): Address6` — The last address in the range given by this address's subnet. IPv6 has no broadcast address, so this is an ordinary assignable address (in a 64-bit-interface-identifier subnet it falls inside the reserved subnet-anycast block of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L510)
|
||||
- `endAddressExclusive(): Address6` — The address one before endAddress. This is the IPv6 counterpart of the IPv4 method that skips the broadcast address; IPv6 has no broadcast, so it drops exactly one address and does not model the 128 reserved subnet-anycast identifiers of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L521)
|
||||
- `offset(n: number | bigint): Address6` — Returns the address `n` addresses after this one (or before, when `n` is negative), keeping this address's subnet mask. Throws `AddressError` when the result would fall outside the IPv6 address space or `n` is not an integer. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L536)
|
||||
- `nextNetwork(): Address6` — Returns the network that follows this address's network: the address after endAddress, with the same subnet mask. Throws `AddressError` when this network is the last one in the address space. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L550)
|
||||
- `subnetMaskAddress(): Address6` — The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a `/64`. Returns an `Address6`; call `.correctForm()` for the string. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L565)
|
||||
- `wildcardMask(): Address6` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L577)
|
||||
- `networkForm(): string` — 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`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L590)
|
||||
- `getScope(): string` — 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). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L602)
|
||||
- `getType(): string` — Return the type of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L629)
|
||||
- `getBits(start: number, end: number): bigint` — Return the bits in the given range as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L644)
|
||||
- `getBitsBase2(start: number, end: number): string` — Return the bits in the given range as a base-2 string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L652)
|
||||
- `getBitsBase16(start: number, end: number): string` — Return the bits in the given range as a base-16 string [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L660)
|
||||
- `getBitsPastSubnet(): string` — Return the bits that are set past the subnet mask length [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L676)
|
||||
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed ip6.arpa form of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L686)
|
||||
- `correctForm(): 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L721)
|
||||
- `binaryZeroPad(): string` — Return a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L783)
|
||||
- `parse4in6(address: string): string` — 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()`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L797)
|
||||
- `parse(address: string): string[]` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L854)
|
||||
- `canonicalForm(): 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L934)
|
||||
- `decimal(): string` — Return the decimal form of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L942)
|
||||
- `bigInt(): bigint` — Return the address as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L950)
|
||||
- `to4(): Address4` — Return the last two groups of this address as an IPv4 address string. If this address carries a CIDR prefix that covers the trailing 32 bits (i.e. `subnetMask >= 96`), the resulting `Address4` inherits the corresponding v4 prefix (`subnetMask - 96`); otherwise it defaults to `/32`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L965)
|
||||
- `to4in6(): string` — Return the v4-in-v6 form of the address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L989)
|
||||
- `inspectTeredo(): TeredoProperties` — 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`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1010)
|
||||
- `inspect6to4(): SixToFourProperties` — 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`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1073)
|
||||
- `to6to4(): Address6 | null` — Return a v6 6to4 address from a v6 v4inv6 address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1093)
|
||||
- `toAddress4Nat64(prefix?: string): Address4 | null` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1162)
|
||||
- `toByteArray(): number[]` — Return a byte array. To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1197)
|
||||
- `toUnsignedByteArray(): number[]` — Return an unsigned byte array. To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1216)
|
||||
- `isCanonical(): boolean` — Returns true if the address is in the canonical form, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1298)
|
||||
- `isLinkLocal(): boolean` — Returns true if the address is a link-local unicast address in `fe80::/10` ([RFC 4291 §2.4](https://datatracker.ietf.org/doc/html/rfc4291#section-2.4)) or an IPv4-mapped / NAT64 address whose embedded IPv4 address is link-local (`169.254.0.0/16`, e.g. `::ffff:169.254.169.254`), false otherwise. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1309)
|
||||
- `isMulticast(): boolean` — Returns true if the address is a multicast address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1322)
|
||||
- `is4(): boolean` — 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 isMapped4. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1339)
|
||||
- `isMapped4(): boolean` — 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 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1351)
|
||||
- `embeddedIPv4(): Address4 | null` — If this address embeds a routable IPv4 address — i.e. it is IPv4-mapped (`::ffff:0:0/96`) or sits in the NAT64 well-known prefix (`64:ff9b::/96`, [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052)) — return that embedded address as an Address4; otherwise return null. The special-property checks (`isLoopback`, `isLinkLocal`, `isMulticast`, `isUnspecified`, `isPrivate`, `isCGNAT`, `isBroadcast`) call this first and delegate to the embedded Address4 when present, so a literal such as `::ffff:127.0.0.1` is classified by what it actually reaches (loopback) rather than by its IPv6 wrapper (which `getType()` reports as IPv4-mapped). This matters wherever the checks back a trust-boundary decision (e.g. an SSRF allow/deny filter): without normalization, `::ffff:10.0.0.1`, `::ffff:169.254.169.254`, `64:ff9b::7f00:1`, etc. would all read as non-internal. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1372)
|
||||
- `isTeredo(): boolean` — Returns true if the address is a Teredo address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1384)
|
||||
- `is6to4(): boolean` — Returns true if the address is a 6to4 address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1392)
|
||||
- `isLoopback(): boolean` — Returns true if the address is a loopback address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1400)
|
||||
- `isULA(): boolean` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1413)
|
||||
- `isPrivate(): boolean` — Returns true if the address is private, i.e. a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)), an address in the NAT64 local-use range `64:ff9b:1::/48` ([RFC 8215](https://datatracker.ietf.org/doc/html/rfc8215)), or an IPv4-mapped / NAT64 well-known address whose embedded IPv4 address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private ranges (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to Address4.isPrivate; use it instead of isULA when you need to catch mapped RFC 1918 addresses as well as native ULAs. The local-use NAT64 range is reported private as a whole rather than by its embedded IPv4 address: an operator may carve a prefix of any RFC 6052 length out of `64:ff9b:1::/48`, so the same bits decode to different IPv4 addresses under different deployments and no single decoding is correct. Use toAddress4Nat64 with the deployment's prefix to decode one. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1435)
|
||||
- `isCGNAT(): boolean` — Returns true if the address is an IPv4-mapped / NAT64 address whose embedded IPv4 address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)), false otherwise. There is no native IPv6 CGNAT range, so this only ever returns true for an embedded IPv4 address (e.g. `::ffff:100.64.0.1`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1452)
|
||||
- `isBroadcast(): boolean` — Returns true if the address is an IPv4-mapped / NAT64 address whose embedded IPv4 address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)), false otherwise. There is no IPv6 broadcast, so this only ever returns true for an embedded IPv4 address (e.g. `::ffff:255.255.255.255`). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1469)
|
||||
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `::`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1482)
|
||||
- `isDocumentation(): boolean` — Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)). [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1495)
|
||||
- `isBenchmarking(): boolean` — Returns true if the address is in the benchmarking range `2001:2::/48` ([RFC 5180](https://datatracker.ietf.org/doc/html/rfc5180)) or is an IPv4-mapped / NAT64 address whose embedded IPv4 address is in `198.18.0.0/15`, false otherwise. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1506)
|
||||
- `isGlobal(): boolean` — Returns true if the address is globally reachable: inside the global unicast allocation `2000::/3` (the only range the [IANA IPv6 Address Space Registry](https://www.iana.org/assignments/ipv6-address-space/) assigns for global unicast; everything else is reserved, ULA, link-local, or multicast) and not in any block the [IANA IPv6 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv6-special-registry/) marks as not globally reachable. An IPv4-mapped or NAT64 well-known address answers for its embedded IPv4 address, so `::ffff:10.0.0.1` and `64:ff9b::7f00:1` are not global. Teredo (`2001::/32`) and 6to4 (`2002::/16`) are not global either: the registry lists them as N/A and a packet to one needs a relay. This covers everything the individual classifiers name and the blocks they do not: the discard-only prefix `100::/64`, the IETF protocol assignments in `2001::/23`, the deprecated site-local `fec0::/10` and IPv4-compatible `::/96` ranges, and unallocated space such as `4000::/3`. It is the single predicate to use where a request must not reach an internal or special-purpose destination; see SECURITY.md. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1535)
|
||||
- `href(optionalPort?: string | number): string` — 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/`. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1554)
|
||||
- `link(options?: { className?: string; prefix?: string; v4?: boolean }): string` — 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. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1572)
|
||||
- `group(): string` — Groups an address. Returns an HTML fragment: each group is wrapped in a `<span>` carrying the group classes an address-inspector UI hovers on. The address content is HTML-escaped; anything you concatenate around it is your responsibility. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1617)
|
||||
- `regularExpressionString(substringSearch?: boolean): string` — Generate a regular expression string that can be used to find or validate all variations of this address [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1669)
|
||||
- `regularExpression(substringSearch?: boolean): RegExp` — Generate a regular expression that can be used to find or validate all variations of this address. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1723)
|
||||
|
||||
**Properties**
|
||||
|
||||
- `address4: Address4` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L97)
|
||||
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L98)
|
||||
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L99)
|
||||
- `elidedGroups: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L100)
|
||||
- `elisionBegin: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L101)
|
||||
- `elisionEnd: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L102)
|
||||
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L103)
|
||||
- `parsedAddress4: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L104)
|
||||
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L105)
|
||||
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L106)
|
||||
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L107)
|
||||
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L108)
|
||||
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L109)
|
||||
- `zone: string` — [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L110)
|
||||
- `isInSubnet: (address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address. An `Address4` is never in the subnet of an `Address6`; convert with `Address6.fromAddress4()` or `to4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1274)
|
||||
- `isHostInSubnet: (address: Address4 | Address6) => boolean` — Returns true if this address's host bits fall inside the given subnet, ignoring this address's own subnet mask. Prefer this over `isInSubnet` when classifying a single address, so the answer doesn't change with the CIDR suffix the caller happened to write — notably when the address came from untrusted input and the result backs a trust-boundary decision. An `Address4` is never in the subnet of an `Address6`; convert with `Address6.fromAddress4()` or `to4()` to compare across families. [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1286)
|
||||
- `isCorrect: () => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/main/src/ipv6.ts#L1292)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><a id="addresserror"></a><strong>AddressError</strong></summary>
|
||||
|
||||
**Constructor**
|
||||
|
||||
- `new AddressError(message: string, parseMessage?: string): AddressError`
|
||||
|
||||
**Properties**
|
||||
|
||||
- `parseMessage: string` — The offending address with the portion that failed to parse wrapped in `<span class="parse-error">`, e.g. `2001:db8<span class="parse-error">:::</span>1`. Present only on errors thrown from a parse path that can point at a specific substring. This is an HTML fragment intended for an address-inspector UI. The address content is HTML-escaped, so it is safe to insert as-is; treat it as markup rather than as a plain-text message, and use `message` for anything that renders as text. [src](https://github.com/beaugunderson/ip-address/blob/main/src/address-error.ts#L13)
|
||||
|
||||
</details>
|
||||
|
||||
<!-- API:END -->
|
||||
|
||||
### Security
|
||||
|
||||
Vulnerabilities go through [GitHub's private vulnerability reporting](https://github.com/beaugunderson/ip-address/security/advisories/new); [SECURITY.md](./SECURITY.md) has the scope and what to expect. Confirmed issues get a fix, a release, and a public [advisory](https://github.com/beaugunderson/ip-address/security/advisories) with a CVE, rather than a quiet patch.
|
||||
|
||||
Releases are built and published by CI through npm trusted publishing. Every version from 10.2.1 onward carries a provenance attestation tying the tarball to the commit and workflow that built it. Check it with `npm audit signatures`.
|
||||
|
||||
If you are using the address-property checks as a security control, read [that section of SECURITY.md](./SECURITY.md#classifiers-are-not-an-ssrf-defense) first. `isPrivate()`, `isLoopback()`, `isInSubnet()` and their siblings classify an address that has already been parsed, which makes them one layer of an SSRF guard rather than the whole of it. A hostname that resolves to an internal address, a DNS record that changes after your check, or a redirect will all sail past a guard built only on them. Within that layer, use `isGlobal()` rather than an OR of the named classifiers: it is false for every block the IANA special-purpose registries mark as not globally reachable, including the ones with no classifier of their own.
|
||||
|
||||
### Used by
|
||||
|
||||
`ip-address` is downloaded ~86 million times per week, mostly via the Node proxy/agent ecosystem. The dependency chain runs through a handful of widely-used packages:
|
||||
|
||||
- [**socks**](https://github.com/JoshGlazebrook/socks) (~53M weekly) — SOCKS4/5 client for Node; depends on `ip-address` directly. The single biggest source of downloads.
|
||||
- [**socks-proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent) (~55M weekly) — `http.Agent` for SOCKS proxies; depends on `socks`. Bundled by virtually every CLI that respects `HTTPS_PROXY`.
|
||||
- [**npm**](https://github.com/npm/cli) and [**pnpm**](https://github.com/pnpm/pnpm) — both bundle `socks-proxy-agent` through their HTTP fetch stack (`make-fetch-happen` → `@npmcli/agent`), so every Node install on the planet pulls in `ip-address` as a transitive dependency.
|
||||
- [**Puppeteer**](https://github.com/puppeteer/puppeteer) — `@puppeteer/browsers` uses `proxy-agent` for browser-binary downloads, which routes through `socks-proxy-agent` → `socks` → `ip-address`.
|
||||
- [**proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/proxy-agent) (~28M weekly) and [**pac-proxy-agent**](https://github.com/TooTallNate/proxy-agents/tree/main/packages/pac-proxy-agent) (~27M weekly) — auto-detecting proxy agents (HTTP/HTTPS/SOCKS/PAC) used widely in scraping, headless-browser, and CI tooling.
|
||||
- [**cacache**](https://github.com/npm/cacache) (~40M weekly) — npm's content-addressable cache; pulls in the same fetch stack.
|
||||
|
||||
Beyond the proxy chain, `ip-address` has been used by Juniper Networks' Contrail, Ably's proxy-protocol implementation, Rackspace's serialization framework, IPFS, and the [SwitchyOmega](https://github.com/FelisCatus/SwitchyOmega) Chrome extension, among many others.
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
export declare class AddressError extends Error {
|
||||
/**
|
||||
* The offending address with the portion that failed to parse wrapped in
|
||||
* `<span class="parse-error">`, e.g. `2001:db8<span
|
||||
* class="parse-error">:::</span>1`. Present only on errors thrown from a
|
||||
* parse path that can point at a specific substring.
|
||||
*
|
||||
* This is an HTML fragment intended for an address-inspector UI. The
|
||||
* address content is HTML-escaped, so it is safe to insert as-is; treat it
|
||||
* as markup rather than as a plain-text message, and use `message` for
|
||||
* anything that renders as text.
|
||||
*/
|
||||
parseMessage?: string;
|
||||
constructor(message: string, parseMessage?: string);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AddressError = void 0;
|
||||
class AddressError extends Error {
|
||||
constructor(message, parseMessage) {
|
||||
super(message);
|
||||
this.name = 'AddressError';
|
||||
this.parseMessage = parseMessage;
|
||||
}
|
||||
}
|
||||
exports.AddressError = AddressError;
|
||||
//# sourceMappingURL=address-error.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"address-error.js","sourceRoot":"","sources":["../src/address-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;IAcrC,YAAY,OAAe,EAAE,YAAqB;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QAEf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAE3B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;CACF;AArBD,oCAqBC","sourcesContent":["export class AddressError extends Error {\n /**\n * The offending address with the portion that failed to parse wrapped in\n * `<span class=\"parse-error\">`, e.g. `2001:db8<span\n * class=\"parse-error\">:::</span>1`. Present only on errors thrown from a\n * parse path that can point at a specific substring.\n *\n * This is an HTML fragment intended for an address-inspector UI. The\n * address content is HTML-escaped, so it is safe to insert as-is; treat it\n * as markup rather than as a plain-text message, and use `message` for\n * anything that renders as text.\n */\n parseMessage?: string;\n\n constructor(message: string, parseMessage?: string) {\n super(message);\n\n this.name = 'AddressError';\n\n this.parseMessage = parseMessage;\n }\n}\n"]}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
import { Address4 } from './ipv4';
|
||||
import { Address6 } from './ipv6';
|
||||
export interface ReverseFormOptions {
|
||||
omitSuffix?: boolean;
|
||||
}
|
||||
/**
|
||||
* Returns whether this address's *network* is contained within `address`,
|
||||
* i.e. whether every address this one can represent also falls inside
|
||||
* `address`. A network wider than `address` is not contained in it, so
|
||||
* `10.0.0.0/8` is not in `10.0.0.0/16`.
|
||||
*
|
||||
* To ask whether the address itself falls inside a range, ignoring any CIDR
|
||||
* suffix it was written with, use {@link isHostInSubnet} instead. That is the
|
||||
* question the special-use classifiers ask.
|
||||
*/
|
||||
export declare function isInSubnet(this: Address4 | Address6, address: Address4 | Address6): boolean;
|
||||
/**
|
||||
* Returns whether this address's host bits fall inside `address`, ignoring
|
||||
* this address's own subnet mask.
|
||||
*
|
||||
* This is the primitive the special-use classifiers (`isLoopback`,
|
||||
* `isPrivate`, `isLinkLocal`, `getType`, …) are built on: they answer a
|
||||
* question about the address, so the answer must not change with the CIDR
|
||||
* suffix the caller happened to write. Use this rather than
|
||||
* {@link isInSubnet} when classifying a single address — notably when the
|
||||
* address came from untrusted input and the result backs a trust-boundary
|
||||
* decision such as an SSRF allow/deny filter.
|
||||
*
|
||||
* An address of one family is never inside a network of the other, so an
|
||||
* `Address4` against an `Address6` (or the reverse) is `false`. To compare
|
||||
* across families, convert first: `Address6.fromAddress4()`, `to4()`, or
|
||||
* `toAddress4Nat64()`.
|
||||
*/
|
||||
export declare function isHostInSubnet(this: Address4 | Address6, address: Address4 | Address6): boolean;
|
||||
/**
|
||||
* One parsed row of an IANA special-purpose address registry: the block, and
|
||||
* whether the registry marks it globally reachable (`null` when the column is
|
||||
* blank, in which case the containing block answers).
|
||||
*/
|
||||
export interface SpecialPurposeEntry<A extends Address4 | Address6> {
|
||||
subnet: A;
|
||||
reachable: boolean | null;
|
||||
}
|
||||
/**
|
||||
* Returns whether the registry marks this address globally reachable: the
|
||||
* answer of the most specific entry containing it that has one, or `true`
|
||||
* when no entry contains it.
|
||||
*/
|
||||
export declare function isGloballyReachable<A extends Address4 | Address6>(this: A, entries: ReadonlyArray<SpecialPurposeEntry<A>>): boolean;
|
||||
/**
|
||||
* Adds `n` to `value` and returns the result, throwing `AddressError` unless
|
||||
* `n` is an integer and the result stays within `[0, 2**bits - 1]`.
|
||||
*/
|
||||
export declare function offsetBigInt(value: bigint, n: number | bigint, bits: number, family: string): bigint;
|
||||
export declare function isCorrect(defaultBits: number): (this: Address4 | Address6) => boolean;
|
||||
/**
|
||||
* 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`).
|
||||
*/
|
||||
export declare function prefixLengthFromMask(value: bigint, totalBits: number): number;
|
||||
/**
|
||||
* Throws `AddressError` unless `bytes` holds exactly `byteCount` integers,
|
||||
* each from `minimum` to 255. Pass a `minimum` of `-128` where signed bytes
|
||||
* are accepted and folded to unsigned, and `0` where they are not.
|
||||
*/
|
||||
export declare function assertByteArray(bytes: number[], byteCount: number, family: 'IPv4' | 'IPv6', minimum: number): void;
|
||||
export declare function numberToPaddedHex(number: number): string;
|
||||
export declare function stringToPaddedHex(numberString: string): string;
|
||||
/**
|
||||
* @param binaryValue Binary representation of a value (e.g. `10`)
|
||||
* @param position Byte position, where 0 is the least significant bit
|
||||
*/
|
||||
export declare function testBit(binaryValue: string, position: number): boolean;
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isInSubnet = isInSubnet;
|
||||
exports.isHostInSubnet = isHostInSubnet;
|
||||
exports.isGloballyReachable = isGloballyReachable;
|
||||
exports.offsetBigInt = offsetBigInt;
|
||||
exports.isCorrect = isCorrect;
|
||||
exports.prefixLengthFromMask = prefixLengthFromMask;
|
||||
exports.assertByteArray = assertByteArray;
|
||||
exports.numberToPaddedHex = numberToPaddedHex;
|
||||
exports.stringToPaddedHex = stringToPaddedHex;
|
||||
exports.testBit = testBit;
|
||||
const address_error_1 = require("./address-error");
|
||||
/**
|
||||
* Returns whether this address's *network* is contained within `address`,
|
||||
* i.e. whether every address this one can represent also falls inside
|
||||
* `address`. A network wider than `address` is not contained in it, so
|
||||
* `10.0.0.0/8` is not in `10.0.0.0/16`.
|
||||
*
|
||||
* To ask whether the address itself falls inside a range, ignoring any CIDR
|
||||
* suffix it was written with, use {@link isHostInSubnet} instead. That is the
|
||||
* question the special-use classifiers ask.
|
||||
*/
|
||||
function isInSubnet(address) {
|
||||
if (this.subnetMask < address.subnetMask) {
|
||||
return false;
|
||||
}
|
||||
return isHostInSubnet.call(this, address);
|
||||
}
|
||||
/**
|
||||
* Returns whether this address's host bits fall inside `address`, ignoring
|
||||
* this address's own subnet mask.
|
||||
*
|
||||
* This is the primitive the special-use classifiers (`isLoopback`,
|
||||
* `isPrivate`, `isLinkLocal`, `getType`, …) are built on: they answer a
|
||||
* question about the address, so the answer must not change with the CIDR
|
||||
* suffix the caller happened to write. Use this rather than
|
||||
* {@link isInSubnet} when classifying a single address — notably when the
|
||||
* address came from untrusted input and the result backs a trust-boundary
|
||||
* decision such as an SSRF allow/deny filter.
|
||||
*
|
||||
* An address of one family is never inside a network of the other, so an
|
||||
* `Address4` against an `Address6` (or the reverse) is `false`. To compare
|
||||
* across families, convert first: `Address6.fromAddress4()`, `to4()`, or
|
||||
* `toAddress4Nat64()`.
|
||||
*/
|
||||
function isHostInSubnet(address) {
|
||||
// mask() is a bit string of the family's width, and the leading bits of a
|
||||
// 32-bit string can coincide with those of a 128-bit one (a00::1 and
|
||||
// 10.0.0.0/8 both mask to 00001010), so the widths must agree before the
|
||||
// strings are compared.
|
||||
if (this.binaryZeroPad().length !== address.binaryZeroPad().length) {
|
||||
return false;
|
||||
}
|
||||
return this.mask(address.subnetMask) === address.mask();
|
||||
}
|
||||
/**
|
||||
* Returns whether the registry marks this address globally reachable: the
|
||||
* answer of the most specific entry containing it that has one, or `true`
|
||||
* when no entry contains it.
|
||||
*/
|
||||
function isGloballyReachable(entries) {
|
||||
let best = null;
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const entry = entries[i];
|
||||
if (entry.reachable !== null &&
|
||||
isHostInSubnet.call(this, entry.subnet) &&
|
||||
(best === null || entry.subnet.subnetMask > best.subnet.subnetMask)) {
|
||||
best = entry;
|
||||
}
|
||||
}
|
||||
return best === null ? true : best.reachable;
|
||||
}
|
||||
/**
|
||||
* Adds `n` to `value` and returns the result, throwing `AddressError` unless
|
||||
* `n` is an integer and the result stays within `[0, 2**bits - 1]`.
|
||||
*/
|
||||
function offsetBigInt(value, n, bits, family) {
|
||||
if (typeof n === 'number' && !Number.isSafeInteger(n)) {
|
||||
throw new address_error_1.AddressError(`${family} offset must be an integer`);
|
||||
}
|
||||
if (typeof n !== 'number' && typeof n !== 'bigint') {
|
||||
throw new address_error_1.AddressError(`${family} offset must be an integer`);
|
||||
}
|
||||
const result = value + BigInt(n);
|
||||
if (result < BigInt(0) || result > (BigInt(1) << BigInt(bits)) - BigInt(1)) {
|
||||
throw new address_error_1.AddressError(`${family} offset leaves the address space`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function isCorrect(defaultBits) {
|
||||
return function isCorrectForm() {
|
||||
if (this.addressMinusSuffix !== this.correctForm()) {
|
||||
return false;
|
||||
}
|
||||
if (this.subnetMask === defaultBits && !this.parsedSubnet) {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* Throws `AddressError` unless `bytes` holds exactly `byteCount` integers,
|
||||
* each from `minimum` to 255. Pass a `minimum` of `-128` where signed bytes
|
||||
* are accepted and folded to unsigned, and `0` where they are not.
|
||||
*/
|
||||
function assertByteArray(bytes, byteCount, family, minimum) {
|
||||
if (bytes.length !== byteCount) {
|
||||
throw new address_error_1.AddressError(`${family} addresses require exactly ${byteCount} bytes`);
|
||||
}
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
if (!Number.isInteger(bytes[i]) || bytes[i] < minimum || bytes[i] > 255) {
|
||||
throw new address_error_1.AddressError(`All bytes must be integers between ${minimum} and 255`);
|
||||
}
|
||||
}
|
||||
}
|
||||
function numberToPaddedHex(number) {
|
||||
return number.toString(16).padStart(2, '0');
|
||||
}
|
||||
function stringToPaddedHex(numberString) {
|
||||
return numberToPaddedHex(parseInt(numberString, 10));
|
||||
}
|
||||
/**
|
||||
* @param binaryValue Binary representation of a value (e.g. `10`)
|
||||
* @param position Byte position, where 0 is the least significant bit
|
||||
*/
|
||||
function testBit(binaryValue, position) {
|
||||
const { length } = binaryValue;
|
||||
if (position > length) {
|
||||
return false;
|
||||
}
|
||||
const positionInString = length - position;
|
||||
return binaryValue.substring(positionInString, positionInString + 1) === '1';
|
||||
}
|
||||
//# sourceMappingURL=common.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+7
@@ -0,0 +1,7 @@
|
||||
export { Address4 } from './ipv4';
|
||||
export { Address6 } from './ipv6';
|
||||
export { AddressError } from './address-error';
|
||||
import * as helpers from './v6/helpers';
|
||||
export declare const v6: {
|
||||
helpers: typeof helpers;
|
||||
};
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.v6 = exports.AddressError = exports.Address6 = exports.Address4 = void 0;
|
||||
var ipv4_1 = require("./ipv4");
|
||||
Object.defineProperty(exports, "Address4", { enumerable: true, get: function () { return ipv4_1.Address4; } });
|
||||
var ipv6_1 = require("./ipv6");
|
||||
Object.defineProperty(exports, "Address6", { enumerable: true, get: function () { return ipv6_1.Address6; } });
|
||||
var address_error_1 = require("./address-error");
|
||||
Object.defineProperty(exports, "AddressError", { enumerable: true, get: function () { return address_error_1.AddressError; } });
|
||||
const helpers = __importStar(require("./v6/helpers"));
|
||||
exports.v6 = { helpers };
|
||||
//# sourceMappingURL=ip-address.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ip-address.js","sourceRoot":"","sources":["../src/ip-address.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+BAAkC;AAAzB,gGAAA,QAAQ,OAAA;AACjB,+BAAkC;AAAzB,gGAAA,QAAQ,OAAA;AACjB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AAErB,sDAAwC;AAE3B,QAAA,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC","sourcesContent":["export { Address4 } from './ipv4';\nexport { Address6 } from './ipv6';\nexport { AddressError } from './address-error';\n\nimport * as helpers from './v6/helpers';\n\nexport const v6 = { helpers };\n"]}
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
import * as common from './common';
|
||||
/**
|
||||
* Represents an IPv4 address
|
||||
* @param {string} address - An IPv4 address string
|
||||
*/
|
||||
export declare class Address4 {
|
||||
address: string;
|
||||
addressMinusSuffix: string;
|
||||
groups: number;
|
||||
parsedAddress: string[];
|
||||
parsedSubnet: string;
|
||||
subnet: string;
|
||||
subnetMask: number;
|
||||
v4: boolean;
|
||||
private _binaryZeroPad?;
|
||||
constructor(address: string);
|
||||
/**
|
||||
* 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: string): boolean;
|
||||
/**
|
||||
* 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: string): 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(): string;
|
||||
/**
|
||||
* Returns true if the address is correct, false otherwise
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isCorrect: (this: Address4 | import("./ipv6").Address6) => boolean;
|
||||
/**
|
||||
* 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: string, mask: string): Address4;
|
||||
/**
|
||||
* 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: string, wildcardMask: string): Address4;
|
||||
/**
|
||||
* 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: string): Address4;
|
||||
/**
|
||||
* 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: string): Address4;
|
||||
/**
|
||||
* 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: number): Address4;
|
||||
/**
|
||||
* Return an address from in-addr.arpa form: the four octets reversed, with
|
||||
* or without the `.in-addr.arpa` suffix and root dot, in any case. Throws
|
||||
* `AddressError` unless the reversed labels form a valid IPv4 address, so
|
||||
* `fromArpa(x.reverseForm())` round-trips {@link reverseForm}.
|
||||
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
|
||||
* @returns {Adress4}
|
||||
* @example
|
||||
* var address = Address4.fromArpa('42.2.0.192.in-addr.arpa.')
|
||||
* address.correctForm(); // '192.0.2.42'
|
||||
*/
|
||||
static fromArpa(arpaFormAddress: string): Address4;
|
||||
/**
|
||||
* Converts an IPv4 address object to a hex string
|
||||
* @returns {String}
|
||||
*/
|
||||
toHex(): string;
|
||||
/**
|
||||
* 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(): number[];
|
||||
/**
|
||||
* Converts an IPv4 address object to an IPv6 address group
|
||||
* @returns {String}
|
||||
*/
|
||||
toGroup6(): string;
|
||||
/**
|
||||
* Returns the address as a `bigint`
|
||||
* @returns {bigint}
|
||||
*/
|
||||
bigInt(): bigint;
|
||||
/**
|
||||
* Helper function getting start address.
|
||||
* @returns {bigint}
|
||||
*/
|
||||
_startAddress(): bigint;
|
||||
/**
|
||||
* The first address in the range given by this address' subnet.
|
||||
* Often referred to as the Network Address.
|
||||
* @returns {Address4}
|
||||
*/
|
||||
startAddress(): Address4;
|
||||
/**
|
||||
* The first host address in the range given by this address's subnet ie
|
||||
* the first address after the Network Address
|
||||
* @returns {Address4}
|
||||
*/
|
||||
startAddressExclusive(): Address4;
|
||||
/**
|
||||
* Returns the address `n` addresses after this one (or before, when `n` is
|
||||
* negative), keeping this address's subnet mask. Throws `AddressError` when
|
||||
* the result would fall outside the IPv4 address space or `n` is not an
|
||||
* integer.
|
||||
* @param {number | bigint} n
|
||||
* @returns {Address4}
|
||||
* @example
|
||||
* new Address4('10.0.0.0/24').offset(1).correctForm(); // '10.0.0.1'
|
||||
*/
|
||||
offset(n: number | bigint): Address4;
|
||||
/**
|
||||
* Returns the network that follows this address's network: the address after
|
||||
* {@link endAddress}, with the same subnet mask. Throws `AddressError` when
|
||||
* this network is the last one in the address space.
|
||||
* @returns {Address4}
|
||||
* @example
|
||||
* new Address4('10.0.0.0/24').nextNetwork().networkForm(); // '10.0.1.0/24'
|
||||
*/
|
||||
nextNetwork(): Address4;
|
||||
private withSubnetMask;
|
||||
/**
|
||||
* Helper function getting end address.
|
||||
* @returns {bigint}
|
||||
*/
|
||||
_endAddress(): bigint;
|
||||
/**
|
||||
* The last address in the range given by this address' subnet
|
||||
* Often referred to as the Broadcast
|
||||
* @returns {Address4}
|
||||
*/
|
||||
endAddress(): Address4;
|
||||
/**
|
||||
* The last host address in the range given by this address's subnet ie
|
||||
* the last address prior to the Broadcast Address
|
||||
* @returns {Address4}
|
||||
*/
|
||||
endAddressExclusive(): Address4;
|
||||
/**
|
||||
* 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(): Address4;
|
||||
/**
|
||||
* 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(): Address4;
|
||||
/**
|
||||
* 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(): string;
|
||||
/**
|
||||
* 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: bigint): Address4;
|
||||
/**
|
||||
* Convert a byte array to an Address4 object. Throws `AddressError` unless
|
||||
* given exactly 4 integers from 0 to 255. Signed bytes are rejected, so
|
||||
* this differs from `Address6.fromByteArray`, which folds them; the two
|
||||
* contracts converge on this stricter form in the next major version.
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
static fromByteArray(bytes: Array<number>): Address4;
|
||||
/**
|
||||
* Convert an unsigned byte array to an Address4 object. Throws
|
||||
* `AddressError` unless given exactly 4 bytes, and rejects values outside
|
||||
* 0 to 255 when parsing the resulting address.
|
||||
*
|
||||
* To convert from a Node.js `Buffer`, spread it:
|
||||
* `Address4.fromUnsignedByteArray([...buf])`.
|
||||
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
|
||||
* @returns {Address4}
|
||||
*/
|
||||
static fromUnsignedByteArray(bytes: Array<number>): Address4;
|
||||
/**
|
||||
* Returns the first n bits of the address, defaulting to the
|
||||
* subnet mask
|
||||
* @returns {String}
|
||||
*/
|
||||
mask(mask?: number): string;
|
||||
/**
|
||||
* Returns the bits in the given range as a base-2 string
|
||||
* @returns {string}
|
||||
*/
|
||||
getBitsBase2(start: number, end: number): string;
|
||||
/**
|
||||
* Return the reversed in-addr.arpa form of the address, e.g.
|
||||
* `42.2.0.192.in-addr.arpa.` for `192.0.2.42`.
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
|
||||
* @returns {String}
|
||||
*/
|
||||
reverseForm(options?: common.ReverseFormOptions): string;
|
||||
/**
|
||||
* Returns true if the given address is in the subnet of the current address.
|
||||
* An `Address6` is never in the subnet of an `Address4`; convert with
|
||||
* `to4()` or `Address6.fromAddress4()` to compare across families.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isInSubnet: typeof common.isInSubnet;
|
||||
/**
|
||||
* Returns true if this address's host bits fall inside the given subnet,
|
||||
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
|
||||
* when classifying a single address, so the answer doesn't change with the
|
||||
* CIDR suffix the caller happened to write — notably when the address came
|
||||
* from untrusted input and the result backs a trust-boundary decision.
|
||||
* An `Address6` is never in the subnet of an `Address4`; convert with
|
||||
* `to4()` or `Address6.fromAddress4()` to compare across families.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isHostInSubnet: typeof common.isHostInSubnet;
|
||||
/**
|
||||
* Returns true if the given address is a multicast address
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMulticast(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* Returns true if the address is the unspecified address `0.0.0.0`.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isUnspecified(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* Returns true if the address is in one of the documentation ranges
|
||||
* `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)).
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDocumentation(): boolean;
|
||||
/**
|
||||
* Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)).
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBenchmarking(): boolean;
|
||||
/**
|
||||
* Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)),
|
||||
* which includes the limited broadcast address.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isReserved(): boolean;
|
||||
/**
|
||||
* Returns true if the address is globally reachable: not multicast, and not
|
||||
* in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/)
|
||||
* marks as not globally reachable. That covers everything the individual
|
||||
* classifiers name (private, loopback, link-local, CGNAT, unspecified,
|
||||
* broadcast, documentation, benchmarking, reserved) and the blocks they do
|
||||
* not, such as `0.0.0.0/8` and the IETF protocol assignments in
|
||||
* `192.0.0.0/24`. This is the single predicate to use where a request must
|
||||
* not reach an internal or special-purpose destination; see SECURITY.md.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isGlobal(): boolean;
|
||||
/**
|
||||
* Returns a zero-padded base-2 string representation of the address
|
||||
* @returns {string}
|
||||
*/
|
||||
binaryZeroPad(): string;
|
||||
/**
|
||||
* Groups an IPv4 address for inclusion at the end of an IPv6 address.
|
||||
*
|
||||
* Returns an HTML fragment: each half of the address is wrapped in a
|
||||
* `<span>` carrying the group classes an address-inspector UI hovers on.
|
||||
* The address content is HTML-escaped; anything you concatenate around it
|
||||
* is your responsibility.
|
||||
* @returns {String}
|
||||
*/
|
||||
groupForV6(): string;
|
||||
}
|
||||
+602
@@ -0,0 +1,602 @@
|
||||
"use strict";
|
||||
/* eslint-disable no-param-reassign */
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
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
|
||||
* @param {string} address - An IPv4 address string
|
||||
*/
|
||||
class Address4 {
|
||||
constructor(address) {
|
||||
this.addressMinusSuffix = '';
|
||||
this.groups = constants.GROUPS;
|
||||
this.parsedAddress = [];
|
||||
this.parsedSubnet = '';
|
||||
this.subnet = '/32';
|
||||
this.subnetMask = 32;
|
||||
this.v4 = true;
|
||||
/**
|
||||
* Returns true if the address is correct, false otherwise
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
this.isCorrect = isCorrect4;
|
||||
/**
|
||||
* Returns true if the given address is in the subnet of the current address.
|
||||
* An `Address6` is never in the subnet of an `Address4`; convert with
|
||||
* `to4()` or `Address6.fromAddress4()` to compare across families.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
this.isInSubnet = common.isInSubnet;
|
||||
/**
|
||||
* Returns true if this address's host bits fall inside the given subnet,
|
||||
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
|
||||
* when classifying a single address, so the answer doesn't change with the
|
||||
* CIDR suffix the caller happened to write — notably when the address came
|
||||
* from untrusted input and the result backs a trust-boundary decision.
|
||||
* An `Address6` is never in the subnet of an `Address4`; convert with
|
||||
* `to4()` or `Address6.fromAddress4()` to compare across families.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
this.isHostInSubnet = common.isHostInSubnet;
|
||||
this.address = address;
|
||||
const subnet = constants.RE_SUBNET_STRING.exec(address);
|
||||
if (subnet) {
|
||||
this.parsedSubnet = subnet[0].replace('/', '');
|
||||
this.subnetMask = parseInt(this.parsedSubnet, 10);
|
||||
this.subnet = `/${this.subnetMask}`;
|
||||
if (this.subnetMask < 0 || this.subnetMask > constants.BITS) {
|
||||
throw new address_error_1.AddressError('Invalid subnet mask.');
|
||||
}
|
||||
address = address.replace(constants.RE_SUBNET_STRING, '');
|
||||
}
|
||||
// Four three-digit octets and three dots: the longest well-formed address
|
||||
// is 15 characters. Longer input is rejected before parsing, as Address6
|
||||
// does at its own limit.
|
||||
const longest = constants.GROUPS * 4 - 1;
|
||||
if (address.length > longest) {
|
||||
throw new address_error_1.AddressError(`IPv4 addresses are at most ${longest} characters.`);
|
||||
}
|
||||
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
|
||||
new Address4(address);
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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('.');
|
||||
// Checked before the general match so the error names the actual problem.
|
||||
// Address6 rejects the same notation on its v4-in-v6 path.
|
||||
if (groups.some((group) => /^0\d/.test(group))) {
|
||||
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.");
|
||||
}
|
||||
if (!address.match(constants.RE_ADDRESS)) {
|
||||
throw new address_error_1.AddressError('Invalid IPv4 address.');
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
/**
|
||||
* 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('.');
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
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 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 = [];
|
||||
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. 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) {
|
||||
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: the four octets reversed, with
|
||||
* or without the `.in-addr.arpa` suffix and root dot, in any case. Throws
|
||||
* `AddressError` unless the reversed labels form a valid IPv4 address, so
|
||||
* `fromArpa(x.reverseForm())` round-trips {@link reverseForm}.
|
||||
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
|
||||
* @returns {Adress4}
|
||||
* @example
|
||||
* var address = Address4.fromArpa('42.2.0.192.in-addr.arpa.')
|
||||
* address.correctForm(); // '192.0.2.42'
|
||||
*/
|
||||
static fromArpa(arpaFormAddress) {
|
||||
// A 15-character address, a "/32" prefix length and ".in-addr.arpa.": the
|
||||
// longest name is 32 characters. Longer input is rejected before its
|
||||
// labels are split, as the constructor does at its own limit.
|
||||
const longest = constants.GROUPS * 4 - 1 + '/32'.length + '.in-addr.arpa.'.length;
|
||||
if (arpaFormAddress.length > longest) {
|
||||
throw new address_error_1.AddressError(`in-addr.arpa names are at most ${longest} characters.`);
|
||||
}
|
||||
// remove an ending ".in-addr.arpa", in any case and with or without the
|
||||
// root dot, as Address6.fromArpa does for ".ip6.arpa"
|
||||
const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.?$/i, '');
|
||||
const address = leader.split('.').reverse().join('.');
|
||||
return new Address4(address);
|
||||
}
|
||||
/**
|
||||
* Converts an IPv4 address object to a hex string
|
||||
* @returns {String}
|
||||
*/
|
||||
toHex() {
|
||||
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
|
||||
}
|
||||
/**
|
||||
* 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() {
|
||||
return this.parsedAddress.map((part) => parseInt(part, 10));
|
||||
}
|
||||
/**
|
||||
* Converts an IPv4 address object to an IPv6 address group
|
||||
* @returns {String}
|
||||
*/
|
||||
toGroup6() {
|
||||
const output = [];
|
||||
let i;
|
||||
for (i = 0; i < constants.GROUPS; i += 2) {
|
||||
output.push(`${common.stringToPaddedHex(this.parsedAddress[i])}${common.stringToPaddedHex(this.parsedAddress[i + 1])}`);
|
||||
}
|
||||
return output.join(':');
|
||||
}
|
||||
/**
|
||||
* Returns the address as a `bigint`
|
||||
* @returns {bigint}
|
||||
*/
|
||||
bigInt() {
|
||||
return BigInt(`0x${this.parsedAddress.map((n) => common.stringToPaddedHex(n)).join('')}`);
|
||||
}
|
||||
/**
|
||||
* Helper function getting start address.
|
||||
* @returns {bigint}
|
||||
*/
|
||||
_startAddress() {
|
||||
return BigInt(`0b${this.mask() + '0'.repeat(constants.BITS - this.subnetMask)}`);
|
||||
}
|
||||
/**
|
||||
* The first address in the range given by this address' subnet.
|
||||
* Often referred to as the Network Address.
|
||||
* @returns {Address4}
|
||||
*/
|
||||
startAddress() {
|
||||
return Address4.fromBigInt(this._startAddress());
|
||||
}
|
||||
/**
|
||||
* The first host address in the range given by this address's subnet ie
|
||||
* the first address after the Network Address
|
||||
* @returns {Address4}
|
||||
*/
|
||||
startAddressExclusive() {
|
||||
const adjust = BigInt('1');
|
||||
return Address4.fromBigInt(this._startAddress() + adjust);
|
||||
}
|
||||
/**
|
||||
* Returns the address `n` addresses after this one (or before, when `n` is
|
||||
* negative), keeping this address's subnet mask. Throws `AddressError` when
|
||||
* the result would fall outside the IPv4 address space or `n` is not an
|
||||
* integer.
|
||||
* @param {number | bigint} n
|
||||
* @returns {Address4}
|
||||
* @example
|
||||
* new Address4('10.0.0.0/24').offset(1).correctForm(); // '10.0.0.1'
|
||||
*/
|
||||
offset(n) {
|
||||
return Address4.fromBigInt(common.offsetBigInt(this.bigInt(), n, constants.BITS, 'IPv4')).withSubnetMask(this.subnetMask);
|
||||
}
|
||||
/**
|
||||
* Returns the network that follows this address's network: the address after
|
||||
* {@link endAddress}, with the same subnet mask. Throws `AddressError` when
|
||||
* this network is the last one in the address space.
|
||||
* @returns {Address4}
|
||||
* @example
|
||||
* new Address4('10.0.0.0/24').nextNetwork().networkForm(); // '10.0.1.0/24'
|
||||
*/
|
||||
nextNetwork() {
|
||||
return Address4.fromBigInt(common.offsetBigInt(this._endAddress(), 1, constants.BITS, 'IPv4')).withSubnetMask(this.subnetMask);
|
||||
}
|
||||
withSubnetMask(subnetMask) {
|
||||
return new Address4(`${this.correctForm()}/${subnetMask}`);
|
||||
}
|
||||
/**
|
||||
* Helper function getting end address.
|
||||
* @returns {bigint}
|
||||
*/
|
||||
_endAddress() {
|
||||
return BigInt(`0b${this.mask() + '1'.repeat(constants.BITS - this.subnetMask)}`);
|
||||
}
|
||||
/**
|
||||
* The last address in the range given by this address' subnet
|
||||
* Often referred to as the Broadcast
|
||||
* @returns {Address4}
|
||||
*/
|
||||
endAddress() {
|
||||
return Address4.fromBigInt(this._endAddress());
|
||||
}
|
||||
/**
|
||||
* The last host address in the range given by this address's subnet ie
|
||||
* the last address prior to the Broadcast Address
|
||||
* @returns {Address4}
|
||||
*/
|
||||
endAddressExclusive() {
|
||||
const adjust = BigInt('1');
|
||||
return Address4.fromBigInt(this._endAddress() - adjust);
|
||||
}
|
||||
/**
|
||||
* 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) {
|
||||
if (bigInt < BigInt(0) || bigInt > BigInt(0xffffffff)) {
|
||||
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. Throws `AddressError` unless
|
||||
* given exactly 4 integers from 0 to 255. Signed bytes are rejected, so
|
||||
* this differs from `Address6.fromByteArray`, which folds them; the two
|
||||
* contracts converge on this stricter form in the next major version.
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
static fromByteArray(bytes) {
|
||||
common.assertByteArray(bytes, 4, 'IPv4', 0);
|
||||
return this.fromUnsignedByteArray(bytes);
|
||||
}
|
||||
/**
|
||||
* Convert an unsigned byte array to an Address4 object. Throws
|
||||
* `AddressError` unless given exactly 4 bytes, and rejects values outside
|
||||
* 0 to 255 when parsing the resulting address.
|
||||
*
|
||||
* To convert from a Node.js `Buffer`, spread it:
|
||||
* `Address4.fromUnsignedByteArray([...buf])`.
|
||||
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
|
||||
* @returns {Address4}
|
||||
*/
|
||||
static fromUnsignedByteArray(bytes) {
|
||||
if (bytes.length !== 4) {
|
||||
throw new address_error_1.AddressError('IPv4 addresses require exactly 4 bytes');
|
||||
}
|
||||
const address = bytes.join('.');
|
||||
return new Address4(address);
|
||||
}
|
||||
/**
|
||||
* Returns the first n bits of the address, defaulting to the
|
||||
* subnet mask
|
||||
* @returns {String}
|
||||
*/
|
||||
mask(mask) {
|
||||
if (mask === undefined) {
|
||||
mask = this.subnetMask;
|
||||
}
|
||||
return this.getBitsBase2(0, mask);
|
||||
}
|
||||
/**
|
||||
* Returns the bits in the given range as a base-2 string
|
||||
* @returns {string}
|
||||
*/
|
||||
getBitsBase2(start, end) {
|
||||
return this.binaryZeroPad().slice(start, end);
|
||||
}
|
||||
/**
|
||||
* Return the reversed in-addr.arpa form of the address, e.g.
|
||||
* `42.2.0.192.in-addr.arpa.` for `192.0.2.42`.
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
|
||||
* @returns {String}
|
||||
*/
|
||||
reverseForm(options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
const reversed = this.correctForm().split('.').reverse().join('.');
|
||||
if (options.omitSuffix) {
|
||||
return reversed;
|
||||
}
|
||||
return `${reversed}.in-addr.arpa.`;
|
||||
}
|
||||
/**
|
||||
* Returns true if the given address is a multicast address
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMulticast() {
|
||||
return this.isHostInSubnet(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.isHostInSubnet(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.isHostInSubnet(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.isHostInSubnet(LINK_LOCAL_V4);
|
||||
}
|
||||
/**
|
||||
* Returns true if the address is the unspecified address `0.0.0.0`.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isUnspecified() {
|
||||
return this.isHostInSubnet(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.isHostInSubnet(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.isHostInSubnet(CGNAT_V4);
|
||||
}
|
||||
/**
|
||||
* Returns true if the address is in one of the documentation ranges
|
||||
* `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)).
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDocumentation() {
|
||||
return DOCUMENTATION_V4.some((subnet) => this.isHostInSubnet(subnet));
|
||||
}
|
||||
/**
|
||||
* Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)).
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBenchmarking() {
|
||||
return this.isHostInSubnet(BENCHMARKING_V4);
|
||||
}
|
||||
/**
|
||||
* Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)),
|
||||
* which includes the limited broadcast address.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isReserved() {
|
||||
return this.isHostInSubnet(RESERVED_V4);
|
||||
}
|
||||
/**
|
||||
* Returns true if the address is globally reachable: not multicast, and not
|
||||
* in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/)
|
||||
* marks as not globally reachable. That covers everything the individual
|
||||
* classifiers name (private, loopback, link-local, CGNAT, unspecified,
|
||||
* broadcast, documentation, benchmarking, reserved) and the blocks they do
|
||||
* not, such as `0.0.0.0/8` and the IETF protocol assignments in
|
||||
* `192.0.0.0/24`. This is the single predicate to use where a request must
|
||||
* not reach an internal or special-purpose destination; see SECURITY.md.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isGlobal() {
|
||||
return !this.isMulticast() && common.isGloballyReachable.call(this, SPECIAL_PURPOSE_V4);
|
||||
}
|
||||
/**
|
||||
* Returns a zero-padded base-2 string representation of the address
|
||||
* @returns {string}
|
||||
*/
|
||||
binaryZeroPad() {
|
||||
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.
|
||||
*
|
||||
* Returns an HTML fragment: each half of the address is wrapped in a
|
||||
* `<span>` carrying the group classes an address-inspector UI hovers on.
|
||||
* The address content is HTML-escaped; anything you concatenate around it
|
||||
* is your responsibility.
|
||||
* @returns {String}
|
||||
*/
|
||||
groupForV6() {
|
||||
const segments = this.parsedAddress;
|
||||
return this.correctForm().replace(constants.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments
|
||||
.slice(0, 2)
|
||||
.join('.')}</span>.<span class="hover-group group-v4 group-7">${segments
|
||||
.slice(2, 4)
|
||||
.join('.')}</span>`);
|
||||
}
|
||||
}
|
||||
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');
|
||||
const DOCUMENTATION_V4 = [
|
||||
new Address4('192.0.2.0/24'),
|
||||
new Address4('198.51.100.0/24'),
|
||||
new Address4('203.0.113.0/24'),
|
||||
];
|
||||
const BENCHMARKING_V4 = new Address4('198.18.0.0/15');
|
||||
const RESERVED_V4 = new Address4('240.0.0.0/4');
|
||||
const SPECIAL_PURPOSE_V4 = constants.SPECIAL_PURPOSE.map(([cidr, , reachable]) => ({
|
||||
subnet: new Address4(cidr),
|
||||
reachable,
|
||||
}));
|
||||
//# sourceMappingURL=ipv4.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+634
@@ -0,0 +1,634 @@
|
||||
import * as common from './common';
|
||||
import { Address4 } from './ipv4';
|
||||
interface SixToFourProperties {
|
||||
prefix: string;
|
||||
gateway: string;
|
||||
}
|
||||
interface TeredoProperties {
|
||||
prefix: string;
|
||||
server4: string;
|
||||
client4: string;
|
||||
flags: string;
|
||||
coneNat: boolean;
|
||||
microsoft: {
|
||||
reserved: boolean;
|
||||
universalLocal: boolean;
|
||||
groupIndividual: boolean;
|
||||
nonce: string;
|
||||
};
|
||||
udpPort: string;
|
||||
}
|
||||
/**
|
||||
* Represents an IPv6 address
|
||||
* @param {string} address - An IPv6 address string
|
||||
* @param {number} [groups=8] - How many octets to parse
|
||||
* @example
|
||||
* var address = new Address6('2001::/32');
|
||||
*/
|
||||
export declare class Address6 {
|
||||
address4?: Address4;
|
||||
address: string;
|
||||
addressMinusSuffix: string;
|
||||
elidedGroups?: number;
|
||||
elisionBegin?: number;
|
||||
elisionEnd?: number;
|
||||
groups: number;
|
||||
parsedAddress4?: string;
|
||||
parsedAddress: string[];
|
||||
parsedSubnet: string;
|
||||
subnet: string;
|
||||
subnetMask: number;
|
||||
v4: boolean;
|
||||
zone: string;
|
||||
private _binaryZeroPad?;
|
||||
constructor(address: string, optionalGroups?: number);
|
||||
/**
|
||||
* 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: string): boolean;
|
||||
/**
|
||||
* 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
|
||||
* var bigInt = BigInt('1000000000000');
|
||||
* var address = Address6.fromBigInt(bigInt);
|
||||
* address.correctForm(); // '::e8:d4a5:1000'
|
||||
*/
|
||||
static fromBigInt(bigInt: bigint): Address6;
|
||||
/**
|
||||
* 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::'
|
||||
* addressAndPort.port; // 8080
|
||||
*/
|
||||
static fromURL(url: string): {
|
||||
error: string;
|
||||
address: null;
|
||||
port: null;
|
||||
} | {
|
||||
address: Address6;
|
||||
port: number | null;
|
||||
error?: undefined;
|
||||
};
|
||||
/**
|
||||
* 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: string, mask: string): Address6;
|
||||
/**
|
||||
* 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: string, wildcardMask: string): Address6;
|
||||
/**
|
||||
* 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: string): Address6;
|
||||
/**
|
||||
* Create an IPv6-mapped address given an IPv4 address
|
||||
* @param {string} address - An IPv4 address string
|
||||
* @returns {Address6}
|
||||
* @example
|
||||
* var address = Address6.fromAddress4('192.168.0.1');
|
||||
* address.correctForm(); // '::ffff:c0a8:1'
|
||||
* address.to4in6(); // '::ffff:192.168.0.1'
|
||||
*/
|
||||
static fromAddress4(address: string): Address6;
|
||||
/**
|
||||
* Return an address from ip6.arpa form. A full 32-nibble name gives a /128
|
||||
* address; a shorter name, as used for a delegated reverse zone, gives the
|
||||
* network it covers, with a subnet mask of four bits per nibble, so
|
||||
* `fromArpa(x.reverseForm())` round-trips {@link reverseForm} for any prefix.
|
||||
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
|
||||
* @returns {Adress6}
|
||||
* @example
|
||||
* var address = Address6.fromArpa(e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.)
|
||||
* address.correctForm(); // '2001:0:ce49:7601:e866:efff:62c3:fffe'
|
||||
* Address6.fromArpa('8.b.d.0.1.0.0.2.ip6.arpa.').networkForm(); // '2001:db8::/32'
|
||||
*/
|
||||
static fromArpa(arpaFormAddress: string): Address6;
|
||||
/**
|
||||
* Return the Microsoft UNC transcription of the address
|
||||
* @returns {String} the Microsoft UNC transcription of the address
|
||||
*/
|
||||
microsoftTranscription(): string;
|
||||
/**
|
||||
* Return the first n bits of the address, defaulting to the subnet mask
|
||||
* @param {number} [mask=subnet] - the number of bits to mask
|
||||
* @returns {String} the first n bits of the address as a string
|
||||
*/
|
||||
mask(mask?: number): string;
|
||||
/**
|
||||
* Return the number of possible subnets of a given size in the address
|
||||
* @param {number} [subnetSize=128] - the subnet size
|
||||
* @returns {String}
|
||||
*/
|
||||
possibleSubnets(subnetSize?: number): string;
|
||||
/**
|
||||
* Helper function getting start address.
|
||||
* @returns {bigint}
|
||||
*/
|
||||
_startAddress(): bigint;
|
||||
/**
|
||||
* The first address in the range given by this address' subnet
|
||||
* Often referred to as the Network Address.
|
||||
* @returns {Address6}
|
||||
*/
|
||||
startAddress(): Address6;
|
||||
/**
|
||||
* The first host address in the range given by this address's subnet ie
|
||||
* the first address after the Network Address
|
||||
* @returns {Address6}
|
||||
*/
|
||||
startAddressExclusive(): Address6;
|
||||
/**
|
||||
* Helper function getting end address.
|
||||
* @returns {bigint}
|
||||
*/
|
||||
_endAddress(): bigint;
|
||||
/**
|
||||
* The last address in the range given by this address's subnet. IPv6 has
|
||||
* no broadcast address, so this is an ordinary assignable address (in a
|
||||
* 64-bit-interface-identifier subnet it falls inside the reserved
|
||||
* subnet-anycast block of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526)).
|
||||
* @returns {Address6}
|
||||
*/
|
||||
endAddress(): Address6;
|
||||
/**
|
||||
* The address one before {@link endAddress}. This is the IPv6 counterpart
|
||||
* of the IPv4 method that skips the broadcast address; IPv6 has no broadcast,
|
||||
* so it drops exactly one address and does not model the 128 reserved
|
||||
* subnet-anycast identifiers of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526).
|
||||
* @returns {Address6}
|
||||
*/
|
||||
endAddressExclusive(): Address6;
|
||||
/**
|
||||
* Returns the address `n` addresses after this one (or before, when `n` is
|
||||
* negative), keeping this address's subnet mask. Throws `AddressError` when
|
||||
* the result would fall outside the IPv6 address space or `n` is not an
|
||||
* integer.
|
||||
* @param {number | bigint} n
|
||||
* @returns {Address6}
|
||||
* @example
|
||||
* new Address6('2001:db8::/64').offset(1).correctForm(); // '2001:db8::1'
|
||||
*/
|
||||
offset(n: number | bigint): Address6;
|
||||
/**
|
||||
* Returns the network that follows this address's network: the address after
|
||||
* {@link endAddress}, with the same subnet mask. Throws `AddressError` when
|
||||
* this network is the last one in the address space.
|
||||
* @returns {Address6}
|
||||
* @example
|
||||
* new Address6('2001:db8::/64').nextNetwork().networkForm(); // '2001:db8:0:1::/64'
|
||||
*/
|
||||
nextNetwork(): Address6;
|
||||
private withSubnetMask;
|
||||
/**
|
||||
* 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(): Address6;
|
||||
/**
|
||||
* 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(): Address6;
|
||||
/**
|
||||
* 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(): string;
|
||||
/**
|
||||
* 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(): string;
|
||||
/**
|
||||
* Return the type of the address
|
||||
* @returns {String}
|
||||
*/
|
||||
getType(): string;
|
||||
/**
|
||||
* Return the bits in the given range as a BigInt
|
||||
* @returns {bigint}
|
||||
*/
|
||||
getBits(start: number, end: number): bigint;
|
||||
/**
|
||||
* Return the bits in the given range as a base-2 string
|
||||
* @returns {String}
|
||||
*/
|
||||
getBitsBase2(start: number, end: number): string;
|
||||
/**
|
||||
* Return the bits in the given range as a base-16 string
|
||||
* @returns {String}
|
||||
*/
|
||||
getBitsBase16(start: number, end: number): string;
|
||||
/**
|
||||
* Return the bits that are set past the subnet mask length
|
||||
* @returns {String}
|
||||
*/
|
||||
getBitsPastSubnet(): string;
|
||||
/**
|
||||
* Return the reversed ip6.arpa form of the address
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
|
||||
* @returns {String}
|
||||
*/
|
||||
reverseForm(options?: common.ReverseFormOptions): 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(): string;
|
||||
/**
|
||||
* Return a zero-padded base-2 string representation of the address
|
||||
* @returns {String}
|
||||
* @example
|
||||
* var address = new Address6('2001:4860:4001:803::1011');
|
||||
* address.binaryZeroPad();
|
||||
* // '0010000000000001010010000110000001000000000000010000100000000011
|
||||
* // 0000000000000000000000000000000000000000000000000001000000010001'
|
||||
*/
|
||||
binaryZeroPad(): string;
|
||||
/**
|
||||
* 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()`.
|
||||
*/
|
||||
parse4in6(address: string): string;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
parse(address: string): 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(): string;
|
||||
/**
|
||||
* Return the decimal form of the address
|
||||
* @returns {String}
|
||||
*/
|
||||
decimal(): string;
|
||||
/**
|
||||
* Return the address as a BigInt
|
||||
* @returns {bigint}
|
||||
*/
|
||||
bigInt(): bigint;
|
||||
/**
|
||||
* Return the last two groups of this address as an IPv4 address string.
|
||||
* If this address carries a CIDR prefix that covers the trailing 32 bits
|
||||
* (i.e. `subnetMask >= 96`), the resulting `Address4` inherits the
|
||||
* corresponding v4 prefix (`subnetMask - 96`); otherwise it defaults to
|
||||
* `/32`.
|
||||
* @returns {Address4}
|
||||
* @example
|
||||
* var address = new Address6('2001:4860:4001::1825:bf11');
|
||||
* address.to4().correctForm(); // '24.37.191.17'
|
||||
*/
|
||||
to4(): Address4;
|
||||
/**
|
||||
* Return the v4-in-v6 form of the address
|
||||
* @returns {String}
|
||||
*/
|
||||
to4in6(): string;
|
||||
/**
|
||||
* 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(): TeredoProperties;
|
||||
/**
|
||||
* 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(): SixToFourProperties;
|
||||
/**
|
||||
* Return a v6 6to4 address from a v6 v4inv6 address
|
||||
* @returns {Address6}
|
||||
*/
|
||||
to6to4(): Address6 | null;
|
||||
/**
|
||||
* 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: string, prefix?: string): Address6;
|
||||
/**
|
||||
* 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?: string): Address4 | null;
|
||||
/**
|
||||
* Return a byte array.
|
||||
*
|
||||
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
|
||||
* @returns {Array}
|
||||
*/
|
||||
toByteArray(): number[];
|
||||
/**
|
||||
* Return an unsigned byte array.
|
||||
*
|
||||
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
|
||||
* @returns {Array}
|
||||
*/
|
||||
toUnsignedByteArray(): number[];
|
||||
/**
|
||||
* Convert a byte array to an Address6 object.
|
||||
*
|
||||
* Accepts unsigned bytes (0 to 255) or signed bytes (-128 to 127, as an
|
||||
* `Int8Array` or a Java `byte[]` holds them), folding signed values to their
|
||||
* unsigned equivalent. Throws `AddressError` unless given exactly 16
|
||||
* integers from -128 to 255.
|
||||
*
|
||||
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
|
||||
* @returns {Address6}
|
||||
*/
|
||||
static fromByteArray(bytes: Array<number>): Address6;
|
||||
/**
|
||||
* Convert an unsigned byte array to an Address6 object.
|
||||
*
|
||||
* Throws `AddressError` unless given exactly 16 integers from 0 to 255.
|
||||
*
|
||||
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
|
||||
* @returns {Address6}
|
||||
*/
|
||||
static fromUnsignedByteArray(bytes: Array<number>): Address6;
|
||||
/**
|
||||
* Returns true if the given address is in the subnet of the current address.
|
||||
* An `Address4` is never in the subnet of an `Address6`; convert with
|
||||
* `Address6.fromAddress4()` or `to4()` to compare across families.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isInSubnet: typeof common.isInSubnet;
|
||||
/**
|
||||
* Returns true if this address's host bits fall inside the given subnet,
|
||||
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
|
||||
* when classifying a single address, so the answer doesn't change with the
|
||||
* CIDR suffix the caller happened to write — notably when the address came
|
||||
* from untrusted input and the result backs a trust-boundary decision.
|
||||
* An `Address4` is never in the subnet of an `Address6`; convert with
|
||||
* `Address6.fromAddress4()` or `to4()` to compare across families.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isHostInSubnet: typeof common.isHostInSubnet;
|
||||
/**
|
||||
* Returns true if the address is correct, false otherwise
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isCorrect: (this: Address4 | Address6) => boolean;
|
||||
/**
|
||||
* Returns true if the address is in the canonical form, false otherwise
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isCanonical(): boolean;
|
||||
/**
|
||||
* Returns true if the address is a link-local unicast address in `fe80::/10`
|
||||
* ([RFC 4291 §2.4](https://datatracker.ietf.org/doc/html/rfc4291#section-2.4))
|
||||
* or an IPv4-mapped / NAT64 address whose embedded IPv4 address is link-local
|
||||
* (`169.254.0.0/16`, e.g. `::ffff:169.254.169.254`), false otherwise.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLinkLocal(): boolean;
|
||||
/**
|
||||
* Returns true if the address is a multicast address, false otherwise
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMulticast(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* If this address embeds a routable IPv4 address — i.e. it is IPv4-mapped
|
||||
* (`::ffff:0:0/96`) or sits in the NAT64 well-known prefix (`64:ff9b::/96`,
|
||||
* [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052)) — return that
|
||||
* embedded address as an {@link Address4}; otherwise return null.
|
||||
*
|
||||
* The special-property checks (`isLoopback`, `isLinkLocal`, `isMulticast`,
|
||||
* `isUnspecified`, `isPrivate`, `isCGNAT`, `isBroadcast`) call this first and
|
||||
* delegate to the embedded {@link Address4} when present, so a literal such as
|
||||
* `::ffff:127.0.0.1` is classified by what it actually reaches (loopback)
|
||||
* rather than by its IPv6 wrapper (which `getType()` reports as IPv4-mapped).
|
||||
* This matters wherever the checks back a trust-boundary decision (e.g. an
|
||||
* SSRF allow/deny filter): without normalization, `::ffff:10.0.0.1`,
|
||||
* `::ffff:169.254.169.254`, `64:ff9b::7f00:1`, etc. would all read as
|
||||
* non-internal.
|
||||
* @returns {Address4 | null}
|
||||
*/
|
||||
embeddedIPv4(): Address4 | null;
|
||||
/**
|
||||
* Returns true if the address is a Teredo address, false otherwise
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isTeredo(): boolean;
|
||||
/**
|
||||
* Returns true if the address is a 6to4 address, false otherwise
|
||||
* @returns {boolean}
|
||||
*/
|
||||
is6to4(): boolean;
|
||||
/**
|
||||
* Returns true if the address is a loopback address, false otherwise
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLoopback(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* Returns true if the address is private, i.e. a Unique Local Address in
|
||||
* `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)), an
|
||||
* address in the NAT64 local-use range `64:ff9b:1::/48`
|
||||
* ([RFC 8215](https://datatracker.ietf.org/doc/html/rfc8215)), or an
|
||||
* IPv4-mapped / NAT64 well-known address whose embedded IPv4 address is in
|
||||
* one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918)
|
||||
* private ranges (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to
|
||||
* {@link Address4.isPrivate}; use it instead of {@link isULA} when you need to
|
||||
* catch mapped RFC 1918 addresses as well as native ULAs.
|
||||
*
|
||||
* The local-use NAT64 range is reported private as a whole rather than by
|
||||
* its embedded IPv4 address: an operator may carve a prefix of any RFC 6052
|
||||
* length out of `64:ff9b:1::/48`, so the same bits decode to different IPv4
|
||||
* addresses under different deployments and no single decoding is correct.
|
||||
* Use {@link toAddress4Nat64} with the deployment's prefix to decode one.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPrivate(): boolean;
|
||||
/**
|
||||
* Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
|
||||
* IPv4 address is in the carrier-grade NAT range `100.64.0.0/10`
|
||||
* ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)), false
|
||||
* otherwise. There is no native IPv6 CGNAT range, so this only ever returns
|
||||
* true for an embedded IPv4 address (e.g. `::ffff:100.64.0.1`).
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isCGNAT(): boolean;
|
||||
/**
|
||||
* Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
|
||||
* IPv4 address is the limited broadcast address `255.255.255.255`
|
||||
* ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)), false otherwise.
|
||||
* There is no IPv6 broadcast, so this only ever returns true for an embedded
|
||||
* IPv4 address (e.g. `::ffff:255.255.255.255`).
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBroadcast(): boolean;
|
||||
/**
|
||||
* Returns true if the address is the unspecified address `::`.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isUnspecified(): boolean;
|
||||
/**
|
||||
* 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(): boolean;
|
||||
/**
|
||||
* Returns true if the address is in the benchmarking range `2001:2::/48`
|
||||
* ([RFC 5180](https://datatracker.ietf.org/doc/html/rfc5180)) or is an
|
||||
* IPv4-mapped / NAT64 address whose embedded IPv4 address is in
|
||||
* `198.18.0.0/15`, false otherwise.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBenchmarking(): boolean;
|
||||
/**
|
||||
* Returns true if the address is globally reachable: inside the global
|
||||
* unicast allocation `2000::/3` (the only range the [IANA IPv6 Address Space
|
||||
* Registry](https://www.iana.org/assignments/ipv6-address-space/) assigns
|
||||
* for global unicast; everything else is reserved, ULA, link-local, or
|
||||
* multicast) and not in any block the [IANA IPv6 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv6-special-registry/)
|
||||
* marks as not globally reachable. An IPv4-mapped or NAT64 well-known
|
||||
* address answers for its embedded IPv4 address, so `::ffff:10.0.0.1` and
|
||||
* `64:ff9b::7f00:1` are not global. Teredo (`2001::/32`) and 6to4
|
||||
* (`2002::/16`) are not global either: the registry lists them as N/A and a
|
||||
* packet to one needs a relay.
|
||||
*
|
||||
* This covers everything the individual classifiers name and the blocks they
|
||||
* do not: the discard-only prefix `100::/64`, the IETF protocol assignments
|
||||
* in `2001::/23`, the deprecated site-local `fec0::/10` and IPv4-compatible
|
||||
* `::/96` ranges, and unallocated space such as `4000::/3`. It is the single
|
||||
* predicate to use where a request must not reach an internal or
|
||||
* special-purpose destination; see SECURITY.md.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isGlobal(): boolean;
|
||||
/**
|
||||
* 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?: number | string): string;
|
||||
/**
|
||||
* 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?: {
|
||||
className?: string;
|
||||
prefix?: string;
|
||||
v4?: boolean;
|
||||
}): string;
|
||||
/**
|
||||
* Groups an address.
|
||||
*
|
||||
* Returns an HTML fragment: each group is wrapped in a `<span>` carrying
|
||||
* the group classes an address-inspector UI hovers on. The address content
|
||||
* is HTML-escaped; anything you concatenate around it is your
|
||||
* responsibility.
|
||||
* @returns {String}
|
||||
*/
|
||||
group(): string;
|
||||
/**
|
||||
* Generate a regular expression string that can be used to find or validate
|
||||
* all variations of this address
|
||||
* @param {boolean} substringSearch
|
||||
* @returns {string}
|
||||
*/
|
||||
regularExpressionString(this: Address6, substringSearch?: boolean): string;
|
||||
/**
|
||||
* Generate a regular expression that can be used to find or validate all
|
||||
* variations of this address.
|
||||
* @param {boolean} substringSearch
|
||||
* @returns {RegExp}
|
||||
*/
|
||||
regularExpression(this: Address6, substringSearch?: boolean): RegExp;
|
||||
}
|
||||
export {};
|
||||
+1461
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+16
@@ -0,0 +1,16 @@
|
||||
export declare const BITS = 32;
|
||||
export declare const GROUPS = 4;
|
||||
export declare const RE_ADDRESS: RegExp;
|
||||
export declare const RE_SUBNET_STRING: RegExp;
|
||||
/**
|
||||
* The IANA IPv4 Special-Purpose Address Registry
|
||||
* (https://www.iana.org/assignments/iana-ipv4-special-registry/), one entry
|
||||
* per block: `[cidr, name, globallyReachable]`. A `null` reachability means
|
||||
* the registry leaves the column blank and the block inherits the answer of
|
||||
* the block containing it (or is global when nothing contains it).
|
||||
*
|
||||
* `Address4.isGlobal()` answers from the most specific entry containing the
|
||||
* address. `test/data/iana-corpus.json` is generated from the registry's CSV
|
||||
* and pins this table to it.
|
||||
*/
|
||||
export declare const SPECIAL_PURPOSE: ReadonlyArray<readonly [string, string, boolean | null]>;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SPECIAL_PURPOSE = exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
|
||||
exports.BITS = 32;
|
||||
exports.GROUPS = 4;
|
||||
// Each octet is 0-255 written without a leading zero. A leading zero is
|
||||
// octal to the WHATWG URL parser, inet_aton, and getaddrinfo, but decimal to
|
||||
// parseInt(part, 10), so accepting the notation would make this library
|
||||
// disagree with the network stack about which host a string names.
|
||||
exports.RE_ADDRESS = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/g;
|
||||
exports.RE_SUBNET_STRING = /\/\d{1,2}$/;
|
||||
/**
|
||||
* The IANA IPv4 Special-Purpose Address Registry
|
||||
* (https://www.iana.org/assignments/iana-ipv4-special-registry/), one entry
|
||||
* per block: `[cidr, name, globallyReachable]`. A `null` reachability means
|
||||
* the registry leaves the column blank and the block inherits the answer of
|
||||
* the block containing it (or is global when nothing contains it).
|
||||
*
|
||||
* `Address4.isGlobal()` answers from the most specific entry containing the
|
||||
* address. `test/data/iana-corpus.json` is generated from the registry's CSV
|
||||
* and pins this table to it.
|
||||
*/
|
||||
exports.SPECIAL_PURPOSE = [
|
||||
['0.0.0.0/8', 'This network', false],
|
||||
['0.0.0.0/32', 'This host on this network', false],
|
||||
['10.0.0.0/8', 'Private-Use', false],
|
||||
['100.64.0.0/10', 'Shared Address Space', false],
|
||||
['127.0.0.0/8', 'Loopback', false],
|
||||
['169.254.0.0/16', 'Link Local', false],
|
||||
['172.16.0.0/12', 'Private-Use', false],
|
||||
['192.0.0.0/24', 'IETF Protocol Assignments', false],
|
||||
['192.0.0.0/29', 'IPv4 Service Continuity Prefix', false],
|
||||
['192.0.0.8/32', 'IPv4 dummy address', false],
|
||||
['192.0.0.9/32', 'Port Control Protocol Anycast', true],
|
||||
['192.0.0.10/32', 'Traversal Using Relays around NAT Anycast', true],
|
||||
['192.0.0.170/32', 'NAT64/DNS64 Discovery', false],
|
||||
['192.0.0.171/32', 'NAT64/DNS64 Discovery', false],
|
||||
['192.0.2.0/24', 'Documentation (TEST-NET-1)', false],
|
||||
['192.31.196.0/24', 'AS112-v4', true],
|
||||
['192.52.193.0/24', 'AMT', true],
|
||||
['192.88.99.0/24', 'Deprecated (6to4 Relay Anycast)', null],
|
||||
['192.88.99.2/32', '6a44-relay anycast address', false],
|
||||
['192.168.0.0/16', 'Private-Use', false],
|
||||
['192.175.48.0/24', 'Direct Delegation AS112 Service', true],
|
||||
['198.18.0.0/15', 'Benchmarking', false],
|
||||
['198.51.100.0/24', 'Documentation (TEST-NET-2)', false],
|
||||
['203.0.113.0/24', 'Documentation (TEST-NET-3)', false],
|
||||
['240.0.0.0/4', 'Reserved', false],
|
||||
['255.255.255.255/32', 'Limited Broadcast', false],
|
||||
];
|
||||
//# sourceMappingURL=constants.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/v4/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,IAAI,GAAG,EAAE,CAAC;AACV,QAAA,MAAM,GAAG,CAAC,CAAC;AAExB,wEAAwE;AACxE,6EAA6E;AAC7E,wEAAwE;AACxE,mEAAmE;AACtD,QAAA,UAAU,GACrB,+LAA+L,CAAC;AAErL,QAAA,gBAAgB,GAAG,YAAY,CAAC;AAE7C;;;;;;;;;;GAUG;AACU,QAAA,eAAe,GAA6D;IACvF,CAAC,WAAW,EAAE,cAAc,EAAE,KAAK,CAAC;IACpC,CAAC,YAAY,EAAE,2BAA2B,EAAE,KAAK,CAAC;IAClD,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK,CAAC;IACpC,CAAC,eAAe,EAAE,sBAAsB,EAAE,KAAK,CAAC;IAChD,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC;IAClC,CAAC,gBAAgB,EAAE,YAAY,EAAE,KAAK,CAAC;IACvC,CAAC,eAAe,EAAE,aAAa,EAAE,KAAK,CAAC;IACvC,CAAC,cAAc,EAAE,2BAA2B,EAAE,KAAK,CAAC;IACpD,CAAC,cAAc,EAAE,gCAAgC,EAAE,KAAK,CAAC;IACzD,CAAC,cAAc,EAAE,oBAAoB,EAAE,KAAK,CAAC;IAC7C,CAAC,cAAc,EAAE,+BAA+B,EAAE,IAAI,CAAC;IACvD,CAAC,eAAe,EAAE,2CAA2C,EAAE,IAAI,CAAC;IACpE,CAAC,gBAAgB,EAAE,uBAAuB,EAAE,KAAK,CAAC;IAClD,CAAC,gBAAgB,EAAE,uBAAuB,EAAE,KAAK,CAAC;IAClD,CAAC,cAAc,EAAE,4BAA4B,EAAE,KAAK,CAAC;IACrD,CAAC,iBAAiB,EAAE,UAAU,EAAE,IAAI,CAAC;IACrC,CAAC,iBAAiB,EAAE,KAAK,EAAE,IAAI,CAAC;IAChC,CAAC,gBAAgB,EAAE,iCAAiC,EAAE,IAAI,CAAC;IAC3D,CAAC,gBAAgB,EAAE,4BAA4B,EAAE,KAAK,CAAC;IACvD,CAAC,gBAAgB,EAAE,aAAa,EAAE,KAAK,CAAC;IACxC,CAAC,iBAAiB,EAAE,iCAAiC,EAAE,IAAI,CAAC;IAC5D,CAAC,eAAe,EAAE,cAAc,EAAE,KAAK,CAAC;IACxC,CAAC,iBAAiB,EAAE,4BAA4B,EAAE,KAAK,CAAC;IACxD,CAAC,gBAAgB,EAAE,4BAA4B,EAAE,KAAK,CAAC;IACvD,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC;IAClC,CAAC,oBAAoB,EAAE,mBAAmB,EAAE,KAAK,CAAC;CACnD,CAAC","sourcesContent":["export const BITS = 32;\nexport const GROUPS = 4;\n\n// Each octet is 0-255 written without a leading zero. A leading zero is\n// octal to the WHATWG URL parser, inet_aton, and getaddrinfo, but decimal to\n// parseInt(part, 10), so accepting the notation would make this library\n// disagree with the network stack about which host a string names.\nexport const RE_ADDRESS =\n /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/g;\n\nexport const RE_SUBNET_STRING = /\\/\\d{1,2}$/;\n\n/**\n * The IANA IPv4 Special-Purpose Address Registry\n * (https://www.iana.org/assignments/iana-ipv4-special-registry/), one entry\n * per block: `[cidr, name, globallyReachable]`. A `null` reachability means\n * the registry leaves the column blank and the block inherits the answer of\n * the block containing it (or is global when nothing contains it).\n *\n * `Address4.isGlobal()` answers from the most specific entry containing the\n * address. `test/data/iana-corpus.json` is generated from the registry's CSV\n * and pins this table to it.\n */\nexport const SPECIAL_PURPOSE: ReadonlyArray<readonly [string, string, boolean | null]> = [\n ['0.0.0.0/8', 'This network', false],\n ['0.0.0.0/32', 'This host on this network', false],\n ['10.0.0.0/8', 'Private-Use', false],\n ['100.64.0.0/10', 'Shared Address Space', false],\n ['127.0.0.0/8', 'Loopback', false],\n ['169.254.0.0/16', 'Link Local', false],\n ['172.16.0.0/12', 'Private-Use', false],\n ['192.0.0.0/24', 'IETF Protocol Assignments', false],\n ['192.0.0.0/29', 'IPv4 Service Continuity Prefix', false],\n ['192.0.0.8/32', 'IPv4 dummy address', false],\n ['192.0.0.9/32', 'Port Control Protocol Anycast', true],\n ['192.0.0.10/32', 'Traversal Using Relays around NAT Anycast', true],\n ['192.0.0.170/32', 'NAT64/DNS64 Discovery', false],\n ['192.0.0.171/32', 'NAT64/DNS64 Discovery', false],\n ['192.0.2.0/24', 'Documentation (TEST-NET-1)', false],\n ['192.31.196.0/24', 'AS112-v4', true],\n ['192.52.193.0/24', 'AMT', true],\n ['192.88.99.0/24', 'Deprecated (6to4 Relay Anycast)', null],\n ['192.88.99.2/32', '6a44-relay anycast address', false],\n ['192.168.0.0/16', 'Private-Use', false],\n ['192.175.48.0/24', 'Direct Delegation AS112 Service', true],\n ['198.18.0.0/15', 'Benchmarking', false],\n ['198.51.100.0/24', 'Documentation (TEST-NET-2)', false],\n ['203.0.113.0/24', 'Documentation (TEST-NET-3)', false],\n ['240.0.0.0/4', 'Reserved', false],\n ['255.255.255.255/32', 'Limited Broadcast', false],\n];\n"]}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
export declare const BITS = 128;
|
||||
export declare const GROUPS = 8;
|
||||
/**
|
||||
* Represents IPv6 address scopes
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
export declare const SCOPES: {
|
||||
[key: number]: string | undefined;
|
||||
};
|
||||
/**
|
||||
* Represents IPv6 address types
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
export declare const TYPES: {
|
||||
[key: string]: string | undefined;
|
||||
};
|
||||
/**
|
||||
* A regular expression that matches bad characters in an IPv6 address
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
export declare const RE_BAD_CHARACTERS: RegExp;
|
||||
/**
|
||||
* A regular expression that matches an incorrect IPv6 address
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
export declare const RE_BAD_ADDRESS: RegExp;
|
||||
/**
|
||||
* A regular expression that matches an IPv6 subnet
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
export declare const RE_SUBNET_STRING: RegExp;
|
||||
/**
|
||||
* A regular expression that matches an IPv6 zone
|
||||
* @memberof Address6
|
||||
* @static
|
||||
* @deprecated Takes quadratic time on input holding many `%` characters
|
||||
* followed by a line terminator. The library finds the zone by index, as
|
||||
* `Address6`'s constructor shows, and 11.0.0 removes this export.
|
||||
*/
|
||||
export declare const RE_ZONE_STRING: RegExp;
|
||||
export declare const RE_URL: RegExp;
|
||||
export declare const RE_URL_WITH_PORT: RegExp;
|
||||
/**
|
||||
* The IANA IPv6 Special-Purpose Address Registry
|
||||
* (https://www.iana.org/assignments/iana-ipv6-special-registry/), one entry
|
||||
* per block: `[cidr, name, globallyReachable]`. A `null` reachability means
|
||||
* the registry says N/A or leaves the column blank; N/A blocks (Teredo, 6to4)
|
||||
* are treated as not globally reachable, since a packet to one needs a relay,
|
||||
* and blank blocks inherit the answer of the block containing them.
|
||||
*
|
||||
* `Address6.isGlobal()` answers from the most specific entry containing the
|
||||
* address, after delegating IPv4-mapped and NAT64 well-known addresses to the
|
||||
* embedded IPv4 address. `test/data/iana-corpus.json` is generated from the
|
||||
* registry's CSV and pins this table to it.
|
||||
*/
|
||||
export declare const SPECIAL_PURPOSE: ReadonlyArray<readonly [string, string, boolean | null]>;
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SPECIAL_PURPOSE = exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
|
||||
exports.BITS = 128;
|
||||
exports.GROUPS = 8;
|
||||
/**
|
||||
* Represents IPv6 address scopes
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
exports.SCOPES = {
|
||||
0: 'Reserved',
|
||||
1: 'Interface local',
|
||||
2: 'Link local',
|
||||
4: 'Admin local',
|
||||
5: 'Site local',
|
||||
8: 'Organization local',
|
||||
14: 'Global',
|
||||
15: 'Reserved',
|
||||
};
|
||||
/**
|
||||
* Represents IPv6 address types
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
exports.TYPES = {
|
||||
'ff01::1/128': 'Multicast (All nodes on this interface)',
|
||||
'ff01::2/128': 'Multicast (All routers on this interface)',
|
||||
'ff02::1/128': 'Multicast (All nodes on this link)',
|
||||
'ff02::2/128': 'Multicast (All routers on this link)',
|
||||
'ff05::2/128': 'Multicast (All routers in this site)',
|
||||
'ff02::5/128': 'Multicast (OSPFv3 AllSPF routers)',
|
||||
'ff02::6/128': 'Multicast (OSPFv3 AllDR routers)',
|
||||
'ff02::9/128': 'Multicast (RIP routers)',
|
||||
'ff02::a/128': 'Multicast (EIGRP routers)',
|
||||
'ff02::d/128': 'Multicast (PIM routers)',
|
||||
'ff02::16/128': 'Multicast (MLDv2 reports)',
|
||||
'ff01::fb/128': 'Multicast (mDNSv6)',
|
||||
'ff02::fb/128': 'Multicast (mDNSv6)',
|
||||
'ff05::fb/128': 'Multicast (mDNSv6)',
|
||||
'ff02::1:2/128': 'Multicast (All DHCP servers and relay agents on this link)',
|
||||
'ff05::1:2/128': 'Multicast (All DHCP servers and relay agents in this site)',
|
||||
'ff02::1:3/128': 'Multicast (All DHCP servers on this link)',
|
||||
'ff05::1:3/128': 'Multicast (All DHCP servers in this site)',
|
||||
'::/128': 'Unspecified',
|
||||
'::1/128': 'Loopback',
|
||||
'::ffff:0:0/96': 'IPv4-mapped',
|
||||
'ff00::/8': 'Multicast',
|
||||
'fe80::/10': 'Link-local unicast',
|
||||
'fc00::/7': 'Unique local',
|
||||
'2001::/32': 'Teredo',
|
||||
'2001:2::/48': 'Benchmarking',
|
||||
'2002::/16': '6to4',
|
||||
'2001:db8::/32': 'Documentation',
|
||||
'3fff::/20': 'Documentation',
|
||||
'100::/64': 'Discard-only',
|
||||
'fec0::/10': 'Site-local unicast (deprecated)',
|
||||
'::/96': 'IPv4-compatible (deprecated)',
|
||||
'64:ff9b::/96': 'NAT64 (well-known)',
|
||||
'64:ff9b:1::/48': 'NAT64 (local-use)',
|
||||
};
|
||||
/**
|
||||
* A regular expression that matches bad characters in an IPv6 address
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
exports.RE_BAD_CHARACTERS = /([^0-9a-f:/%])/gi;
|
||||
/**
|
||||
* A regular expression that matches an incorrect IPv6 address
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
exports.RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]|\/$)/gi;
|
||||
/**
|
||||
* A regular expression that matches an IPv6 subnet
|
||||
* @memberof Address6
|
||||
* @static
|
||||
*/
|
||||
exports.RE_SUBNET_STRING = /\/\d{1,3}(?=%|$)/;
|
||||
/**
|
||||
* A regular expression that matches an IPv6 zone
|
||||
* @memberof Address6
|
||||
* @static
|
||||
* @deprecated Takes quadratic time on input holding many `%` characters
|
||||
* followed by a line terminator. The library finds the zone by index, as
|
||||
* `Address6`'s constructor shows, and 11.0.0 removes this export.
|
||||
*/
|
||||
exports.RE_ZONE_STRING = /%.*$/;
|
||||
exports.RE_URL = /^(?:\[([0-9a-f:.]+)\]|([0-9a-f:.]+))(?:[/?#].*)?$/i;
|
||||
exports.RE_URL_WITH_PORT = /^\[([0-9a-f:.]+)\]:([0-9]{1,5})(?:[/?#].*)?$/i;
|
||||
/**
|
||||
* The IANA IPv6 Special-Purpose Address Registry
|
||||
* (https://www.iana.org/assignments/iana-ipv6-special-registry/), one entry
|
||||
* per block: `[cidr, name, globallyReachable]`. A `null` reachability means
|
||||
* the registry says N/A or leaves the column blank; N/A blocks (Teredo, 6to4)
|
||||
* are treated as not globally reachable, since a packet to one needs a relay,
|
||||
* and blank blocks inherit the answer of the block containing them.
|
||||
*
|
||||
* `Address6.isGlobal()` answers from the most specific entry containing the
|
||||
* address, after delegating IPv4-mapped and NAT64 well-known addresses to the
|
||||
* embedded IPv4 address. `test/data/iana-corpus.json` is generated from the
|
||||
* registry's CSV and pins this table to it.
|
||||
*/
|
||||
exports.SPECIAL_PURPOSE = [
|
||||
['::1/128', 'Loopback Address', false],
|
||||
['::/128', 'Unspecified Address', false],
|
||||
['::ffff:0:0/96', 'IPv4-mapped Address', false],
|
||||
['64:ff9b::/96', 'IPv4-IPv6 Translat.', true],
|
||||
['64:ff9b:1::/48', 'IPv4-IPv6 Translat.', false],
|
||||
['100::/64', 'Discard-Only Address Block', false],
|
||||
['100:0:0:1::/64', 'Dummy IPv6 Prefix', false],
|
||||
['2001::/23', 'IETF Protocol Assignments', false],
|
||||
['2001::/32', 'TEREDO', false],
|
||||
['2001:1::1/128', 'Port Control Protocol Anycast', true],
|
||||
['2001:1::2/128', 'Traversal Using Relays around NAT Anycast', true],
|
||||
['2001:1::3/128', 'DNS-SD Service Registration Protocol Anycast', true],
|
||||
['2001:2::/48', 'Benchmarking', false],
|
||||
['2001:3::/32', 'AMT', true],
|
||||
['2001:4:112::/48', 'AS112-v6', true],
|
||||
['2001:10::/28', 'Deprecated (previously ORCHID)', null],
|
||||
['2001:20::/28', 'ORCHIDv2', true],
|
||||
['2001:30::/28', 'Drone Remote ID Protocol Entity Tags (DETs) Prefix', true],
|
||||
['2001:db8::/32', 'Documentation', false],
|
||||
['2002::/16', '6to4', false],
|
||||
['2620:4f:8000::/48', 'Direct Delegation AS112 Service', true],
|
||||
['3fff::/20', 'Documentation', false],
|
||||
['5f00::/16', 'Segment Routing (SRv6) SIDs', false],
|
||||
['fc00::/7', 'Unique-Local', false],
|
||||
['fe80::/10', 'Link-Local Unicast', false],
|
||||
];
|
||||
//# sourceMappingURL=constants.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
export declare function escapeHtml(s: string): string;
|
||||
/**
|
||||
* @returns {String} the string with all zeroes contained in a <span>
|
||||
*/
|
||||
export declare function spanAllZeroes(s: string): string;
|
||||
/**
|
||||
* @returns {String} the string with each character contained in a <span>
|
||||
*/
|
||||
export declare function spanAll(s: string, offset?: number): string;
|
||||
/**
|
||||
* @returns {String} the string with leading zeroes contained in a <span>
|
||||
*/
|
||||
export declare function spanLeadingZeroes(address: string): string;
|
||||
/**
|
||||
* Groups an address
|
||||
* @returns {String} a grouped address
|
||||
*/
|
||||
export declare function simpleGroup(addressString: string, offset?: number): string[];
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.escapeHtml = escapeHtml;
|
||||
exports.spanAllZeroes = spanAllZeroes;
|
||||
exports.spanAll = spanAll;
|
||||
exports.spanLeadingZeroes = spanLeadingZeroes;
|
||||
exports.simpleGroup = simpleGroup;
|
||||
function escapeHtml(s) {
|
||||
return s
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
/**
|
||||
* @returns {String} the string with all zeroes contained in a <span>
|
||||
*/
|
||||
function spanAllZeroes(s) {
|
||||
return escapeHtml(s).replace(/(0+)/g, '<span class="zero">$1</span>');
|
||||
}
|
||||
/**
|
||||
* @returns {String} the string with each character contained in a <span>
|
||||
*/
|
||||
function spanAll(s, offset = 0) {
|
||||
const letters = s.split('');
|
||||
return letters
|
||||
.map((n, i) => `<span class="digit value-${escapeHtml(n)} position-${i + offset}">${spanAllZeroes(n)}</span>`)
|
||||
.join('');
|
||||
}
|
||||
function spanLeadingZeroesSimple(group) {
|
||||
return escapeHtml(group).replace(/^(0+)/, '<span class="zero">$1</span>');
|
||||
}
|
||||
/**
|
||||
* @returns {String} the string with leading zeroes contained in a <span>
|
||||
*/
|
||||
function spanLeadingZeroes(address) {
|
||||
const groups = address.split(':');
|
||||
return groups.map((g) => spanLeadingZeroesSimple(g)).join(':');
|
||||
}
|
||||
/**
|
||||
* Groups an address
|
||||
* @returns {String} a grouped address
|
||||
*/
|
||||
function simpleGroup(addressString, offset = 0) {
|
||||
const groups = addressString.split(':');
|
||||
return groups.map((g, i) => {
|
||||
if (/group-v4/.test(g)) {
|
||||
return g;
|
||||
}
|
||||
return `<span class="hover-group group-${i + offset}">${spanLeadingZeroesSimple(g)}</span>`;
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=helpers.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/v6/helpers.ts"],"names":[],"mappings":";;AAAA,gCAOC;AAKD,sCAEC;AAKD,0BASC;AASD,8CAIC;AAMD,kCAUC;AAzDD,SAAgB,UAAU,CAAC,CAAS;IAClC,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,CAAS;IACrC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,SAAgB,OAAO,CAAC,CAAS,EAAE,SAAiB,CAAC;IACnD,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAE5B,OAAO,OAAO;SACX,GAAG,CACF,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,4BAA4B,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,SAAS,CACjG;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAa;IAC5C,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAElC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,aAAqB,EAAE,SAAiB,CAAC;IACnE,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAExC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzB,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,CAAC;QACX,CAAC;QAED,OAAO,kCAAkC,CAAC,GAAG,MAAM,KAAK,uBAAuB,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9F,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["export function escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * @returns {String} the string with all zeroes contained in a <span>\n */\nexport function spanAllZeroes(s: string): string {\n return escapeHtml(s).replace(/(0+)/g, '<span class=\"zero\">$1</span>');\n}\n\n/**\n * @returns {String} the string with each character contained in a <span>\n */\nexport function spanAll(s: string, offset: number = 0): string {\n const letters = s.split('');\n\n return letters\n .map(\n (n, i) =>\n `<span class=\"digit value-${escapeHtml(n)} position-${i + offset}\">${spanAllZeroes(n)}</span>`,\n )\n .join('');\n}\n\nfunction spanLeadingZeroesSimple(group: string): string {\n return escapeHtml(group).replace(/^(0+)/, '<span class=\"zero\">$1</span>');\n}\n\n/**\n * @returns {String} the string with leading zeroes contained in a <span>\n */\nexport function spanLeadingZeroes(address: string): string {\n const groups = address.split(':');\n\n return groups.map((g) => spanLeadingZeroesSimple(g)).join(':');\n}\n\n/**\n * Groups an address\n * @returns {String} a grouped address\n */\nexport function simpleGroup(addressString: string, offset: number = 0): string[] {\n const groups = addressString.split(':');\n\n return groups.map((g, i) => {\n if (/group-v4/.test(g)) {\n return g;\n }\n\n return `<span class=\"hover-group group-${i + offset}\">${spanLeadingZeroesSimple(g)}</span>`;\n });\n}\n"]}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export declare function groupPossibilities(possibilities: string[]): string;
|
||||
export declare function padGroup(group: string): string;
|
||||
export declare const ADDRESS_BOUNDARY = "[^A-Fa-f0-9:]";
|
||||
export declare function simpleRegularExpression(groups: string[]): string;
|
||||
export declare function possibleElisions(elidedGroups: number, moreLeft?: boolean, moreRight?: boolean): string;
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ADDRESS_BOUNDARY = void 0;
|
||||
exports.groupPossibilities = groupPossibilities;
|
||||
exports.padGroup = padGroup;
|
||||
exports.simpleRegularExpression = simpleRegularExpression;
|
||||
exports.possibleElisions = possibleElisions;
|
||||
const v6 = __importStar(require("./constants"));
|
||||
function groupPossibilities(possibilities) {
|
||||
return `(${possibilities.join('|')})`;
|
||||
}
|
||||
function padGroup(group) {
|
||||
if (group.length < 4) {
|
||||
return `0{0,${4 - group.length}}${group}`;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
exports.ADDRESS_BOUNDARY = '[^A-Fa-f0-9:]';
|
||||
function simpleRegularExpression(groups) {
|
||||
const zeroIndexes = [];
|
||||
groups.forEach((group, i) => {
|
||||
const groupInteger = parseInt(group, 16);
|
||||
if (groupInteger === 0) {
|
||||
zeroIndexes.push(i);
|
||||
}
|
||||
});
|
||||
// You can technically elide a single 0, this creates the regular expressions
|
||||
// to match that eventuality
|
||||
const possibilities = zeroIndexes.map((zeroIndex) => groups
|
||||
.map((group, i) => {
|
||||
if (i === zeroIndex) {
|
||||
const elision = i === 0 || i === v6.GROUPS - 1 ? ':' : '';
|
||||
return groupPossibilities([padGroup(group), elision]);
|
||||
}
|
||||
return padGroup(group);
|
||||
})
|
||||
.join(':'));
|
||||
// The simplest case
|
||||
possibilities.push(groups.map(padGroup).join(':'));
|
||||
return groupPossibilities(possibilities);
|
||||
}
|
||||
function possibleElisions(elidedGroups, moreLeft, moreRight) {
|
||||
const left = moreLeft ? '' : ':';
|
||||
const right = moreRight ? '' : ':';
|
||||
const possibilities = [];
|
||||
// 1. elision of everything (::)
|
||||
if (!moreLeft && !moreRight) {
|
||||
possibilities.push('::');
|
||||
}
|
||||
// 2. complete elision of the middle
|
||||
if (moreLeft && moreRight) {
|
||||
possibilities.push('');
|
||||
}
|
||||
if ((moreRight && !moreLeft) || (!moreRight && moreLeft)) {
|
||||
// 3. complete elision of one side
|
||||
possibilities.push(':');
|
||||
}
|
||||
// 4. elision from the left side
|
||||
possibilities.push(`${left}(:0{1,4}){1,${elidedGroups - 1}}`);
|
||||
// 5. elision from the right side
|
||||
possibilities.push(`(0{1,4}:){1,${elidedGroups - 1}}${right}`);
|
||||
// 6. no elision
|
||||
possibilities.push(`(0{1,4}:){${elidedGroups - 1}}0{1,4}`);
|
||||
// 7. elision (including sloppy elision) from the middle
|
||||
for (let groups = 1; groups < elidedGroups - 1; groups++) {
|
||||
for (let position = 1; position < elidedGroups - groups; position++) {
|
||||
possibilities.push(`(0{1,4}:){${position}}:(0{1,4}:){${elidedGroups - position - groups - 1}}0{1,4}`);
|
||||
}
|
||||
}
|
||||
return groupPossibilities(possibilities);
|
||||
}
|
||||
//# sourceMappingURL=regular-expressions.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+91
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"name": "ip-address",
|
||||
"description": "A library for parsing IPv4 and IPv6 IP addresses in node and the browser.",
|
||||
"keywords": [
|
||||
"ip",
|
||||
"ipv4",
|
||||
"ipv6",
|
||||
"address",
|
||||
"cidr",
|
||||
"subnet",
|
||||
"netmask",
|
||||
"validate",
|
||||
"validation",
|
||||
"parse",
|
||||
"arpa",
|
||||
"bigint",
|
||||
"browser"
|
||||
],
|
||||
"version": "10.7.4",
|
||||
"author": "Beau Gunderson <beau@beaugunderson.com> (https://beaugunderson.com/)",
|
||||
"license": "MIT",
|
||||
"main": "dist/ip-address.js",
|
||||
"types": "dist/ip-address.d.ts",
|
||||
"scripts": {
|
||||
"docs": "tsx scripts/build-readme.ts",
|
||||
"docs:check": "tsx scripts/build-readme.ts --check",
|
||||
"build": "rm -rf dist; mkdir dist; tsc",
|
||||
"prepack": "npm run docs && npm run build",
|
||||
"prepare": "git config core.hooksPath hooks || true",
|
||||
"lint": "prettier --check . && eslint . --ext .ts,.js --max-warnings 0",
|
||||
"lint:fix": "prettier --write . && eslint . --ext .ts,.js --max-warnings 0 --fix",
|
||||
"test-ci": "c8 --experimental-monocart mocha",
|
||||
"test": "mocha",
|
||||
"watch": "mocha --watch"
|
||||
},
|
||||
"c8": {
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.d.ts",
|
||||
"src/ip-address.ts",
|
||||
"src/v4/constants.ts",
|
||||
"src/v6/constants.ts"
|
||||
],
|
||||
"reporter": [
|
||||
"html",
|
||||
"lcov",
|
||||
"text"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/beaugunderson/ip-address.git"
|
||||
},
|
||||
"overrides": {
|
||||
"diff": "^8.0.3",
|
||||
"serialize-javascript": "^7.0.5",
|
||||
"@eslint/plugin-kit": "^0.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^5.2.3",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
||||
"@typescript-eslint/parser": "^8.59.1",
|
||||
"c8": "^11.0.0",
|
||||
"chai": "^6.2.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint_d": "^14.0.4",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-filenames": "^1.3.2",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
|
||||
"mocha": "^11.7.5",
|
||||
"monocart-coverage-reports": "^2.12.11",
|
||||
"prettier": "^3.8.3",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tsx": "^4.21.0",
|
||||
"typedoc": "^0.28.19",
|
||||
"typescript": "<5.6.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user