avancement planning

This commit is contained in:
2026-05-26 11:58:39 +02:00
parent 619a2b240a
commit 150b97cd2e
4892 changed files with 99214 additions and 429382 deletions
+252 -79
View File
@@ -2,104 +2,277 @@
[![codecov]](https://codecov.io/github/beaugunderson/ip-address?branch=master)
[![downloads]](https://www.npmjs.com/package/ip-address)
[![npm]](https://www.npmjs.com/package/ip-address)
[![snyk]](https://snyk.io/test/github/beaugunderson/ip-address)
[codecov]: https://codecov.io/github/beaugunderson/ip-address/coverage.svg?branch=master
[downloads]: https://img.shields.io/npm/dm/ip-address.svg
[npm]: https://img.shields.io/npm/v/ip-address.svg
[snyk]: https://snyk.io/test/github/beaugunderson/ip-address/badge.svg
## ip-address
`ip-address` is a library for validating and manipulating IPv4 and IPv6
addresses in JavaScript.
`ip-address` is a library for validating and manipulating IPv4 and IPv6 addresses in JavaScript and TypeScript.
### Upgrading from 9.x to 10.x
### Install
The dependency on `jsbn` was removed thanks to
[michal-kocarek](https://github.com/michal-kocarek). Thanks Michal! For
clarity, all methods with BigInteger in the name were renamed to BigInt.
#### Breaking changes
- `#fromBigInteger()``#fromBigInt()`; now returns a native BigInt
- `#bigInteger()``#bigInt()`; now returns a native BigInt
### Documentation
Documentation is available at [ip-address.js.org](http://ip-address.js.org/).
```sh
npm install ip-address
```
### Examples
```js
var Address6 = require('ip-address').Address6;
```ts
import { Address4, Address6 } from 'ip-address';
var address = new Address6('2001:0:ce49:7601:e866:efff:62c3:fffe');
// Validation
Address4.isValid('192.168.1.1'); // true
Address6.isValid('2001:db8::1'); // true
Address6.isValid('not an address'); // false
var teredo = address.inspectTeredo();
// Parsing (throws AddressError on invalid input)
const v4 = new Address4('192.168.1.1/24');
const v6 = new Address6('2001:db8::1/64');
teredo.client4; // '157.60.0.1'
// 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
- Usable via CommonJS or ESM
- Parsing of all IPv6 notations
- Parsing of IPv6 addresses and ports from URLs with `Address6.fromURL(url)`
- Validity checking
- Decoding of the [Teredo
information](http://en.wikipedia.org/wiki/Teredo_tunneling#IPv6_addressing)
in an address
- Whether one address is a valid subnet of another
- What special properties a given address has (multicast prefix, unique
local address prefix, etc.)
- Number of subnets of a certain size in a given address
- Display methods
- Hex, binary, and decimal
- Canonical form
- Correct form
- IPv4-compatible (i.e. `::ffff:192.168.0.1`)
- Works in [node](http://nodejs.org/) and the browser (with browserify)
- ~1,600 test cases
- Written in TypeScript with full type definitions; usable from CommonJS and ESM
- Zero runtime dependencies
- Parses all standard IPv4 and IPv6 notations, including subnets and zones
- 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 an IPv4 address as the second 16 bits of a `2002::/16` IPv6 address. `inspect6to4()` decodes the embedded v4 address.
### API
<!-- API:START -->
#### AddressError
**Constructor**
- `new AddressError(message: string, parseMessage?: string): AddressError`
**Properties**
- `parseMessage: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/address-error.ts#L2)
#### Address4
Represents an IPv4 address
**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/master/src/ipv4.ts#L53)
- `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/master/src/ipv4.ts#L104)
- `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/master/src/ipv4.ts#L118)
- `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/master/src/ipv4.ts#L140)
- `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/master/src/ipv4.ts#L175)
- `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/master/src/ipv4.ts#L198)
- `static fromArpa(arpaFormAddress: string): Address4` — Return an address from in-addr.arpa form [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L214)
- `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/master/src/ipv4.ts#L361)
- `static fromByteArray(bytes: number[]): Address4` — Convert a byte array to an Address4 object. To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L376)
- `static fromUnsignedByteArray(bytes: number[]): Address4` — Convert an unsigned byte array to an Address4 object [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L396)
**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/master/src/ipv4.ts#L70)
- `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/master/src/ipv4.ts#L85)
- `toHex(): string` — Converts an IPv4 address object to a hex string [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L227)
- `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/master/src/ipv4.ts#L237)
- `toGroup6(): string` — Converts an IPv4 address object to an IPv6 address group [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L245)
- `bigInt(): bigint` — Returns the address as a `bigint` [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L264)
- `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/master/src/ipv4.ts#L281)
- `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/master/src/ipv4.ts#L290)
- `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/master/src/ipv4.ts#L308)
- `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/master/src/ipv4.ts#L317)
- `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/master/src/ipv4.ts#L327)
- `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/master/src/ipv4.ts#L339)
- `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/master/src/ipv4.ts#L351)
- `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/master/src/ipv4.ts#L410)
- `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/master/src/ipv4.ts#L422)
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed ip6.arpa form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L432)
- `isMulticast(): boolean` — Returns true if the given address is a multicast address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L456)
- `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/master/src/ipv4.ts#L464)
- `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/master/src/ipv4.ts#L472)
- `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/master/src/ipv4.ts#L480)
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `0.0.0.0`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L488)
- `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/master/src/ipv4.ts#L496)
- `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/master/src/ipv4.ts#L504)
- `binaryZeroPad(): string` — Returns a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L512)
- `groupForV6(): string` — Groups an IPv4 address for inclusion at the end of an IPv6 address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L523)
**Properties**
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L14)
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L15)
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L16)
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L17)
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L18)
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L19)
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L20)
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L21)
- `isCorrect: (this: Address4 | Address6) => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L93)
- `isInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv4.ts#L450)
#### Address6
Represents an IPv6 address
**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/master/src/ipv6.ts#L163)
- `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/master/src/ipv6.ts#L184)
- `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/master/src/ipv6.ts#L209)
- `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/master/src/ipv6.ts#L273)
- `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/master/src/ipv6.ts#L287)
- `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/master/src/ipv6.ts#L310)
- `static fromAddress4(address: string): Address6` — Create an IPv6-mapped address given an IPv4 address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L371)
- `static fromArpa(arpaFormAddress: string): Address6` — Return an address from ip6.arpa form [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L387)
- `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 6471. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1048)
- `static fromByteArray(bytes: any[]): Address6` — Convert a byte array to an Address6 object. To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1154)
- `static fromUnsignedByteArray(bytes: any[]): Address6` — Convert an unsigned byte array to an Address6 object. To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1164)
**Instance methods**
- `microsoftTranscription(): string` — Return the Microsoft UNC transcription of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L413)
- `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/master/src/ipv6.ts#L422)
- `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/master/src/ipv6.ts#L432)
- `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/master/src/ipv6.ts#L457)
- `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/master/src/ipv6.ts#L466)
- `endAddress(): Address6` — 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/master/src/ipv6.ts#L484)
- `endAddressExclusive(): Address6` — 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/master/src/ipv6.ts#L493)
- `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/master/src/ipv6.ts#L503)
- `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/master/src/ipv6.ts#L515)
- `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/master/src/ipv6.ts#L528)
- `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/master/src/ipv6.ts#L540)
- `getType(): string` — Return the type of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L567)
- `getBits(start: number, end: number): bigint` — Return the bits in the given range as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L582)
- `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/master/src/ipv6.ts#L590)
- `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/master/src/ipv6.ts#L598)
- `getBitsPastSubnet(): string` — Return the bits that are set past the subnet mask length [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L614)
- `reverseForm(options?: ReverseFormOptions): string` — Return the reversed ip6.arpa form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L624)
- `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/master/src/ipv6.ts#L659)
- `binaryZeroPad(): string` — Return a zero-padded base-2 string representation of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L721)
- `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/master/src/ipv6.ts#L735)
- `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/master/src/ipv6.ts#L783)
- `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/master/src/ipv6.ts#L863)
- `decimal(): string` — Return the decimal form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L871)
- `bigInt(): bigint` — Return the address as a BigInt [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L879)
- `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/master/src/ipv6.ts#L894)
- `to4in6(): string` — Return the v4-in-v6 form of the address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L916)
- `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/master/src/ipv6.ts#L937)
- `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/master/src/ipv6.ts#L1002)
- `to6to4(): Address6 | null` — Return a v6 6to4 address from a v6 v4inv6 address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1022)
- `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/master/src/ipv6.ts#L1089)
- `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/master/src/ipv6.ts#L1124)
- `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/master/src/ipv6.ts#L1144)
- `isCanonical(): boolean` — Returns true if the address is in the canonical form, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1195)
- `isLinkLocal(): boolean` — Returns true if the address is a link local address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1203)
- `isMulticast(): boolean` — Returns true if the address is a multicast address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1219)
- `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/master/src/ipv6.ts#L1231)
- `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/master/src/ipv6.ts#L1243)
- `isTeredo(): boolean` — Returns true if the address is a Teredo address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1251)
- `is6to4(): boolean` — Returns true if the address is a 6to4 address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1259)
- `isLoopback(): boolean` — Returns true if the address is a loopback address, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1267)
- `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/master/src/ipv6.ts#L1275)
- `isUnspecified(): boolean` — Returns true if the address is the unspecified address `::`. [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1283)
- `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/master/src/ipv6.ts#L1291)
- `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/master/src/ipv6.ts#L1302)
- `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/master/src/ipv6.ts#L1320)
- `group(): string` — Groups an address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1360)
- `regularExpressionString(this: Address6, 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/master/src/ipv6.ts#L1412)
- `regularExpression(this: Address6, 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/master/src/ipv6.ts#L1466)
**Properties**
- `address4: Address4` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L98)
- `address: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L99)
- `addressMinusSuffix: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L100)
- `elidedGroups: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L101)
- `elisionBegin: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L102)
- `elisionEnd: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L103)
- `groups: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L104)
- `parsedAddress4: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L105)
- `parsedAddress: string[]` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L106)
- `parsedSubnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L107)
- `subnet: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L108)
- `subnetMask: number` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L109)
- `v4: boolean` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L110)
- `zone: string` — [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L111)
- `isInSubnet: (this: Address4 | Address6, address: Address4 | Address6) => boolean` — Returns true if the given address is in the subnet of the current address [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1183)
- `isCorrect: (this: Address4 | Address6) => boolean` — Returns true if the address is correct, false otherwise [src](https://github.com/beaugunderson/ip-address/blob/master/src/ipv6.ts#L1189)
<!-- API:END -->
### Used by
- [anon](https://github.com/edsu/anon) which powers
[@congressedits](https://twitter.com/congressedits), among
[many others](https://github.com/edsu/anon#community)
- [base85](https://github.com/noseglid/base85): base85 encoding/decoding
- [contrail-web-core](https://github.com/Juniper/contrail-web-core): part of
Contrail, a network virtualization solution made by Juniper Networks
- [dhcpjs](https://github.com/apaprocki/node-dhcpjs): a DHCP client and server
- [epochtalk](https://github.com/epochtalk/epochtalk): next generation forum
software
- [geoip-web](https://github.com/tfrce/node-geoip-web): a server for
quickly geolocating IP addresses
- [hexabus](https://github.com/mysmartgrid/hexabus): an IPv6-based home
automation bus
- [hubot-deploy](https://github.com/atmos/hubot-deploy): GitHub Flow via hubot
- [heroku-portscanner](https://github.com/robison/heroku-portscanner): nmap
hosted on Heroku
- [ipfs-swarm](https://github.com/diasdavid/node-ipfs-swarm): a swarm
implementation based on IPFS
- [javascript-x-server](https://github.com/GothAck/javascript-x-server): an X
server written in JavaScript
- [libnmap](https://github.com/jas-/node-libnmap): a node API for nmap
- [mail-io](https://github.com/mofux/mail-io): a lightweight SMTP server
- [maxmind-db-reader](https://github.com/PaddeK/node-maxmind-db): a library for
reading MaxMind database files
- [proxy-protocol-v2](https://github.com/ably/proxy-protocol-v2): a proxy
protocol encoder/decoder built by [Ably](https://www.ably.io/)
- [Samsara](https://github.com/mariusGundersen/Samsara): a Docker web interface
- [sis-api](https://github.com/sis-cmdb/sis-api): a configuration management
database API
- [socks5-client](https://github.com/mattcg/socks5-client): a SOCKS v5 client
- [socksified](https://github.com/vially/node-socksified): a SOCKS v5 client
- [socksv5](https://github.com/mscdex/socksv5): a SOCKS v5 server/client
- [ssdapi](https://github.com/rsolomou/ssdapi): an API created by the
University of Portsmouth
- [SwitchyOmega](https://github.com/FelisCatus/SwitchyOmega): a [Chrome
extension](https://chrome.google.com/webstore/detail/padekgcemlokbadohgkifijomclgjgif)
for switching between multiple proxies with ~311k users!
- [swiz](https://github.com/racker/node-swiz): a serialization framework built
and used by [Rackspace](http://www.rackspace.com/)
`ip-address` is downloaded ~66 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) (~57M 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) (~44M 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.
-1
View File
@@ -2,4 +2,3 @@ export declare class AddressError extends Error {
parseMessage?: string;
constructor(message: string, parseMessage?: string);
}
//# sourceMappingURL=address-error.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"address-error.d.ts","sourceRoot":"","sources":["../src/address-error.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;CAOnD"}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"address-error.js","sourceRoot":"","sources":["../src/address-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;IAGrC,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;AAVD,oCAUC"}
{"version":3,"file":"address-error.js","sourceRoot":"","sources":["../src/address-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;IAGrC,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;AAVD,oCAUC","sourcesContent":["export class AddressError extends Error {\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"]}
+6 -1
View File
@@ -5,6 +5,12 @@ export interface ReverseFormOptions {
}
export declare function isInSubnet(this: Address4 | Address6, address: Address4 | Address6): boolean;
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;
export declare function numberToPaddedHex(number: number): string;
export declare function stringToPaddedHex(numberString: string): string;
/**
@@ -12,4 +18,3 @@ export declare function stringToPaddedHex(numberString: string): string;
* @param position Byte position, where 0 is the least significant bit
*/
export declare function testBit(binaryValue: string, position: number): boolean;
//# sourceMappingURL=common.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,OAAO,EAAE,QAAQ,GAAG,QAAQ,WAUjF;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,UACpB,QAAQ,GAAG,QAAQ,aAW3C;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,UAE/C;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,UAErD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAStE"}
+21
View File
@@ -2,9 +2,11 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.isInSubnet = isInSubnet;
exports.isCorrect = isCorrect;
exports.prefixLengthFromMask = prefixLengthFromMask;
exports.numberToPaddedHex = numberToPaddedHex;
exports.stringToPaddedHex = stringToPaddedHex;
exports.testBit = testBit;
const address_error_1 = require("./address-error");
function isInSubnet(address) {
if (this.subnetMask < address.subnetMask) {
return false;
@@ -25,6 +27,25 @@ function isCorrect(defaultBits) {
return this.parsedSubnet === String(this.subnetMask);
};
}
/**
* Returns the prefix length (number of leading 1 bits) of a contiguous
* subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g.
* `255.0.255.0`).
*/
function prefixLengthFromMask(value, totalBits) {
const binary = value.toString(2).padStart(totalBits, '0');
if (binary.length > totalBits) {
throw new address_error_1.AddressError('Invalid subnet mask.');
}
const firstZero = binary.indexOf('0');
if (firstZero === -1) {
return totalBits;
}
if (binary.slice(firstZero).includes('1')) {
throw new address_error_1.AddressError('Invalid subnet mask.');
}
return firstZero;
}
function numberToPaddedHex(number) {
return number.toString(16).padStart(2, '0');
}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"common.js","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":";;AAOA,gCAUC;AAED,8BAYC;AAED,8CAEC;AAED,8CAEC;AAMD,0BASC;AA/CD,SAAgB,UAAU,CAA4B,OAA4B;IAChF,IAAI,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,SAAS,CAAC,WAAmB;IAC3C,OAAO;QACL,IAAI,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,iBAAiB,CAAC,MAAc;IAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED,SAAgB,iBAAiB,CAAC,YAAoB;IACpD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,WAAmB,EAAE,QAAgB;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAE/B,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,OAAO,WAAW,CAAC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;AAC/E,CAAC"}
{"version":3,"file":"common.js","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":";;AAQA,gCAUC;AAED,8BAYC;AAOD,oDAkBC;AAED,8CAEC;AAED,8CAEC;AAMD,0BASC;AA9ED,mDAA+C;AAM/C,SAAgB,UAAU,CAA4B,OAA4B;IAChF,IAAI,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,SAAS,CAAC,WAAmB;IAC3C,OAAO;QACL,IAAI,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,oBAAoB,CAAC,KAAa,EAAE,SAAiB;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAE1D,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,4BAAY,CAAC,sBAAsB,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAEtC,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,4BAAY,CAAC,sBAAsB,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,iBAAiB,CAAC,MAAc;IAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED,SAAgB,iBAAiB,CAAC,YAAoB;IACpD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,WAAmB,EAAE,QAAgB;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAE/B,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,OAAO,WAAW,CAAC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;AAC/E,CAAC","sourcesContent":["import { Address4 } from './ipv4';\nimport { Address6 } from './ipv6';\nimport { AddressError } from './address-error';\n\nexport interface ReverseFormOptions {\n omitSuffix?: boolean;\n}\n\nexport function isInSubnet(this: Address4 | Address6, address: Address4 | Address6) {\n if (this.subnetMask < address.subnetMask) {\n return false;\n }\n\n if (this.mask(address.subnetMask) === address.mask()) {\n return true;\n }\n\n return false;\n}\n\nexport function isCorrect(defaultBits: number) {\n return function (this: Address4 | Address6) {\n if (this.addressMinusSuffix !== this.correctForm()) {\n return false;\n }\n\n if (this.subnetMask === defaultBits && !this.parsedSubnet) {\n return true;\n }\n\n return this.parsedSubnet === String(this.subnetMask);\n };\n}\n\n/**\n * Returns the prefix length (number of leading 1 bits) of a contiguous\n * subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g.\n * `255.0.255.0`).\n */\nexport function prefixLengthFromMask(value: bigint, totalBits: number): number {\n const binary = value.toString(2).padStart(totalBits, '0');\n\n if (binary.length > totalBits) {\n throw new AddressError('Invalid subnet mask.');\n }\n\n const firstZero = binary.indexOf('0');\n\n if (firstZero === -1) {\n return totalBits;\n }\n\n if (binary.slice(firstZero).includes('1')) {\n throw new AddressError('Invalid subnet mask.');\n }\n\n return firstZero;\n}\n\nexport function numberToPaddedHex(number: number) {\n return number.toString(16).padStart(2, '0');\n}\n\nexport function stringToPaddedHex(numberString: string) {\n return numberToPaddedHex(parseInt(numberString, 10));\n}\n\n/**\n * @param binaryValue Binary representation of a value (e.g. `10`)\n * @param position Byte position, where 0 is the least significant bit\n */\nexport function testBit(binaryValue: string, position: number): boolean {\n const { length } = binaryValue;\n\n if (position > length) {\n return false;\n }\n\n const positionInString = length - position;\n return binaryValue.substring(positionInString, positionInString + 1) === '1';\n}\n"]}
-1
View File
@@ -5,4 +5,3 @@ import * as helpers from './v6/helpers';
export declare const v6: {
helpers: typeof helpers;
};
//# sourceMappingURL=ip-address.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"ip-address.d.ts","sourceRoot":"","sources":["../src/ip-address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC,eAAO,MAAM,EAAE;;CAAc,CAAC"}
+1 -1
View File
@@ -1 +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"}
{"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"]}
+115 -57
View File
@@ -1,7 +1,6 @@
import * as common from './common';
/**
* Represents an IPv4 address
* @class Address4
* @param {string} address - An IPv4 address string
*/
export declare class Address4 {
@@ -13,43 +12,86 @@ export declare class Address4 {
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 correct form of an address
* @memberof Address4
* @instance
* @returns {String}
* Returns the address in correct form: octets joined with `.` and any
* leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
* canonical dotted-decimal representation.
*/
correctForm(): string;
/**
* Returns true if the address is correct, false otherwise
* @memberof Address4
* @instance
* @returns {Boolean}
*/
isCorrect: (this: Address4 | import("./ipv6").Address6) => boolean;
/**
* Converts a hex string to an IPv4 address object
* @memberof Address4
* @static
* Construct an `Address4` from an address and a dotted-decimal subnet
* mask given as separate strings (e.g. as returned by Node's
* `os.networkInterfaces()`). Throws `AddressError` if the mask is
* non-contiguous (e.g. `255.0.255.0`).
* @example
* var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
* address.subnetMask; // 24
*/
static fromAddressAndMask(address: 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
* @memberof Address4
* @static
* Converts an integer into a IPv4 address object. The integer must be a
* non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
* `AddressError` is thrown.
* @param {integer} integer - a number to convert
* @returns {Address4}
*/
static fromInteger(integer: number): Address4;
/**
* Return an address from in-addr.arpa form
* @memberof Address4
* @static
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
* @returns {Adress4}
* @example
@@ -59,98 +101,97 @@ export declare class Address4 {
static fromArpa(arpaFormAddress: string): Address4;
/**
* Converts an IPv4 address object to a hex string
* @memberof Address4
* @instance
* @returns {String}
*/
toHex(): string;
/**
* Converts an IPv4 address object to an array of bytes
* @memberof Address4
* @instance
* Converts an IPv4 address object to an array of bytes.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
* @returns {Array}
*/
toArray(): number[];
/**
* Converts an IPv4 address object to an IPv6 address group
* @memberof Address4
* @instance
* @returns {String}
*/
toGroup6(): string;
/**
* Returns the address as a `bigint`
* @memberof Address4
* @instance
* @returns {bigint}
*/
bigInt(): bigint;
/**
* Helper function getting start address.
* @memberof Address4
* @instance
* @returns {bigint}
*/
_startAddress(): bigint;
/**
* The first address in the range given by this address' subnet.
* Often referred to as the Network Address.
* @memberof Address4
* @instance
* @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
* @memberof Address4
* @instance
* @returns {Address4}
*/
startAddressExclusive(): Address4;
/**
* Helper function getting end address.
* @memberof Address4
* @instance
* @returns {bigint}
*/
_endAddress(): bigint;
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
* @memberof Address4
* @instance
* @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
* @memberof Address4
* @instance
* @returns {Address4}
*/
endAddressExclusive(): Address4;
/**
* Converts a BigInt to a v4 address object
* @memberof Address4
* @static
* The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
* a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
* @returns {Address4}
*/
subnetMaskAddress(): 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
* @memberof Address4
* @static
* Convert a byte array to an Address4 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
* @returns {Address4}
*/
static fromByteArray(bytes: Array<number>): Address4;
/**
* Convert an unsigned byte array to an Address4 object
* @memberof Address4
* @static
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
* @returns {Address4}
*/
@@ -158,45 +199,63 @@ export declare class Address4 {
/**
* Returns the first n bits of the address, defaulting to the
* subnet mask
* @memberof Address4
* @instance
* @returns {String}
*/
mask(mask?: number): string;
/**
* Returns the bits in the given range as a base-2 string
* @memberof Address4
* @instance
* @returns {string}
*/
getBitsBase2(start: number, end: number): string;
/**
* Return the reversed ip6.arpa form of the address
* @memberof Address4
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
* @instance
* @returns {String}
*/
reverseForm(options?: common.ReverseFormOptions): string;
/**
* Returns true if the given address is in the subnet of the current address
* @memberof Address4
* @instance
* @returns {boolean}
*/
isInSubnet: typeof common.isInSubnet;
/**
* Returns true if the given address is a multicast address
* @memberof Address4
* @instance
* @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 a zero-padded base-2 string representation of the address
* @memberof Address4
* @instance
* @returns {string}
*/
binaryZeroPad(): string;
@@ -206,4 +265,3 @@ export declare class Address4 {
*/
groupForV6(): string;
}
//# sourceMappingURL=ipv4.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"ipv4.d.ts","sourceRoot":"","sources":["../src/ipv4.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AAInC;;;;GAIG;AACH,qBAAa,QAAQ;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAoB;IAClC,aAAa,EAAE,MAAM,EAAE,CAAM;IAC7B,YAAY,EAAE,MAAM,CAAM;IAC1B,MAAM,EAAE,MAAM,CAAS;IACvB,UAAU,EAAE,MAAM,CAAM;IACxB,EAAE,EAAE,OAAO,CAAQ;gBAEP,OAAO,EAAE,MAAM;IAsB3B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAcxC,KAAK,CAAC,OAAO,EAAE,MAAM;IAUrB;;;;;OAKG;IACH,WAAW,IAAI,MAAM;IAIrB;;;;;OAKG;IACH,SAAS,0DAAoC;IAE7C;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAcrC;;;;;;OAMG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ;IAI7C;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,QAAQ;IASlD;;;;;OAKG;IACH,KAAK,IAAI,MAAM;IAIf;;;;;OAKG;IACH,OAAO,IAAI,MAAM,EAAE;IAInB;;;;;OAKG;IACH,QAAQ,IAAI,MAAM;IAelB;;;;;OAKG;IACH,MAAM,IAAI,MAAM;IAIhB;;;;;OAKG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;;;OAMG;IACH,YAAY,IAAI,QAAQ;IAIxB;;;;;;OAMG;IACH,qBAAqB,IAAI,QAAQ;IAKjC;;;;;OAKG;IACH,WAAW,IAAI,MAAM;IAIrB;;;;;;OAMG;IACH,UAAU,IAAI,QAAQ;IAItB;;;;;;OAMG;IACH,mBAAmB,IAAI,QAAQ;IAK/B;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAI3C;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,QAAQ;IAepD;;;;;;OAMG;IACH,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,QAAQ;IAS5D;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAQ3B;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIhD;;;;;;;OAOG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,kBAAkB,GAAG,MAAM;IAcxD;;;;;OAKG;IACH,UAAU,2BAAqB;IAE/B;;;;;OAKG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;OAKG;IACH,aAAa,IAAI,MAAM;IAIvB;;;OAGG;IACH,UAAU,IAAI,MAAM;CAYrB"}
+193 -68
View File
@@ -28,9 +28,9 @@ exports.Address4 = void 0;
const common = __importStar(require("./common"));
const constants = __importStar(require("./v4/constants"));
const address_error_1 = require("./address-error");
const isCorrect4 = common.isCorrect(constants.BITS);
/**
* Represents an IPv4 address
* @class Address4
* @param {string} address - An IPv4 address string
*/
class Address4 {
@@ -43,15 +43,11 @@ class Address4 {
this.v4 = true;
/**
* Returns true if the address is correct, false otherwise
* @memberof Address4
* @instance
* @returns {Boolean}
*/
this.isCorrect = common.isCorrect(constants.BITS);
this.isCorrect = isCorrect4;
/**
* Returns true if the given address is in the subnet of the current address
* @memberof Address4
* @instance
* @returns {boolean}
*/
this.isInSubnet = common.isInSubnet;
@@ -69,6 +65,13 @@ class Address4 {
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(address);
}
/**
* Returns true if the given string is a valid IPv4 address (with optional
* CIDR subnet), false otherwise. Host bits in the subnet portion are
* allowed (e.g. `192.168.1.5/24` is valid); for strict network-address
* validation compare `correctForm()` to `startAddress().correctForm()`,
* or use `networkForm()`.
*/
static isValid(address) {
try {
// eslint-disable-next-line no-new
@@ -79,8 +82,11 @@ class Address4 {
return false;
}
}
/*
* Parses a v4 address
/**
* Parses an IPv4 address string into its four octet groups and stores the
* result on `this.parsedAddress`. Called automatically by the constructor;
* you typically don't need to call it directly. Throws `AddressError` if
* the input is not a valid IPv4 address.
*/
parse(address) {
const groups = address.split('.');
@@ -90,45 +96,110 @@ class Address4 {
return groups;
}
/**
* Returns the correct form of an address
* @memberof Address4
* @instance
* @returns {String}
* Returns the address in correct form: octets joined with `.` and any
* leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
* canonical dotted-decimal representation.
*/
correctForm() {
return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
}
/**
* Converts a hex string to an IPv4 address object
* @memberof Address4
* @static
* Construct an `Address4` from an address and a dotted-decimal subnet
* mask given as separate strings (e.g. as returned by Node's
* `os.networkInterfaces()`). Throws `AddressError` if the mask is
* non-contiguous (e.g. `255.0.255.0`).
* @example
* var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
* address.subnetMask; // 24
*/
static fromAddressAndMask(address, mask) {
const bits = common.prefixLengthFromMask(new Address4(mask).bigInt(), constants.BITS);
return new Address4(`${address}/${bits}`);
}
/**
* Construct an `Address4` from an address and a Cisco-style wildcard mask
* given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard
* mask is the bitwise inverse of the subnet mask. Throws `AddressError`
* if the mask is non-contiguous (e.g. `0.255.0.255`).
* @example
* var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255');
* address.subnetMask; // 24
*/
static fromAddressAndWildcardMask(address, wildcardMask) {
const wildcard = new Address4(wildcardMask).bigInt();
const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
// eslint-disable-next-line no-bitwise
const mask = wildcard ^ allOnes;
const bits = common.prefixLengthFromMask(mask, constants.BITS);
return new Address4(`${address}/${bits}`);
}
/**
* Construct an `Address4` from a wildcard pattern with trailing `*`
* octets. The number of trailing wildcards determines the prefix
* length: each `*` represents 8 bits.
*
* Only trailing whole-octet wildcards are supported. Partial-octet
* wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g.
* `192.*.0.1`) throw `AddressError`.
* @example
* Address4.fromWildcard('192.168.0.*').subnet; // '/24'
* Address4.fromWildcard('192.168.*.*').subnet; // '/16'
* Address4.fromWildcard('*.*.*.*').subnet; // '/0'
*/
static fromWildcard(input) {
const groups = input.split('.');
if (groups.length !== constants.GROUPS) {
throw new address_error_1.AddressError('Wildcard pattern must have 4 octets');
}
let firstWildcard = -1;
for (let i = 0; i < groups.length; i++) {
if (groups[i] === '*') {
if (firstWildcard === -1) {
firstWildcard = i;
}
}
else if (firstWildcard !== -1) {
throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)');
}
}
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
const replaced = groups.map((g) => (g === '*' ? '0' : g));
const subnetBits = constants.BITS - trailing * 8;
return new Address4(`${replaced.join('.')}/${subnetBits}`);
}
/**
* Converts a hex string to an IPv4 address object. Accepts 8 hex digits
* with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`).
* Throws `AddressError` for any other length or for non-hex characters.
* @param {string} hex - a hex string to convert
* @returns {Address4}
*/
static fromHex(hex) {
const padded = hex.replace(/:/g, '').padStart(8, '0');
const stripped = hex.replace(/:/g, '');
if (!/^[0-9a-fA-F]{8}$/.test(stripped)) {
throw new address_error_1.AddressError('IPv4 hex must be exactly 8 hex digits');
}
const groups = [];
let i;
for (i = 0; i < 8; i += 2) {
const h = padded.slice(i, i + 2);
groups.push(parseInt(h, 16));
for (let i = 0; i < 8; i += 2) {
groups.push(parseInt(stripped.slice(i, i + 2), 16));
}
return new Address4(groups.join('.'));
}
/**
* Converts an integer into a IPv4 address object
* @memberof Address4
* @static
* Converts an integer into a IPv4 address object. The integer must be a
* non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
* `AddressError` is thrown.
* @param {integer} integer - a number to convert
* @returns {Address4}
*/
static fromInteger(integer) {
return Address4.fromHex(integer.toString(16));
if (!Number.isInteger(integer) || integer < 0 || integer > 0xffffffff) {
throw new address_error_1.AddressError('IPv4 integer must be in the range 0 to 2**32 - 1');
}
return Address4.fromHex(integer.toString(16).padStart(8, '0'));
}
/**
* Return an address from in-addr.arpa form
* @memberof Address4
* @static
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
* @returns {Adress4}
* @example
@@ -143,17 +214,15 @@ class Address4 {
}
/**
* Converts an IPv4 address object to a hex string
* @memberof Address4
* @instance
* @returns {String}
*/
toHex() {
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
}
/**
* Converts an IPv4 address object to an array of bytes
* @memberof Address4
* @instance
* Converts an IPv4 address object to an array of bytes.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
* @returns {Array}
*/
toArray() {
@@ -161,8 +230,6 @@ class Address4 {
}
/**
* Converts an IPv4 address object to an IPv6 address group
* @memberof Address4
* @instance
* @returns {String}
*/
toGroup6() {
@@ -175,8 +242,6 @@ class Address4 {
}
/**
* Returns the address as a `bigint`
* @memberof Address4
* @instance
* @returns {bigint}
*/
bigInt() {
@@ -184,8 +249,6 @@ class Address4 {
}
/**
* Helper function getting start address.
* @memberof Address4
* @instance
* @returns {bigint}
*/
_startAddress() {
@@ -194,8 +257,6 @@ class Address4 {
/**
* The first address in the range given by this address' subnet.
* Often referred to as the Network Address.
* @memberof Address4
* @instance
* @returns {Address4}
*/
startAddress() {
@@ -204,8 +265,6 @@ class Address4 {
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
* @memberof Address4
* @instance
* @returns {Address4}
*/
startAddressExclusive() {
@@ -214,8 +273,6 @@ class Address4 {
}
/**
* Helper function getting end address.
* @memberof Address4
* @instance
* @returns {bigint}
*/
_endAddress() {
@@ -224,8 +281,6 @@ class Address4 {
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
* @memberof Address4
* @instance
* @returns {Address4}
*/
endAddress() {
@@ -234,8 +289,6 @@ class Address4 {
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
* @memberof Address4
* @instance
* @returns {Address4}
*/
endAddressExclusive() {
@@ -243,19 +296,47 @@ class Address4 {
return Address4.fromBigInt(this._endAddress() - adjust);
}
/**
* Converts a BigInt to a v4 address object
* @memberof Address4
* @static
* The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
* a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
* @returns {Address4}
*/
subnetMaskAddress() {
return Address4.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants.BITS - this.subnetMask)}`));
}
/**
* The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
* the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`;
* call `.correctForm()` for the string.
* @returns {Address4}
*/
wildcardMask() {
return Address4.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants.BITS - this.subnetMask)}`));
}
/**
* The network address in CIDR string form, e.g. `192.168.1.0/24` for
* `192.168.1.5/24`. For an address with no explicit subnet the prefix is
* `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`.
* @returns {string}
*/
networkForm() {
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
}
/**
* Converts a BigInt to a v4 address object. The value must be in the
* range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address4}
*/
static fromBigInt(bigInt) {
return Address4.fromHex(bigInt.toString(16));
if (bigInt < 0n || bigInt > 0xffffffffn) {
throw new address_error_1.AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
}
return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
}
/**
* Convert a byte array to an Address4 object
* @memberof Address4
* @static
* Convert a byte array to an Address4 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
* @returns {Address4}
*/
@@ -273,8 +354,6 @@ class Address4 {
}
/**
* Convert an unsigned byte array to an Address4 object
* @memberof Address4
* @static
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
* @returns {Address4}
*/
@@ -288,8 +367,6 @@ class Address4 {
/**
* Returns the first n bits of the address, defaulting to the
* subnet mask
* @memberof Address4
* @instance
* @returns {String}
*/
mask(mask) {
@@ -300,8 +377,6 @@ class Address4 {
}
/**
* Returns the bits in the given range as a base-2 string
* @memberof Address4
* @instance
* @returns {string}
*/
getBitsBase2(start, end) {
@@ -309,10 +384,8 @@ class Address4 {
}
/**
* Return the reversed ip6.arpa form of the address
* @memberof Address4
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
* @instance
* @returns {String}
*/
reverseForm(options) {
@@ -327,21 +400,62 @@ class Address4 {
}
/**
* Returns true if the given address is a multicast address
* @memberof Address4
* @instance
* @returns {boolean}
*/
isMulticast() {
return this.isInSubnet(new Address4('224.0.0.0/4'));
return this.isInSubnet(MULTICAST_V4);
}
/**
* Returns true if the address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private address ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`).
* @returns {boolean}
*/
isPrivate() {
return PRIVATE_V4.some((subnet) => this.isInSubnet(subnet));
}
/**
* Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
* @returns {boolean}
*/
isLoopback() {
return this.isInSubnet(LOOPBACK_V4);
}
/**
* Returns true if the address is in the link-local range `169.254.0.0/16` ([RFC 3927](https://datatracker.ietf.org/doc/html/rfc3927)).
* @returns {boolean}
*/
isLinkLocal() {
return this.isInSubnet(LINK_LOCAL_V4);
}
/**
* Returns true if the address is the unspecified address `0.0.0.0`.
* @returns {boolean}
*/
isUnspecified() {
return this.isInSubnet(UNSPECIFIED_V4);
}
/**
* Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
* @returns {boolean}
*/
isBroadcast() {
return this.isInSubnet(BROADCAST_V4);
}
/**
* Returns true if the address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)).
* @returns {boolean}
*/
isCGNAT() {
return this.isInSubnet(CGNAT_V4);
}
/**
* Returns a zero-padded base-2 string representation of the address
* @memberof Address4
* @instance
* @returns {string}
*/
binaryZeroPad() {
return this.bigInt().toString(2).padStart(constants.BITS, '0');
if (this._binaryZeroPad === undefined) {
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, '0');
}
return this._binaryZeroPad;
}
/**
* Groups an IPv4 address for inclusion at the end of an IPv6 address
@@ -357,4 +471,15 @@ class Address4 {
}
}
exports.Address4 = Address4;
const MULTICAST_V4 = new Address4('224.0.0.0/4');
const PRIVATE_V4 = [
new Address4('10.0.0.0/8'),
new Address4('172.16.0.0/12'),
new Address4('192.168.0.0/16'),
];
const LOOPBACK_V4 = new Address4('127.0.0.0/8');
const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
const BROADCAST_V4 = new Address4('255.255.255.255/32');
const CGNAT_V4 = new Address4('100.64.0.0/10');
//# sourceMappingURL=ipv4.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
+172 -111
View File
@@ -20,7 +20,6 @@ interface TeredoProperties {
}
/**
* Represents an IPv6 address
* @class Address6
* @param {string} address - An IPv6 address string
* @param {number} [groups=8] - How many octets to parse
* @example
@@ -41,12 +40,19 @@ export declare class Address6 {
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
* @memberof Address6
* @static
* Convert a BigInt to a v6 address object. The value must be in the
* range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address6}
* @example
@@ -56,10 +62,10 @@ export declare class Address6 {
*/
static fromBigInt(bigInt: bigint): Address6;
/**
* Convert a URL (with optional port number) to an address object
* @memberof Address6
* @static
* @param {string} url - a URL with optional port number
* Parse a URL (with optional bracketed host and port) into an address and
* port. Returns either `{ address, port }` on success or
* `{ error, address: null, port: null }` if the URL could not be parsed.
* Ports are returned as numbers (or `null` if absent or out of range).
* @example
* var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
* addressAndPort.address.correctForm(); // 'ffff::'
@@ -74,10 +80,43 @@ export declare class 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
* @memberof Address6
* @static
* @param {string} address - An IPv4 address string
* @returns {Address6}
* @example
@@ -88,8 +127,6 @@ export declare class Address6 {
static fromAddress4(address: string): Address6;
/**
* Return an address from ip6.arpa form
* @memberof Address6
* @static
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
* @returns {Adress6}
* @example
@@ -99,135 +136,126 @@ export declare class Address6 {
static fromArpa(arpaFormAddress: string): Address6;
/**
* Return the Microsoft UNC transcription of the address
* @memberof Address6
* @instance
* @returns {String} the Microsoft UNC transcription of the address
*/
microsoftTranscription(): string;
/**
* Return the first n bits of the address, defaulting to the subnet mask
* @memberof Address6
* @instance
* @param {number} [mask=subnet] - the number of bits to mask
* @returns {String} the first n bits of the address as a string
*/
mask(mask?: number): string;
/**
* Return the number of possible subnets of a given size in the address
* @memberof Address6
* @instance
* @param {number} [subnetSize=128] - the subnet size
* @returns {String}
*/
possibleSubnets(subnetSize?: number): string;
/**
* Helper function getting start address.
* @memberof Address6
* @instance
* @returns {bigint}
*/
_startAddress(): bigint;
/**
* The first address in the range given by this address' subnet
* Often referred to as the Network Address.
* @memberof Address6
* @instance
* @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
* @memberof Address6
* @instance
* @returns {Address6}
*/
startAddressExclusive(): Address6;
/**
* Helper function getting end address.
* @memberof Address6
* @instance
* @returns {bigint}
*/
_endAddress(): bigint;
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
* @memberof Address6
* @instance
* @returns {Address6}
*/
endAddress(): Address6;
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
* @memberof Address6
* @instance
* @returns {Address6}
*/
endAddressExclusive(): Address6;
/**
* Return the scope of the address
* @memberof Address6
* @instance
* The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
* `/64`. Returns an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
subnetMaskAddress(): 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
* @memberof Address6
* @instance
* @returns {String}
*/
getType(): string;
/**
* Return the bits in the given range as a BigInt
* @memberof Address6
* @instance
* @returns {bigint}
*/
getBits(start: number, end: number): bigint;
/**
* Return the bits in the given range as a base-2 string
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsBase2(start: number, end: number): string;
/**
* Return the bits in the given range as a base-16 string
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsBase16(start: number, end: number): string;
/**
* Return the bits that are set past the subnet mask length
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsPastSubnet(): string;
/**
* Return the reversed ip6.arpa form of the address
* @memberof Address6
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
* @instance
* @returns {String}
*/
reverseForm(options?: common.ReverseFormOptions): string;
/**
* Return the correct form of the address
* @memberof Address6
* @instance
* @returns {String}
* Returns the address in correct form, per
* [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
* stripped, the longest run of zero groups collapsed to `::`, and hex digits
* lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
*/
correctForm(): string;
/**
* Return a zero-padded base-2 string representation of the address
* @memberof Address6
* @instance
* @returns {String}
* @example
* var address = new Address6('2001:4860:4001:803::1011');
@@ -236,33 +264,40 @@ export declare class Address6 {
* // 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[];
/**
* Return the canonical form of the address
* @memberof Address6
* @instance
* @returns {String}
* Returns the canonical (fully expanded) form of the address: all 8 groups,
* each padded to 4 hex digits, with no `::` collapsing
* (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
* byte-exact comparison.
*/
canonicalForm(): string;
/**
* Return the decimal form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
decimal(): string;
/**
* Return the address as a BigInt
* @memberof Address6
* @instance
* @returns {bigint}
*/
bigInt(): bigint;
/**
* Return the last two groups of this address as an IPv4 address string
* @memberof Address6
* @instance
* @returns {Address4}
* @example
* var address = new Address6('2001:4860:4001::1825:bf11');
@@ -271,129 +306,160 @@ export declare class Address6 {
to4(): Address4;
/**
* Return the v4-in-v6 form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
to4in6(): string;
/**
* Return an object containing the Teredo properties of the address
* @memberof Address6
* @instance
* @returns {Object}
* Decodes the Teredo tunneling fields embedded in this address. Returns the
* Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
* UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
* group/individual, nonce). Only meaningful for addresses in `2001::/32`.
*/
inspectTeredo(): TeredoProperties;
/**
* Return an object containing the 6to4 properties of the address
* @memberof Address6
* @instance
* @returns {Object}
* Decodes the 6to4 tunneling fields embedded in this address. Returns the
* 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
* addresses in `2002::/16`.
*/
inspect6to4(): SixToFourProperties;
/**
* Return a v6 6to4 address from a v6 v4inv6 address
* @memberof Address6
* @instance
* @returns {Address6}
*/
to6to4(): Address6 | null;
/**
* Return a byte array
* @memberof Address6
* @instance
* Embed an IPv4 address into a NAT64 IPv6 address using the encoding
* defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
* length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
* than /64 the IPv4 octets are split around the reserved bits 6471.
* @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
* @memberof Address6
* @instance
* 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
* @memberof Address6
* @static
* Convert a byte array to an Address6 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
* @returns {Address6}
*/
static fromByteArray(bytes: Array<any>): Address6;
/**
* Convert an unsigned byte array to an Address6 object
* @memberof Address6
* @static
* Convert an unsigned byte array to an Address6 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
* @returns {Address6}
*/
static fromUnsignedByteArray(bytes: Array<any>): Address6;
/**
* Returns true if the given address is in the subnet of the current address
* @memberof Address6
* @instance
* @returns {boolean}
*/
isInSubnet: typeof common.isInSubnet;
/**
* Returns true if the address is correct, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isCorrect: (this: Address4 | Address6) => boolean;
/**
* Returns true if the address is in the canonical form, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isCanonical(): boolean;
/**
* Returns true if the address is a link local address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isLinkLocal(): boolean;
/**
* Returns true if the address is a multicast address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isMulticast(): boolean;
/**
* Returns true if the address is a v4-in-v6 address, false otherwise
* @memberof Address6
* @instance
* Returns true if the address was written in v4-in-v6 dotted-quad notation
* (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
* and does not reflect whether the address bits lie in the IPv4-mapped
* (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
* @returns {boolean}
*/
is4(): 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;
/**
* Returns true if the address is a Teredo address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isTeredo(): boolean;
/**
* Returns true if the address is a 6to4 address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
is6to4(): boolean;
/**
* Returns true if the address is a loopback address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isLoopback(): boolean;
/**
* @returns {String} the address in link form with a default port of 80
* 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 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 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 {String} a link suitable for conveying the address via a URL hash
* Returns an HTML `<a>` element whose `href` encodes the address in a URL
* hash fragment (default prefix `/#address=`). Useful for linking between
* pages of an address-inspector UI.
* @param options.className - CSS class for the rendered `<a>` element
* @param options.prefix - hash prefix prepended to the address (default `/#address=`)
* @param options.v4 - when true, render the address in v4-in-v6 form
*/
link(options?: {
className?: string;
@@ -408,8 +474,6 @@ export declare class Address6 {
/**
* Generate a regular expression string that can be used to find or validate
* all variations of this address
* @memberof Address6
* @instance
* @param {boolean} substringSearch
* @returns {string}
*/
@@ -417,12 +481,9 @@ export declare class Address6 {
/**
* Generate a regular expression that can be used to find or validate all
* variations of this address.
* @memberof Address6
* @instance
* @param {boolean} substringSearch
* @returns {RegExp}
*/
regularExpression(this: Address6, substringSearch?: boolean): RegExp;
}
export {};
//# sourceMappingURL=ipv6.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"ipv6.d.ts","sourceRoot":"","sources":["../src/ipv6.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AAInC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AA4DlC,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,cAAc,EAAE,OAAO,CAAC;QACxB,eAAe,EAAE,OAAO,CAAC;QACzB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAM;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,CAAM;IAC1B,MAAM,EAAE,MAAM,CAAU;IACxB,UAAU,EAAE,MAAM,CAAO;IACzB,EAAE,EAAE,OAAO,CAAS;IACpB,IAAI,EAAE,MAAM,CAAM;gBAEN,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM;IA0CpD,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAWxC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAY3C;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM;;;;;;;;;IA4D1B;;;;;;;;;;OAUG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ;IAQ9C;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,QAAQ;IAsBlD;;;;;OAKG;IACH,sBAAsB,IAAI,MAAM;IAIhC;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,GAAE,MAAwB,GAAG,MAAM;IAI5C;;;;;;OAMG;IAEH,eAAe,CAAC,UAAU,GAAE,MAAY,GAAG,MAAM;IAYjD;;;;;OAKG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;;;OAMG;IACH,YAAY,IAAI,QAAQ;IAIxB;;;;;;OAMG;IACH,qBAAqB,IAAI,QAAQ;IAKjC;;;;;OAKG;IACH,WAAW,IAAI,MAAM;IAIrB;;;;;;OAMG;IACH,UAAU,IAAI,QAAQ;IAItB;;;;;;OAMG;IACH,mBAAmB,IAAI,QAAQ;IAK/B;;;;;OAKG;IACH,QAAQ,IAAI,MAAM;IAUlB;;;;;OAKG;IACH,OAAO,IAAI,MAAM;IAUjB;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAI3C;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIhD;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAYjD;;;;;OAKG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;;;;;;OAOG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,kBAAkB,GAAG,MAAM;IA6BxD;;;;;OAKG;IACH,WAAW,IAAI,MAAM;IAqDrB;;;;;;;;;;OAUG;IACH,aAAa,IAAI,MAAM;IAKvB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAiClC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IA0EhC;;;;;OAKG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;;OAKG;IACH,OAAO,IAAI,MAAM;IAIjB;;;;;OAKG;IACH,MAAM,IAAI,MAAM;IAIhB;;;;;;;;OAQG;IACH,GAAG,IAAI,QAAQ;IAMf;;;;;OAKG;IACH,MAAM,IAAI,MAAM;IAehB;;;;;OAKG;IACH,aAAa,IAAI,gBAAgB;IA0DjC;;;;;OAKG;IACH,WAAW,IAAI,mBAAmB;IAgBlC;;;;;OAKG;IACH,MAAM,IAAI,QAAQ,GAAG,IAAI;IAgBzB;;;;;OAKG;IACH,WAAW,IAAI,MAAM,EAAE;IAcvB;;;;;OAKG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAI/B;;;;;OAKG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ;IAIjD;;;;;OAKG;IACH,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ;IAezD;;;;;OAKG;IACH,UAAU,2BAAqB;IAE/B;;;;;OAKG;IACH,SAAS,yCAAqC;IAE9C;;;;;OAKG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;OAKG;IACH,WAAW,IAAI,OAAO;IAYtB;;;;;OAKG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;OAKG;IACH,GAAG,IAAI,OAAO;IAId;;;;;OAKG;IACH,QAAQ,IAAI,OAAO;IAInB;;;;;OAKG;IACH,MAAM,IAAI,OAAO;IAIjB;;;;;OAKG;IACH,UAAU,IAAI,OAAO;IAMrB;;OAEG;IACH,IAAI,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM;IAU5C;;OAEG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAgC7E;;;OAGG;IACH,KAAK,IAAI,MAAM;IA8Cf;;;;;;;OAOG;IACH,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,GAAE,OAAe,GAAG,MAAM;IAgDjF;;;;;;;OAOG;IACH,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,GAAE,OAAe,GAAG,MAAM;CAI5E"}
+345 -131
View File
@@ -34,6 +34,7 @@ const ipv4_1 = require("./ipv4");
const regular_expressions_1 = require("./v6/regular-expressions");
const address_error_1 = require("./address-error");
const common_1 = require("./common");
const isCorrect6 = common.isCorrect(constants6.BITS);
function assert(condition) {
if (!condition) {
throw new Error('Assertion failed.');
@@ -77,7 +78,6 @@ function unsignByte(b) {
}
/**
* Represents an IPv6 address
* @class Address6
* @param {string} address - An IPv6 address string
* @param {number} [groups=8] - How many octets to parse
* @example
@@ -94,18 +94,14 @@ class Address6 {
// #region Attributes
/**
* Returns true if the given address is in the subnet of the current address
* @memberof Address6
* @instance
* @returns {boolean}
*/
this.isInSubnet = common.isInSubnet;
/**
* Returns true if the address is correct, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
this.isCorrect = common.isCorrect(constants6.BITS);
this.isCorrect = isCorrect6;
if (optionalGroups === undefined) {
this.groups = constants6.GROUPS;
}
@@ -136,6 +132,13 @@ class Address6 {
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(this.addressMinusSuffix);
}
/**
* Returns true if the given string is a valid IPv6 address (with optional
* CIDR subnet and zone identifier), false otherwise. Host bits in the
* subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict
* network-address validation compare `correctForm()` to
* `startAddress().correctForm()`, or use `networkForm()`.
*/
static isValid(address) {
try {
// eslint-disable-next-line no-new
@@ -147,9 +150,8 @@ class Address6 {
}
}
/**
* Convert a BigInt to a v6 address object
* @memberof Address6
* @static
* Convert a BigInt to a v6 address object. The value must be in the
* range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address6}
* @example
@@ -158,19 +160,21 @@ class Address6 {
* address.correctForm(); // '::e8:d4a5:1000'
*/
static fromBigInt(bigInt) {
if (bigInt < 0n || bigInt > (1n << BigInt(constants6.BITS)) - 1n) {
throw new address_error_1.AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
}
const hex = bigInt.toString(16).padStart(32, '0');
const groups = [];
let i;
for (i = 0; i < constants6.GROUPS; i++) {
for (let i = 0; i < constants6.GROUPS; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
* Convert a URL (with optional port number) to an address object
* @memberof Address6
* @static
* @param {string} url - a URL with optional port number
* Parse a URL (with optional bracketed host and port) into an address and
* port. Returns either `{ address, port }` on success or
* `{ error, address: null, port: null }` if the URL could not be parsed.
* Ports are returned as numbers (or `null` if absent or out of range).
* @example
* var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
* addressAndPort.address.correctForm(); // 'ffff::'
@@ -229,10 +233,92 @@ class Address6 {
port,
};
}
/**
* Construct an `Address6` from an address and a hex subnet mask given as
* separate strings (e.g. as returned by Node's `os.networkInterfaces()`).
* Throws `AddressError` if the mask is non-contiguous (e.g.
* `ffff::ffff`).
* @example
* var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::');
* address.subnetMask; // 64
*/
static fromAddressAndMask(address, mask) {
const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
return new Address6(`${address}/${bits}`);
}
/**
* Construct an `Address6` from an address and a Cisco-style wildcard mask
* given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`).
* The wildcard mask is the bitwise inverse of the subnet mask. Throws
* `AddressError` if the mask is non-contiguous.
* @example
* var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff');
* address.subnetMask; // 64
*/
static fromAddressAndWildcardMask(address, wildcardMask) {
const wildcard = new Address6(wildcardMask).bigInt();
const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
// eslint-disable-next-line no-bitwise
const mask = wildcard ^ allOnes;
const bits = common.prefixLengthFromMask(mask, constants6.BITS);
return new Address6(`${address}/${bits}`);
}
/**
* Construct an `Address6` from a wildcard pattern with trailing `*`
* groups. The number of trailing wildcards determines the prefix
* length: each `*` represents 16 bits. `::` is expanded to zero groups
* (not wildcards) before evaluating trailing wildcards.
*
* Only trailing whole-group wildcards are supported. Partial-group
* wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g.
* `*::1`) throw `AddressError`.
* @example
* Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32'
* Address6.fromWildcard('2001:db8::*').subnet; // '/112'
* Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0'
*/
static fromWildcard(input) {
if (input.includes('%') || input.includes('/')) {
throw new address_error_1.AddressError('Wildcard pattern must not include a zone or CIDR suffix');
}
const halves = input.split('::');
if (halves.length > 2) {
throw new address_error_1.AddressError("Wildcard pattern cannot contain more than one '::'");
}
let groups;
if (halves.length === 2) {
const left = halves[0] === '' ? [] : halves[0].split(':');
const right = halves[1] === '' ? [] : halves[1].split(':');
const remaining = constants6.GROUPS - left.length - right.length;
if (remaining < 1) {
throw new address_error_1.AddressError("Wildcard pattern with '::' has too many groups");
}
groups = [...left, ...new Array(remaining).fill('0'), ...right];
}
else {
groups = input.split(':');
}
if (groups.length !== constants6.GROUPS) {
throw new address_error_1.AddressError('Wildcard pattern must have 8 groups');
}
let firstWildcard = -1;
for (let i = 0; i < groups.length; i++) {
if (groups[i] === '*') {
if (firstWildcard === -1) {
firstWildcard = i;
}
}
else if (firstWildcard !== -1) {
throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)');
}
}
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
const replaced = groups.map((g) => (g === '*' ? '0' : g));
const subnetBits = constants6.BITS - trailing * 16;
return new Address6(`${replaced.join(':')}/${subnetBits}`);
}
/**
* Create an IPv6-mapped address given an IPv4 address
* @memberof Address6
* @static
* @param {string} address - An IPv4 address string
* @returns {Address6}
* @example
@@ -247,8 +333,6 @@ class Address6 {
}
/**
* Return an address from ip6.arpa form
* @memberof Address6
* @static
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
* @returns {Adress6}
* @example
@@ -273,8 +357,6 @@ class Address6 {
}
/**
* Return the Microsoft UNC transcription of the address
* @memberof Address6
* @instance
* @returns {String} the Microsoft UNC transcription of the address
*/
microsoftTranscription() {
@@ -282,8 +364,6 @@ class Address6 {
}
/**
* Return the first n bits of the address, defaulting to the subnet mask
* @memberof Address6
* @instance
* @param {number} [mask=subnet] - the number of bits to mask
* @returns {String} the first n bits of the address as a string
*/
@@ -292,8 +372,6 @@ class Address6 {
}
/**
* Return the number of possible subnets of a given size in the address
* @memberof Address6
* @instance
* @param {number} [subnetSize=128] - the subnet size
* @returns {String}
*/
@@ -309,8 +387,6 @@ class Address6 {
}
/**
* Helper function getting start address.
* @memberof Address6
* @instance
* @returns {bigint}
*/
_startAddress() {
@@ -319,8 +395,6 @@ class Address6 {
/**
* The first address in the range given by this address' subnet
* Often referred to as the Network Address.
* @memberof Address6
* @instance
* @returns {Address6}
*/
startAddress() {
@@ -329,8 +403,6 @@ class Address6 {
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
* @memberof Address6
* @instance
* @returns {Address6}
*/
startAddressExclusive() {
@@ -339,8 +411,6 @@ class Address6 {
}
/**
* Helper function getting end address.
* @memberof Address6
* @instance
* @returns {bigint}
*/
_endAddress() {
@@ -349,8 +419,6 @@ class Address6 {
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
* @memberof Address6
* @instance
* @returns {Address6}
*/
endAddress() {
@@ -359,8 +427,6 @@ class Address6 {
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
* @memberof Address6
* @instance
* @returns {Address6}
*/
endAddressExclusive() {
@@ -368,36 +434,73 @@ class Address6 {
return Address6.fromBigInt(this._endAddress() - adjust);
}
/**
* Return the scope of the address
* @memberof Address6
* @instance
* The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
* `/64`. Returns an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
subnetMaskAddress() {
return Address6.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`));
}
/**
* The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a
* `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns
* an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
wildcardMask() {
return Address6.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`));
}
/**
* The network address in CIDR string form, e.g. `2001:db8::/32` for
* `2001:db8::1/32`. For an address with no explicit subnet the prefix
* is `/128`, e.g. `networkForm()` on `2001:db8::1` returns
* `2001:db8::1/128`.
* @returns {string}
*/
networkForm() {
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
}
/**
* Return the scope of the address. The 4-bit scope field
* ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7))
* is only defined for multicast addresses; for unicast addresses the scope
* is derived from the address type per
* [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6).
* @returns {String}
*/
getScope() {
let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
if (this.getType() === 'Global unicast' && scope !== 'Link local') {
scope = 'Global';
const type = this.getType();
if (type === 'Multicast' || type.startsWith('Multicast ')) {
const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
return scope || 'Unknown';
}
return scope || 'Unknown';
// RFC 4291 §2.5.3: the loopback address is treated as having Link-Local
// scope. (Multicast scope 1, "Interface-Local", is a different concept
// used only for loopback transmission of multicast.)
if (type === 'Link-local unicast' || type === 'Loopback') {
return 'Link local';
}
// RFC 4007 §6: the unspecified address has no scope.
if (type === 'Unspecified') {
return 'Unknown';
}
return 'Global';
}
/**
* Return the type of the address
* @memberof Address6
* @instance
* @returns {String}
*/
getType() {
for (const subnet of Object.keys(constants6.TYPES)) {
if (this.isInSubnet(new Address6(subnet))) {
return constants6.TYPES[subnet];
for (let i = 0; i < TYPE_SUBNETS.length; i++) {
const entry = TYPE_SUBNETS[i];
if (this.isInSubnet(entry[0])) {
return entry[1];
}
}
return 'Global unicast';
}
/**
* Return the bits in the given range as a BigInt
* @memberof Address6
* @instance
* @returns {bigint}
*/
getBits(start, end) {
@@ -405,8 +508,6 @@ class Address6 {
}
/**
* Return the bits in the given range as a base-2 string
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsBase2(start, end) {
@@ -414,8 +515,6 @@ class Address6 {
}
/**
* Return the bits in the given range as a base-16 string
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsBase16(start, end) {
@@ -429,8 +528,6 @@ class Address6 {
}
/**
* Return the bits that are set past the subnet mask length
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsPastSubnet() {
@@ -438,10 +535,8 @@ class Address6 {
}
/**
* Return the reversed ip6.arpa form of the address
* @memberof Address6
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
* @instance
* @returns {String}
*/
reverseForm(options) {
@@ -467,10 +562,10 @@ class Address6 {
return 'ip6.arpa.';
}
/**
* Return the correct form of the address
* @memberof Address6
* @instance
* @returns {String}
* Returns the address in correct form, per
* [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
* stripped, the longest run of zero groups collapsed to `::`, and hex digits
* lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
*/
correctForm() {
let i;
@@ -514,8 +609,6 @@ class Address6 {
}
/**
* Return a zero-padded base-2 string representation of the address
* @memberof Address6
* @instance
* @returns {String}
* @example
* var address = new Address6('2001:4860:4001:803::1011');
@@ -524,10 +617,22 @@ class Address6 {
* // 0000000000000000000000000000000000000000000000000001000000010001'
*/
binaryZeroPad() {
return this.bigInt().toString(2).padStart(constants6.BITS, '0');
if (this._binaryZeroPad === undefined) {
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
}
return this._binaryZeroPad;
}
/**
* Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the
* trailing IPv4 address into `this.address4` / `this.parsedAddress4` and
* returning the address with the v4 portion converted to two v6 groups.
* Used internally by `parse()`.
*/
// TODO: Improve the semantics of this helper function
parse4in6(address) {
if (address.indexOf('.') === -1) {
return address;
}
const groups = address.split(':');
const lastGroup = groups.slice(-1)[0];
const address4 = lastGroup.match(constants4.RE_ADDRESS);
@@ -536,7 +641,12 @@ class Address6 {
this.address4 = new ipv4_1.Address4(this.parsedAddress4);
for (let i = 0; i < this.address4.groups; i++) {
if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join('.')));
// The prefix groups haven't been through the bad-character check
// yet, so escape them before including in the error HTML.
const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join('.');
const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
const separator = groups.length > 1 ? ':' : '';
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`);
}
}
this.v4 = true;
@@ -545,6 +655,13 @@ class Address6 {
}
return address;
}
/**
* Parses an IPv6 address string into its 8 hexadecimal groups (expanding
* any `::` elision and any trailing v4-in-v6 portion) and stores the result
* on `this.parsedAddress`. Called automatically by the constructor; you
* typically don't need to call it directly. Throws `AddressError` if the
* input is malformed.
*/
// TODO: Make private?
parse(address) {
address = this.parse4in6(address);
@@ -594,18 +711,16 @@ class Address6 {
return groups;
}
/**
* Return the canonical form of the address
* @memberof Address6
* @instance
* @returns {String}
* Returns the canonical (fully expanded) form of the address: all 8 groups,
* each padded to 4 hex digits, with no `::` collapsing
* (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
* byte-exact comparison.
*/
canonicalForm() {
return this.parsedAddress.map(paddedHex).join(':');
}
/**
* Return the decimal form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
decimal() {
@@ -613,8 +728,6 @@ class Address6 {
}
/**
* Return the address as a BigInt
* @memberof Address6
* @instance
* @returns {bigint}
*/
bigInt() {
@@ -622,8 +735,6 @@ class Address6 {
}
/**
* Return the last two groups of this address as an IPv4 address string
* @memberof Address6
* @instance
* @returns {Address4}
* @example
* var address = new Address6('2001:4860:4001::1825:bf11');
@@ -631,12 +742,10 @@ class Address6 {
*/
to4() {
const binary = this.binaryZeroPad().split('');
return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16));
return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16).padStart(8, '0'));
}
/**
* Return the v4-in-v6 form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
to4in6() {
@@ -650,10 +759,10 @@ class Address6 {
return correct + infix + address4.address;
}
/**
* Return an object containing the Teredo properties of the address
* @memberof Address6
* @instance
* @returns {Object}
* Decodes the Teredo tunneling fields embedded in this address. Returns the
* Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
* UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
* group/individual, nonce). Only meaningful for addresses in `2001::/32`.
*/
inspectTeredo() {
/*
@@ -684,7 +793,7 @@ class Address6 {
const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
const bitsForClient4 = this.getBits(96, 128);
// eslint-disable-next-line no-bitwise
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16));
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'));
const flagsBase2 = this.getBitsBase2(64, 80);
const coneNat = (0, common_1.testBit)(flagsBase2, 15);
const reserved = (0, common_1.testBit)(flagsBase2, 14);
@@ -707,10 +816,9 @@ class Address6 {
};
}
/**
* Return an object containing the 6to4 properties of the address
* @memberof Address6
* @instance
* @returns {Object}
* Decodes the 6to4 tunneling fields embedded in this address. Returns the
* 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
* addresses in `2002::/16`.
*/
inspect6to4() {
/*
@@ -726,8 +834,6 @@ class Address6 {
}
/**
* Return a v6 6to4 address from a v6 v4inv6 address
* @memberof Address6
* @instance
* @returns {Address6}
*/
to6to4() {
@@ -744,9 +850,80 @@ class Address6 {
return new Address6(addr6to4);
}
/**
* Return a byte array
* @memberof Address6
* @instance
* Embed an IPv4 address into a NAT64 IPv6 address using the encoding
* defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
* length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
* than /64 the IPv4 octets are split around the reserved bits 6471.
* @example
* Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221'
* Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::'
*/
static fromAddress4Nat64(address, prefix = '64:ff9b::/96') {
const v4 = new ipv4_1.Address4(address);
const prefix6 = new Address6(prefix);
const pl = prefix6.subnetMask;
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
}
const prefixBits = prefix6.binaryZeroPad();
const v4Bits = v4.binaryZeroPad();
let bits;
if (pl === 96) {
bits = prefixBits.slice(0, 96) + v4Bits;
}
else {
const beforeU = 64 - pl;
bits =
prefixBits.slice(0, pl) +
v4Bits.slice(0, beforeU) +
'00000000' +
v4Bits.slice(beforeU) +
'0'.repeat(128 - 72 - (32 - beforeU));
}
const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
const groups = [];
for (let i = 0; i < 8; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
* Extract the embedded IPv4 address from a NAT64 IPv6 address using the
* encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. Returns
* `null` if this address is not contained within the given prefix.
* @example
* new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33'
*/
toAddress4Nat64(prefix = '64:ff9b::/96') {
const prefix6 = new Address6(prefix);
const pl = prefix6.subnetMask;
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
}
if (!this.isInSubnet(prefix6)) {
return null;
}
const bits = this.binaryZeroPad();
let v4Bits;
if (pl === 96) {
v4Bits = bits.slice(96, 128);
}
else {
const beforeU = 64 - pl;
v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU));
}
const octets = [];
for (let i = 0; i < 4; i++) {
octets.push(parseInt(v4Bits.slice(i * 8, (i + 1) * 8), 2).toString());
}
return new ipv4_1.Address4(octets.join('.'));
}
/**
* Return a byte array.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
* @returns {Array}
*/
toByteArray() {
@@ -760,27 +937,27 @@ class Address6 {
return bytes;
}
/**
* Return an unsigned byte array
* @memberof Address6
* @instance
* Return an unsigned byte array.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
* @returns {Array}
*/
toUnsignedByteArray() {
return this.toByteArray().map(unsignByte);
}
/**
* Convert a byte array to an Address6 object
* @memberof Address6
* @static
* Convert a byte array to an Address6 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
* @returns {Address6}
*/
static fromByteArray(bytes) {
return this.fromUnsignedByteArray(bytes.map(unsignByte));
}
/**
* Convert an unsigned byte array to an Address6 object
* @memberof Address6
* @static
* Convert an unsigned byte array to an Address6 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
* @returns {Address6}
*/
static fromUnsignedByteArray(bytes) {
@@ -795,8 +972,6 @@ class Address6 {
}
/**
* Returns true if the address is in the canonical form, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isCanonical() {
@@ -804,8 +979,6 @@ class Address6 {
}
/**
* Returns true if the address is a link local address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isLinkLocal() {
@@ -818,53 +991,81 @@ class Address6 {
}
/**
* Returns true if the address is a multicast address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isMulticast() {
return this.getType() === 'Multicast';
const type = this.getType();
return type === 'Multicast' || type.startsWith('Multicast ');
}
/**
* Returns true if the address is a v4-in-v6 address, false otherwise
* @memberof Address6
* @instance
* Returns true if the address was written in v4-in-v6 dotted-quad notation
* (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
* and does not reflect whether the address bits lie in the IPv4-mapped
* (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
* @returns {boolean}
*/
is4() {
return this.v4;
}
/**
* Returns true if the address is an IPv4-mapped IPv6 address in
* `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)),
* false otherwise. Unlike {@link is4}, this checks the underlying address
* bits rather than the textual notation, so `::ffff:127.0.0.1` and
* `::ffff:7f00:1` both return true.
* @returns {boolean}
*/
isMapped4() {
return this.isInSubnet(IPV4_MAPPED_SUBNET);
}
/**
* Returns true if the address is a Teredo address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isTeredo() {
return this.isInSubnet(new Address6('2001::/32'));
return this.isInSubnet(TEREDO_SUBNET);
}
/**
* Returns true if the address is a 6to4 address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
is6to4() {
return this.isInSubnet(new Address6('2002::/16'));
return this.isInSubnet(SIX_TO_FOUR_SUBNET);
}
/**
* Returns true if the address is a loopback address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isLoopback() {
return this.getType() === 'Loopback';
}
/**
* Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses.
* @returns {boolean}
*/
isULA() {
return this.isInSubnet(ULA_SUBNET);
}
/**
* Returns true if the address is the unspecified address `::`.
* @returns {boolean}
*/
isUnspecified() {
return this.getType() === 'Unspecified';
}
/**
* Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)).
* @returns {boolean}
*/
isDocumentation() {
return this.isInSubnet(DOCUMENTATION_SUBNET);
}
// #endregion
// #region HTML
/**
* @returns {String} the address in link form with a default port of 80
* Returns the address as an HTTP URL with the host bracketed, e.g.
* `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended,
* e.g. `http://[2001:db8::1]:8080/`.
*/
href(optionalPort) {
if (optionalPort === undefined) {
@@ -876,7 +1077,12 @@ class Address6 {
return `http://[${this.correctForm()}]${optionalPort}/`;
}
/**
* @returns {String} a link suitable for conveying the address via a URL hash
* Returns an HTML `<a>` element whose `href` encodes the address in a URL
* hash fragment (default prefix `/#address=`). Useful for linking between
* pages of an address-inspector UI.
* @param options.className - CSS class for the rendered `<a>` element
* @param options.prefix - hash prefix prepended to the address (default `/#address=`)
* @param options.v4 - when true, render the address in v4-in-v6 form
*/
link(options) {
if (!options) {
@@ -896,10 +1102,13 @@ class Address6 {
formFunction = this.to4in6;
}
const form = formFunction.call(this);
const safeHref = helpers.escapeHtml(`${options.prefix}${form}`);
const safeForm = helpers.escapeHtml(form);
if (options.className) {
return `<a href="${options.prefix}${form}" class="${options.className}">${form}</a>`;
const safeClass = helpers.escapeHtml(options.className);
return `<a href="${safeHref}" class="${safeClass}">${safeForm}</a>`;
}
return `<a href="${options.prefix}${form}">${form}</a>`;
return `<a href="${safeHref}">${safeForm}</a>`;
}
/**
* Groups an address
@@ -908,13 +1117,13 @@ class Address6 {
group() {
if (this.elidedGroups === 0) {
// The simple case
return helpers.simpleGroup(this.address).join(':');
return helpers.simpleGroup(this.addressMinusSuffix).join(':');
}
assert(typeof this.elidedGroups === 'number');
assert(typeof this.elisionBegin === 'number');
// The elided case
const output = [];
const [left, right] = this.address.split('::');
const [left, right] = this.addressMinusSuffix.split('::');
if (left.length) {
output.push(...helpers.simpleGroup(left));
}
@@ -944,8 +1153,6 @@ class Address6 {
/**
* Generate a regular expression string that can be used to find or validate
* all variations of this address
* @memberof Address6
* @instance
* @param {boolean} substringSearch
* @returns {string}
*/
@@ -990,8 +1197,6 @@ class Address6 {
/**
* Generate a regular expression that can be used to find or validate all
* variations of this address.
* @memberof Address6
* @instance
* @param {boolean} substringSearch
* @returns {RegExp}
*/
@@ -1000,4 +1205,13 @@ class Address6 {
}
}
exports.Address6 = Address6;
const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [
new Address6(subnet),
constants6.TYPES[subnet],
]);
const TEREDO_SUBNET = new Address6('2001::/32');
const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
const ULA_SUBNET = new Address6('fc00::/7');
const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
//# sourceMappingURL=ipv6.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
-1
View File
@@ -2,4 +2,3 @@ export declare const BITS = 32;
export declare const GROUPS = 4;
export declare const RE_ADDRESS: RegExp;
export declare const RE_SUBNET_STRING: RegExp;
//# sourceMappingURL=constants.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/v4/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,KAAK,CAAC;AACvB,eAAO,MAAM,MAAM,IAAI,CAAC;AAExB,eAAO,MAAM,UAAU,QAC8I,CAAC;AAEtK,eAAO,MAAM,gBAAgB,QAAe,CAAC"}
+1 -1
View File
@@ -1 +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;AAEX,QAAA,UAAU,GACrB,mKAAmK,CAAC;AAEzJ,QAAA,gBAAgB,GAAG,YAAY,CAAC"}
{"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;AAEX,QAAA,UAAU,GACrB,mKAAmK,CAAC;AAEzJ,QAAA,gBAAgB,GAAG,YAAY,CAAC","sourcesContent":["export const BITS = 32;\nexport const GROUPS = 4;\n\nexport const RE_ADDRESS =\n /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/g;\n\nexport const RE_SUBNET_STRING = /\\/\\d{1,2}$/;\n"]}
-1
View File
@@ -42,4 +42,3 @@ export declare const RE_SUBNET_STRING: RegExp;
export declare const RE_ZONE_STRING: RegExp;
export declare const RE_URL: RegExp;
export declare const RE_URL_WITH_PORT: RegExp;
//# sourceMappingURL=constants.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/v6/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,MAAM,CAAC;AACxB,eAAO,MAAM,MAAM,IAAI,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAS9C,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,KAAK,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAuB7C,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAqB,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAA6C,CAAC;AAEzE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAqB,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC,eAAO,MAAM,MAAM,QAAgC,CAAC;AACpD,eAAO,MAAM,gBAAgB,QAAkC,CAAC"}
+5
View File
@@ -46,6 +46,11 @@ exports.TYPES = {
'::1/128': 'Loopback',
'ff00::/8': 'Multicast',
'fe80::/10': 'Link-local unicast',
'fc00::/7': 'Unique local',
'2002::/16': '6to4',
'2001:db8::/32': 'Documentation',
'64:ff9b::/96': 'NAT64 (well-known)',
'64:ff9b:1::/48': 'NAT64 (local-use)',
};
/**
* A regular expression that matches bad characters in an IPv6 address
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/v6/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,IAAI,GAAG,GAAG,CAAC;AACX,QAAA,MAAM,GAAG,CAAC,CAAC;AAExB;;;;GAIG;AACU,QAAA,MAAM,GAA0C;IAC3D,CAAC,EAAE,UAAU;IACb,CAAC,EAAE,iBAAiB;IACpB,CAAC,EAAE,YAAY;IACf,CAAC,EAAE,aAAa;IAChB,CAAC,EAAE,YAAY;IACf,CAAC,EAAE,oBAAoB;IACvB,EAAE,EAAE,QAAQ;IACZ,EAAE,EAAE,UAAU;CACN,CAAC;AAEX;;;;GAIG;AACU,QAAA,KAAK,GAA0C;IAC1D,aAAa,EAAE,yCAAyC;IACxD,aAAa,EAAE,2CAA2C;IAC1D,aAAa,EAAE,oCAAoC;IACnD,aAAa,EAAE,sCAAsC;IACrD,aAAa,EAAE,sCAAsC;IACrD,aAAa,EAAE,mCAAmC;IAClD,aAAa,EAAE,kCAAkC;IACjD,aAAa,EAAE,yBAAyB;IACxC,aAAa,EAAE,2BAA2B;IAC1C,aAAa,EAAE,yBAAyB;IACxC,cAAc,EAAE,2BAA2B;IAC3C,cAAc,EAAE,oBAAoB;IACpC,cAAc,EAAE,oBAAoB;IACpC,cAAc,EAAE,oBAAoB;IACpC,eAAe,EAAE,4DAA4D;IAC7E,eAAe,EAAE,4DAA4D;IAC7E,eAAe,EAAE,2CAA2C;IAC5D,eAAe,EAAE,2CAA2C;IAC5D,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,UAAU;IACrB,UAAU,EAAE,WAAW;IACvB,WAAW,EAAE,oBAAoB;CACzB,CAAC;AAEX;;;;GAIG;AACU,QAAA,iBAAiB,GAAG,kBAAkB,CAAC;AAEpD;;;;GAIG;AACU,QAAA,cAAc,GAAG,0CAA0C,CAAC;AAEzE;;;;GAIG;AACU,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AAEnD;;;;GAIG;AACU,QAAA,cAAc,GAAG,MAAM,CAAC;AAExB,QAAA,MAAM,GAAG,6BAA6B,CAAC;AACvC,QAAA,gBAAgB,GAAG,+BAA+B,CAAC"}
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/v6/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,IAAI,GAAG,GAAG,CAAC;AACX,QAAA,MAAM,GAAG,CAAC,CAAC;AAExB;;;;GAIG;AACU,QAAA,MAAM,GAA0C;IAC3D,CAAC,EAAE,UAAU;IACb,CAAC,EAAE,iBAAiB;IACpB,CAAC,EAAE,YAAY;IACf,CAAC,EAAE,aAAa;IAChB,CAAC,EAAE,YAAY;IACf,CAAC,EAAE,oBAAoB;IACvB,EAAE,EAAE,QAAQ;IACZ,EAAE,EAAE,UAAU;CACN,CAAC;AAEX;;;;GAIG;AACU,QAAA,KAAK,GAA0C;IAC1D,aAAa,EAAE,yCAAyC;IACxD,aAAa,EAAE,2CAA2C;IAC1D,aAAa,EAAE,oCAAoC;IACnD,aAAa,EAAE,sCAAsC;IACrD,aAAa,EAAE,sCAAsC;IACrD,aAAa,EAAE,mCAAmC;IAClD,aAAa,EAAE,kCAAkC;IACjD,aAAa,EAAE,yBAAyB;IACxC,aAAa,EAAE,2BAA2B;IAC1C,aAAa,EAAE,yBAAyB;IACxC,cAAc,EAAE,2BAA2B;IAC3C,cAAc,EAAE,oBAAoB;IACpC,cAAc,EAAE,oBAAoB;IACpC,cAAc,EAAE,oBAAoB;IACpC,eAAe,EAAE,4DAA4D;IAC7E,eAAe,EAAE,4DAA4D;IAC7E,eAAe,EAAE,2CAA2C;IAC5D,eAAe,EAAE,2CAA2C;IAC5D,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,UAAU;IACrB,UAAU,EAAE,WAAW;IACvB,WAAW,EAAE,oBAAoB;IACjC,UAAU,EAAE,cAAc;IAC1B,WAAW,EAAE,MAAM;IACnB,eAAe,EAAE,eAAe;IAChC,cAAc,EAAE,oBAAoB;IACpC,gBAAgB,EAAE,mBAAmB;CAC7B,CAAC;AAEX;;;;GAIG;AACU,QAAA,iBAAiB,GAAG,kBAAkB,CAAC;AAEpD;;;;GAIG;AACU,QAAA,cAAc,GAAG,0CAA0C,CAAC;AAEzE;;;;GAIG;AACU,QAAA,gBAAgB,GAAG,kBAAkB,CAAC;AAEnD;;;;GAIG;AACU,QAAA,cAAc,GAAG,MAAM,CAAC;AAExB,QAAA,MAAM,GAAG,6BAA6B,CAAC;AACvC,QAAA,gBAAgB,GAAG,+BAA+B,CAAC","sourcesContent":["export const BITS = 128;\nexport const GROUPS = 8;\n\n/**\n * Represents IPv6 address scopes\n * @memberof Address6\n * @static\n */\nexport const SCOPES: { [key: number]: string | undefined } = {\n 0: 'Reserved',\n 1: 'Interface local',\n 2: 'Link local',\n 4: 'Admin local',\n 5: 'Site local',\n 8: 'Organization local',\n 14: 'Global',\n 15: 'Reserved',\n} as const;\n\n/**\n * Represents IPv6 address types\n * @memberof Address6\n * @static\n */\nexport const TYPES: { [key: string]: string | undefined } = {\n 'ff01::1/128': 'Multicast (All nodes on this interface)',\n 'ff01::2/128': 'Multicast (All routers on this interface)',\n 'ff02::1/128': 'Multicast (All nodes on this link)',\n 'ff02::2/128': 'Multicast (All routers on this link)',\n 'ff05::2/128': 'Multicast (All routers in this site)',\n 'ff02::5/128': 'Multicast (OSPFv3 AllSPF routers)',\n 'ff02::6/128': 'Multicast (OSPFv3 AllDR routers)',\n 'ff02::9/128': 'Multicast (RIP routers)',\n 'ff02::a/128': 'Multicast (EIGRP routers)',\n 'ff02::d/128': 'Multicast (PIM routers)',\n 'ff02::16/128': 'Multicast (MLDv2 reports)',\n 'ff01::fb/128': 'Multicast (mDNSv6)',\n 'ff02::fb/128': 'Multicast (mDNSv6)',\n 'ff05::fb/128': 'Multicast (mDNSv6)',\n 'ff02::1:2/128': 'Multicast (All DHCP servers and relay agents on this link)',\n 'ff05::1:2/128': 'Multicast (All DHCP servers and relay agents in this site)',\n 'ff02::1:3/128': 'Multicast (All DHCP servers on this link)',\n 'ff05::1:3/128': 'Multicast (All DHCP servers in this site)',\n '::/128': 'Unspecified',\n '::1/128': 'Loopback',\n 'ff00::/8': 'Multicast',\n 'fe80::/10': 'Link-local unicast',\n 'fc00::/7': 'Unique local',\n '2002::/16': '6to4',\n '2001:db8::/32': 'Documentation',\n '64:ff9b::/96': 'NAT64 (well-known)',\n '64:ff9b:1::/48': 'NAT64 (local-use)',\n} as const;\n\n/**\n * A regular expression that matches bad characters in an IPv6 address\n * @memberof Address6\n * @static\n */\nexport const RE_BAD_CHARACTERS = /([^0-9a-f:/%])/gi;\n\n/**\n * A regular expression that matches an incorrect IPv6 address\n * @memberof Address6\n * @static\n */\nexport const RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]|\\/$)/gi;\n\n/**\n * A regular expression that matches an IPv6 subnet\n * @memberof Address6\n * @static\n */\nexport const RE_SUBNET_STRING = /\\/\\d{1,3}(?=%|$)/;\n\n/**\n * A regular expression that matches an IPv6 zone\n * @memberof Address6\n * @static\n */\nexport const RE_ZONE_STRING = /%.*$/;\n\nexport const RE_URL = /^\\[{0,1}([0-9a-f:]+)\\]{0,1}/;\nexport const RE_URL_WITH_PORT = /\\[([0-9a-f:]+)\\]:([0-9]{1,5})/;\n"]}
+1 -1
View File
@@ -1,3 +1,4 @@
export declare function escapeHtml(s: string): string;
/**
* @returns {String} the string with all zeroes contained in a <span>
*/
@@ -15,4 +16,3 @@ export declare function spanLeadingZeroes(address: string): string;
* @returns {String} a grouped address
*/
export declare function simpleGroup(addressString: string, offset?: number): string[];
//# sourceMappingURL=helpers.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/v6/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,CAQ7D;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM,EAAE,CAU/E"}
+12 -3
View File
@@ -1,14 +1,23 @@
"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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
/**
* @returns {String} the string with all zeroes contained in a <span>
*/
function spanAllZeroes(s) {
return s.replace(/(0+)/g, '<span class="zero">$1</span>');
return escapeHtml(s).replace(/(0+)/g, '<span class="zero">$1</span>');
}
/**
* @returns {String} the string with each character contained in a <span>
@@ -16,11 +25,11 @@ function spanAllZeroes(s) {
function spanAll(s, offset = 0) {
const letters = s.split('');
return letters
.map((n, i) => `<span class="digit value-${n} position-${i + offset}">${spanAllZeroes(n)}</span>`)
.map((n, i) => `<span class="digit value-${escapeHtml(n)} position-${i + offset}">${spanAllZeroes(n)}</span>`)
.join('');
}
function spanLeadingZeroesSimple(group) {
return group.replace(/^(0+)/, '<span class="zero">$1</span>');
return escapeHtml(group).replace(/^(0+)/, '<span class="zero">$1</span>');
}
/**
* @returns {String} the string with leading zeroes contained in a <span>
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/v6/helpers.ts"],"names":[],"mappings":";;AAGA,sCAEC;AAKD,0BAQC;AASD,8CAIC;AAMD,kCAUC;AA/CD;;GAEG;AACH,SAAgB,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;AAC5D,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,CAAC,4BAA4B,CAAC,aAAa,CAAC,GAAG,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,SAAS,CAC7F;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAa;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;AAChE,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"}
{"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, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\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"]}
-1
View File
@@ -3,4 +3,3 @@ 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;
//# sourceMappingURL=regular-expressions.d.ts.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"regular-expressions.d.ts","sourceRoot":"","sources":["../../src/v6/regular-expressions.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAElE;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,UA+BvD;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,OAAO,EAClB,SAAS,CAAC,EAAE,OAAO,GAClB,MAAM,CAwCR"}
File diff suppressed because one or more lines are too long
+45 -35
View File
@@ -2,77 +2,87 @@
"name": "ip-address",
"description": "A library for parsing IPv4 and IPv6 IP addresses in node and the browser.",
"keywords": [
"ipv6",
"ip",
"ipv4",
"browser",
"validation"
"ipv6",
"address",
"cidr",
"subnet",
"netmask",
"validate",
"validation",
"parse",
"arpa",
"bigint",
"browser"
],
"version": "10.1.0",
"version": "10.2.0",
"author": "Beau Gunderson <beau@beaugunderson.com> (https://beaugunderson.com/)",
"license": "MIT",
"main": "dist/ip-address.js",
"types": "dist/ip-address.d.ts",
"scripts": {
"docs": "documentation build --github --output docs --format html ./ip-address.js",
"docs": "tsx scripts/build-readme.ts",
"build": "rm -rf dist; mkdir dist; tsc",
"prepack": "npm run build",
"release": "release-it",
"test-ci": "nyc mocha",
"prepack": "npm run docs && npm run build",
"test-ci": "c8 --experimental-monocart mocha",
"test": "mocha",
"watch": "mocha --watch"
},
"nyc": {
"extension": [
".ts"
"c8": {
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts",
".eslintrc.js",
"coverage/",
"dist/",
"test/",
"tmp/"
"src/ip-address.ts",
"src/v4/constants.ts",
"src/v6/constants.ts"
],
"reporter": [
"html",
"lcov",
"text"
],
"all": true
]
},
"engines": {
"node": ">= 12"
},
"sideEffects": false,
"files": [
"src",
"dist"
],
"repository": {
"type": "git",
"url": "git://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.0.0",
"@types/mocha": "^10.0.8",
"@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/parser": "^8.8.0",
"chai": "^5.1.1",
"documentation": "^14.0.3",
"eslint": "^8.50.0",
"@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": "^19.0.4",
"eslint-config-prettier": "^9.1.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-jsx-a11y": "^6.10.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
"mocha": "^10.7.3",
"nyc": "^17.1.0",
"prettier": "^3.3.3",
"release-it": "^17.6.0",
"mocha": "^11.7.5",
"monocart-coverage-reports": "^2.12.11",
"prettier": "^3.8.3",
"source-map-support": "^0.5.21",
"tsx": "^4.19.1",
"tsx": "^4.21.0",
"typedoc": "^0.28.19",
"typescript": "<5.6.0"
}
}
-11
View File
@@ -1,11 +0,0 @@
export class AddressError extends Error {
parseMessage?: string;
constructor(message: string, parseMessage?: string) {
super(message);
this.name = 'AddressError';
this.parseMessage = parseMessage;
}
}
-55
View File
@@ -1,55 +0,0 @@
import { Address4 } from './ipv4';
import { Address6 } from './ipv6';
export interface ReverseFormOptions {
omitSuffix?: boolean;
}
export function isInSubnet(this: Address4 | Address6, address: Address4 | Address6) {
if (this.subnetMask < address.subnetMask) {
return false;
}
if (this.mask(address.subnetMask) === address.mask()) {
return true;
}
return false;
}
export function isCorrect(defaultBits: number) {
return function (this: Address4 | Address6) {
if (this.addressMinusSuffix !== this.correctForm()) {
return false;
}
if (this.subnetMask === defaultBits && !this.parsedSubnet) {
return true;
}
return this.parsedSubnet === String(this.subnetMask);
};
}
export function numberToPaddedHex(number: number) {
return number.toString(16).padStart(2, '0');
}
export function stringToPaddedHex(numberString: string) {
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
*/
export function testBit(binaryValue: string, position: number): boolean {
const { length } = binaryValue;
if (position > length) {
return false;
}
const positionInString = length - position;
return binaryValue.substring(positionInString, positionInString + 1) === '1';
}
-7
View File
@@ -1,7 +0,0 @@
export { Address4 } from './ipv4';
export { Address6 } from './ipv6';
export { AddressError } from './address-error';
import * as helpers from './v6/helpers';
export const v6 = { helpers };
-394
View File
@@ -1,394 +0,0 @@
/* eslint-disable no-param-reassign */
import * as common from './common';
import * as constants from './v4/constants';
import { AddressError } from './address-error';
/**
* Represents an IPv4 address
* @class Address4
* @param {string} address - An IPv4 address string
*/
export class Address4 {
address: string;
addressMinusSuffix?: string;
groups: number = constants.GROUPS;
parsedAddress: string[] = [];
parsedSubnet: string = '';
subnet: string = '/32';
subnetMask: number = 32;
v4: boolean = true;
constructor(address: string) {
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 AddressError('Invalid subnet mask.');
}
address = address.replace(constants.RE_SUBNET_STRING, '');
}
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(address);
}
static isValid(address: string): boolean {
try {
// eslint-disable-next-line no-new
new Address4(address);
return true;
} catch (e) {
return false;
}
}
/*
* Parses a v4 address
*/
parse(address: string) {
const groups = address.split('.');
if (!address.match(constants.RE_ADDRESS)) {
throw new AddressError('Invalid IPv4 address.');
}
return groups;
}
/**
* Returns the correct form of an address
* @memberof Address4
* @instance
* @returns {String}
*/
correctForm(): string {
return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
}
/**
* Returns true if the address is correct, false otherwise
* @memberof Address4
* @instance
* @returns {Boolean}
*/
isCorrect = common.isCorrect(constants.BITS);
/**
* Converts a hex string to an IPv4 address object
* @memberof Address4
* @static
* @param {string} hex - a hex string to convert
* @returns {Address4}
*/
static fromHex(hex: string): Address4 {
const padded = hex.replace(/:/g, '').padStart(8, '0');
const groups = [];
let i;
for (i = 0; i < 8; i += 2) {
const h = padded.slice(i, i + 2);
groups.push(parseInt(h, 16));
}
return new Address4(groups.join('.'));
}
/**
* Converts an integer into a IPv4 address object
* @memberof Address4
* @static
* @param {integer} integer - a number to convert
* @returns {Address4}
*/
static fromInteger(integer: number): Address4 {
return Address4.fromHex(integer.toString(16));
}
/**
* Return an address from in-addr.arpa form
* @memberof Address4
* @static
* @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 {
// remove ending ".in-addr.arpa." or just "."
const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.$/, '');
const address = leader.split('.').reverse().join('.');
return new Address4(address);
}
/**
* Converts an IPv4 address object to a hex string
* @memberof Address4
* @instance
* @returns {String}
*/
toHex(): string {
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
}
/**
* Converts an IPv4 address object to an array of bytes
* @memberof Address4
* @instance
* @returns {Array}
*/
toArray(): number[] {
return this.parsedAddress.map((part) => parseInt(part, 10));
}
/**
* Converts an IPv4 address object to an IPv6 address group
* @memberof Address4
* @instance
* @returns {String}
*/
toGroup6(): string {
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`
* @memberof Address4
* @instance
* @returns {bigint}
*/
bigInt(): bigint {
return BigInt(`0x${this.parsedAddress.map((n) => common.stringToPaddedHex(n)).join('')}`);
}
/**
* Helper function getting start address.
* @memberof Address4
* @instance
* @returns {bigint}
*/
_startAddress(): bigint {
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.
* @memberof Address4
* @instance
* @returns {Address4}
*/
startAddress(): Address4 {
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
* @memberof Address4
* @instance
* @returns {Address4}
*/
startAddressExclusive(): Address4 {
const adjust = BigInt('1');
return Address4.fromBigInt(this._startAddress() + adjust);
}
/**
* Helper function getting end address.
* @memberof Address4
* @instance
* @returns {bigint}
*/
_endAddress(): bigint {
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
* @memberof Address4
* @instance
* @returns {Address4}
*/
endAddress(): Address4 {
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
* @memberof Address4
* @instance
* @returns {Address4}
*/
endAddressExclusive(): Address4 {
const adjust = BigInt('1');
return Address4.fromBigInt(this._endAddress() - adjust);
}
/**
* Converts a BigInt to a v4 address object
* @memberof Address4
* @static
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address4}
*/
static fromBigInt(bigInt: bigint): Address4 {
return Address4.fromHex(bigInt.toString(16));
}
/**
* Convert a byte array to an Address4 object
* @memberof Address4
* @static
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
* @returns {Address4}
*/
static fromByteArray(bytes: Array<number>): Address4 {
if (bytes.length !== 4) {
throw new AddressError('IPv4 addresses require exactly 4 bytes');
}
// Validate that all bytes are within valid range (0-255)
for (let i = 0; i < bytes.length; i++) {
if (!Number.isInteger(bytes[i]) || bytes[i] < 0 || bytes[i] > 255) {
throw new AddressError('All bytes must be integers between 0 and 255');
}
}
return this.fromUnsignedByteArray(bytes);
}
/**
* Convert an unsigned byte array to an Address4 object
* @memberof Address4
* @static
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
* @returns {Address4}
*/
static fromUnsignedByteArray(bytes: Array<number>): Address4 {
if (bytes.length !== 4) {
throw new 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
* @memberof Address4
* @instance
* @returns {String}
*/
mask(mask?: number): string {
if (mask === undefined) {
mask = this.subnetMask;
}
return this.getBitsBase2(0, mask);
}
/**
* Returns the bits in the given range as a base-2 string
* @memberof Address4
* @instance
* @returns {string}
*/
getBitsBase2(start: number, end: number): string {
return this.binaryZeroPad().slice(start, end);
}
/**
* Return the reversed ip6.arpa form of the address
* @memberof Address4
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
* @instance
* @returns {String}
*/
reverseForm(options?: common.ReverseFormOptions): string {
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 in the subnet of the current address
* @memberof Address4
* @instance
* @returns {boolean}
*/
isInSubnet = common.isInSubnet;
/**
* Returns true if the given address is a multicast address
* @memberof Address4
* @instance
* @returns {boolean}
*/
isMulticast(): boolean {
return this.isInSubnet(new Address4('224.0.0.0/4'));
}
/**
* Returns a zero-padded base-2 string representation of the address
* @memberof Address4
* @instance
* @returns {string}
*/
binaryZeroPad(): string {
return this.bigInt().toString(2).padStart(constants.BITS, '0');
}
/**
* Groups an IPv4 address for inclusion at the end of an IPv6 address
* @returns {String}
*/
groupForV6(): string {
const segments = this.parsedAddress;
return this.address.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>`,
);
}
}
-1212
View File
File diff suppressed because it is too large Load Diff
-7
View File
@@ -1,7 +0,0 @@
export const BITS = 32;
export const GROUPS = 4;
export const RE_ADDRESS =
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/g;
export const RE_SUBNET_STRING = /\/\d{1,2}$/;
-79
View File
@@ -1,79 +0,0 @@
export const BITS = 128;
export const GROUPS = 8;
/**
* Represents IPv6 address scopes
* @memberof Address6
* @static
*/
export const SCOPES: { [key: number]: string | undefined } = {
0: 'Reserved',
1: 'Interface local',
2: 'Link local',
4: 'Admin local',
5: 'Site local',
8: 'Organization local',
14: 'Global',
15: 'Reserved',
} as const;
/**
* Represents IPv6 address types
* @memberof Address6
* @static
*/
export const TYPES: { [key: string]: string | undefined } = {
'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',
'ff00::/8': 'Multicast',
'fe80::/10': 'Link-local unicast',
} as const;
/**
* A regular expression that matches bad characters in an IPv6 address
* @memberof Address6
* @static
*/
export const RE_BAD_CHARACTERS = /([^0-9a-f:/%])/gi;
/**
* A regular expression that matches an incorrect IPv6 address
* @memberof Address6
* @static
*/
export const RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]|\/$)/gi;
/**
* A regular expression that matches an IPv6 subnet
* @memberof Address6
* @static
*/
export const RE_SUBNET_STRING = /\/\d{1,3}(?=%|$)/;
/**
* A regular expression that matches an IPv6 zone
* @memberof Address6
* @static
*/
export const RE_ZONE_STRING = /%.*$/;
export const RE_URL = /^\[{0,1}([0-9a-f:]+)\]{0,1}/;
export const RE_URL_WITH_PORT = /\[([0-9a-f:]+)\]:([0-9]{1,5})/;
-48
View File
@@ -1,48 +0,0 @@
/**
* @returns {String} the string with all zeroes contained in a <span>
*/
export function spanAllZeroes(s: string): string {
return s.replace(/(0+)/g, '<span class="zero">$1</span>');
}
/**
* @returns {String} the string with each character contained in a <span>
*/
export function spanAll(s: string, offset: number = 0): string {
const letters = s.split('');
return letters
.map(
(n, i) => `<span class="digit value-${n} position-${i + offset}">${spanAllZeroes(n)}</span>`,
)
.join('');
}
function spanLeadingZeroesSimple(group: string): string {
return group.replace(/^(0+)/, '<span class="zero">$1</span>');
}
/**
* @returns {String} the string with leading zeroes contained in a <span>
*/
export function spanLeadingZeroes(address: string): string {
const groups = address.split(':');
return groups.map((g) => spanLeadingZeroesSimple(g)).join(':');
}
/**
* Groups an address
* @returns {String} a grouped address
*/
export function simpleGroup(addressString: string, offset: number = 0): string[] {
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>`;
});
}
-94
View File
@@ -1,94 +0,0 @@
import * as v6 from './constants';
export function groupPossibilities(possibilities: string[]): string {
return `(${possibilities.join('|')})`;
}
export function padGroup(group: string): string {
if (group.length < 4) {
return `0{0,${4 - group.length}}${group}`;
}
return group;
}
export const ADDRESS_BOUNDARY = '[^A-Fa-f0-9:]';
export function simpleRegularExpression(groups: string[]) {
const zeroIndexes: number[] = [];
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);
}
export function possibleElisions(
elidedGroups: number,
moreLeft?: boolean,
moreRight?: boolean,
): string {
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);
}