| "use strict";
|
|
|
|
|
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
| if (k2 === undefined) k2 = k;
|
| var desc = Object.getOwnPropertyDescriptor(m, k);
|
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
| desc = { enumerable: true, get: function() { return m[k]; } };
|
| }
|
| Object.defineProperty(o, k2, desc);
|
| }) : (function(o, m, k, k2) {
|
| if (k2 === undefined) k2 = k;
|
| o[k2] = m[k];
|
| }));
|
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
| Object.defineProperty(o, "default", { enumerable: true, value: v });
|
| }) : function(o, v) {
|
| o["default"] = v;
|
| });
|
| var __importStar = (this && this.__importStar) || function (mod) {
|
| if (mod && mod.__esModule) return mod;
|
| var result = {};
|
| if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
| __setModuleDefault(result, mod);
|
| return result;
|
| };
|
| Object.defineProperty(exports, "__esModule", { value: true });
|
| exports.Address6 = void 0;
|
| const common = __importStar(require("./common"));
|
| const constants4 = __importStar(require("./v4/constants"));
|
| const constants6 = __importStar(require("./v6/constants"));
|
| const helpers = __importStar(require("./v6/helpers"));
|
| 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.');
|
| }
|
| }
|
| function addCommas(number) {
|
| const r = /(\d+)(\d{3})/;
|
| while (r.test(number)) {
|
| number = number.replace(r, '$1,$2');
|
| }
|
| return number;
|
| }
|
| function spanLeadingZeroes4(n) {
|
| n = n.replace(/^(0{1,})([1-9]+)$/, '<span class="parse-error">$1</span>$2');
|
| n = n.replace(/^(0{1,})(0)$/, '<span class="parse-error">$1</span>$2');
|
| return n;
|
| }
|
| |
| |
|
|
| function compact(address, slice) {
|
| const s1 = [];
|
| const s2 = [];
|
| let i;
|
| for (i = 0; i < address.length; i++) {
|
| if (i < slice[0]) {
|
| s1.push(address[i]);
|
| }
|
| else if (i > slice[1]) {
|
| s2.push(address[i]);
|
| }
|
| }
|
| return s1.concat(['compact']).concat(s2);
|
| }
|
| function paddedHex(octet) {
|
| return parseInt(octet, 16).toString(16).padStart(4, '0');
|
| }
|
| function unsignByte(b) {
|
|
|
| return b & 0xff;
|
| }
|
| |
| |
| |
| |
| |
| |
|
|
| class Address6 {
|
| constructor(address, optionalGroups) {
|
| this.addressMinusSuffix = '';
|
| this.parsedSubnet = '';
|
| this.subnet = '/128';
|
| this.subnetMask = 128;
|
| this.v4 = false;
|
| this.zone = '';
|
|
|
| |
| |
| |
|
|
| this.isInSubnet = common.isInSubnet;
|
| |
| |
| |
|
|
| this.isCorrect = isCorrect6;
|
| if (optionalGroups === undefined) {
|
| this.groups = constants6.GROUPS;
|
| }
|
| else {
|
| this.groups = optionalGroups;
|
| }
|
| this.address = address;
|
| const subnet = constants6.RE_SUBNET_STRING.exec(address);
|
| if (subnet) {
|
| this.parsedSubnet = subnet[0].replace('/', '');
|
| this.subnetMask = parseInt(this.parsedSubnet, 10);
|
| this.subnet = `/${this.subnetMask}`;
|
| if (Number.isNaN(this.subnetMask) ||
|
| this.subnetMask < 0 ||
|
| this.subnetMask > constants6.BITS) {
|
| throw new address_error_1.AddressError('Invalid subnet mask.');
|
| }
|
| address = address.replace(constants6.RE_SUBNET_STRING, '');
|
| }
|
| else if (/\//.test(address)) {
|
| throw new address_error_1.AddressError('Invalid subnet mask.');
|
| }
|
| const zone = constants6.RE_ZONE_STRING.exec(address);
|
| if (zone) {
|
| this.zone = zone[0];
|
| address = address.replace(constants6.RE_ZONE_STRING, '');
|
| }
|
| this.addressMinusSuffix = address;
|
| this.parsedAddress = this.parse(this.addressMinusSuffix);
|
| }
|
| |
| |
| |
| |
| |
| |
|
|
| static isValid(address) {
|
| try {
|
|
|
| new Address6(address);
|
| return true;
|
| }
|
| catch (e) {
|
| return false;
|
| }
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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 = [];
|
| for (let i = 0; i < constants6.GROUPS; i++) {
|
| groups.push(hex.slice(i * 4, (i + 1) * 4));
|
| }
|
| return new Address6(groups.join(':'));
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| static fromURL(url) {
|
| let host;
|
| let port = null;
|
| let result;
|
|
|
| if (url.indexOf('[') !== -1 && url.indexOf(']:') !== -1) {
|
| result = constants6.RE_URL_WITH_PORT.exec(url);
|
| if (result === null) {
|
| return {
|
| error: 'failed to parse address with port',
|
| address: null,
|
| port: null,
|
| };
|
| }
|
| host = result[1];
|
| port = result[2];
|
|
|
| }
|
| else if (url.indexOf('/') !== -1) {
|
|
|
| url = url.replace(/^[a-z0-9]+:\/\//, '');
|
|
|
| result = constants6.RE_URL.exec(url);
|
| if (result === null) {
|
| return {
|
| error: 'failed to parse address from URL',
|
| address: null,
|
| port: null,
|
| };
|
| }
|
| host = result[1];
|
|
|
| }
|
| else {
|
| host = url;
|
| }
|
|
|
| if (port) {
|
| port = parseInt(port, 10);
|
|
|
| if (port < 0 || port > 65536) {
|
| port = null;
|
| }
|
| }
|
| else {
|
|
|
| port = null;
|
| }
|
| return {
|
| address: new Address6(host),
|
| port,
|
| };
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| static fromAddressAndMask(address, mask) {
|
| const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
|
| return new Address6(`${address}/${bits}`);
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| static fromAddressAndWildcardMask(address, wildcardMask) {
|
| const wildcard = new Address6(wildcardMask).bigInt();
|
| const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
|
|
|
| const mask = wildcard ^ allOnes;
|
| const bits = common.prefixLengthFromMask(mask, constants6.BITS);
|
| return new Address6(`${address}/${bits}`);
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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}`);
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| static fromAddress4(address) {
|
| const address4 = new ipv4_1.Address4(address);
|
| const mask6 = constants6.BITS - (constants4.BITS - address4.subnetMask);
|
| return new Address6(`::ffff:${address4.correctForm()}/${mask6}`);
|
| }
|
| |
| |
| |
| |
| |
| |
| |
|
|
| static fromArpa(arpaFormAddress) {
|
|
|
| let address = arpaFormAddress.replace(/(\.ip6\.arpa)?\.$/, '');
|
| const semicolonAmount = 7;
|
|
|
| if (address.length !== 63) {
|
| throw new address_error_1.AddressError("Invalid 'ip6.arpa' form.");
|
| }
|
| const parts = address.split('.').reverse();
|
| for (let i = semicolonAmount; i > 0; i--) {
|
| const insertIndex = i * 4;
|
| parts.splice(insertIndex, 0, ':');
|
| }
|
| address = parts.join('');
|
| return new Address6(address);
|
| }
|
| |
| |
| |
|
|
| microsoftTranscription() {
|
| return `${this.correctForm().replace(/:/g, '-')}.ipv6-literal.net`;
|
| }
|
| |
| |
| |
| |
|
|
| mask(mask = this.subnetMask) {
|
| return this.getBitsBase2(0, mask);
|
| }
|
| |
| |
| |
| |
|
|
|
|
| possibleSubnets(subnetSize = 128) {
|
| const availableBits = constants6.BITS - this.subnetMask;
|
| const subnetBits = Math.abs(subnetSize - constants6.BITS);
|
| const subnetPowers = availableBits - subnetBits;
|
| if (subnetPowers < 0) {
|
| return '0';
|
| }
|
| return addCommas((BigInt('2') ** BigInt(subnetPowers)).toString(10));
|
| }
|
| |
| |
| |
|
|
| _startAddress() {
|
| return BigInt(`0b${this.mask() + '0'.repeat(constants6.BITS - this.subnetMask)}`);
|
| }
|
| |
| |
| |
| |
|
|
| startAddress() {
|
| return Address6.fromBigInt(this._startAddress());
|
| }
|
| |
| |
| |
| |
|
|
| startAddressExclusive() {
|
| const adjust = BigInt('1');
|
| return Address6.fromBigInt(this._startAddress() + adjust);
|
| }
|
| |
| |
| |
|
|
| _endAddress() {
|
| return BigInt(`0b${this.mask() + '1'.repeat(constants6.BITS - this.subnetMask)}`);
|
| }
|
| |
| |
| |
| |
|
|
| endAddress() {
|
| return Address6.fromBigInt(this._endAddress());
|
| }
|
| |
| |
| |
| |
|
|
| endAddressExclusive() {
|
| const adjust = BigInt('1');
|
| return Address6.fromBigInt(this._endAddress() - adjust);
|
| }
|
| |
| |
| |
| |
|
|
| subnetMaskAddress() {
|
| return Address6.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`));
|
| }
|
| |
| |
| |
| |
| |
|
|
| wildcardMask() {
|
| return Address6.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`));
|
| }
|
| |
| |
| |
| |
| |
| |
|
|
| networkForm() {
|
| return `${this.startAddress().correctForm()}/${this.subnetMask}`;
|
| }
|
| |
| |
| |
| |
| |
| |
| |
|
|
| getScope() {
|
| 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';
|
| }
|
|
|
|
|
|
|
| if (type === 'Link-local unicast' || type === 'Loopback') {
|
| return 'Link local';
|
| }
|
|
|
| if (type === 'Unspecified') {
|
| return 'Unknown';
|
| }
|
| return 'Global';
|
| }
|
| |
| |
| |
|
|
| getType() {
|
| 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';
|
| }
|
| |
| |
| |
|
|
| getBits(start, end) {
|
| return BigInt(`0b${this.getBitsBase2(start, end)}`);
|
| }
|
| |
| |
| |
|
|
| getBitsBase2(start, end) {
|
| return this.binaryZeroPad().slice(start, end);
|
| }
|
| |
| |
| |
|
|
| getBitsBase16(start, end) {
|
| const length = end - start;
|
| if (length % 4 !== 0) {
|
| throw new Error('Length of bits to retrieve must be divisible by four');
|
| }
|
| return this.getBits(start, end)
|
| .toString(16)
|
| .padStart(length / 4, '0');
|
| }
|
| |
| |
| |
|
|
| getBitsPastSubnet() {
|
| return this.getBitsBase2(this.subnetMask, constants6.BITS);
|
| }
|
| |
| |
| |
| |
| |
|
|
| reverseForm(options) {
|
| if (!options) {
|
| options = {};
|
| }
|
| const characters = Math.floor(this.subnetMask / 4);
|
| const reversed = this.canonicalForm()
|
| .replace(/:/g, '')
|
| .split('')
|
| .slice(0, characters)
|
| .reverse()
|
| .join('.');
|
| if (characters > 0) {
|
| if (options.omitSuffix) {
|
| return reversed;
|
| }
|
| return `${reversed}.ip6.arpa.`;
|
| }
|
| if (options.omitSuffix) {
|
| return '';
|
| }
|
| return 'ip6.arpa.';
|
| }
|
| |
| |
| |
| |
| |
|
|
| correctForm() {
|
| let i;
|
| let groups = [];
|
| let zeroCounter = 0;
|
| const zeroes = [];
|
| for (i = 0; i < this.parsedAddress.length; i++) {
|
| const value = parseInt(this.parsedAddress[i], 16);
|
| if (value === 0) {
|
| zeroCounter++;
|
| }
|
| if (value !== 0 && zeroCounter > 0) {
|
| if (zeroCounter > 1) {
|
| zeroes.push([i - zeroCounter, i - 1]);
|
| }
|
| zeroCounter = 0;
|
| }
|
| }
|
|
|
| if (zeroCounter > 1) {
|
| zeroes.push([this.parsedAddress.length - zeroCounter, this.parsedAddress.length - 1]);
|
| }
|
| const zeroLengths = zeroes.map((n) => n[1] - n[0] + 1);
|
| if (zeroes.length > 0) {
|
| const index = zeroLengths.indexOf(Math.max(...zeroLengths));
|
| groups = compact(this.parsedAddress, zeroes[index]);
|
| }
|
| else {
|
| groups = this.parsedAddress;
|
| }
|
| for (i = 0; i < groups.length; i++) {
|
| if (groups[i] !== 'compact') {
|
| groups[i] = parseInt(groups[i], 16).toString(16);
|
| }
|
| }
|
| let correct = groups.join(':');
|
| correct = correct.replace(/^compact$/, '::');
|
| correct = correct.replace(/(^compact)|(compact$)/, ':');
|
| correct = correct.replace(/compact/, '');
|
| return correct;
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| binaryZeroPad() {
|
| if (this._binaryZeroPad === undefined) {
|
| this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
|
| }
|
| return this._binaryZeroPad;
|
| }
|
| |
| |
| |
| |
| |
|
|
|
|
| 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);
|
| if (address4) {
|
| this.parsedAddress4 = address4[0];
|
| 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])) {
|
|
|
|
|
| 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;
|
| groups[groups.length - 1] = this.address4.toGroup6();
|
| address = groups.join(':');
|
| }
|
| return address;
|
| }
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| parse(address) {
|
| address = this.parse4in6(address);
|
| const badCharacters = address.match(constants6.RE_BAD_CHARACTERS);
|
| if (badCharacters) {
|
| throw new address_error_1.AddressError(`Bad character${badCharacters.length > 1 ? 's' : ''} detected in address: ${badCharacters.join('')}`, address.replace(constants6.RE_BAD_CHARACTERS, '<span class="parse-error">$1</span>'));
|
| }
|
| const badAddress = address.match(constants6.RE_BAD_ADDRESS);
|
| if (badAddress) {
|
| throw new address_error_1.AddressError(`Address failed regex: ${badAddress.join('')}`, address.replace(constants6.RE_BAD_ADDRESS, '<span class="parse-error">$1</span>'));
|
| }
|
| let groups = [];
|
| const halves = address.split('::');
|
| if (halves.length === 2) {
|
| let first = halves[0].split(':');
|
| let last = halves[1].split(':');
|
| if (first.length === 1 && first[0] === '') {
|
| first = [];
|
| }
|
| if (last.length === 1 && last[0] === '') {
|
| last = [];
|
| }
|
| const remaining = this.groups - (first.length + last.length);
|
| if (!remaining) {
|
| throw new address_error_1.AddressError('Error parsing groups');
|
| }
|
| this.elidedGroups = remaining;
|
| this.elisionBegin = first.length;
|
| this.elisionEnd = first.length + this.elidedGroups;
|
| groups = groups.concat(first);
|
| for (let i = 0; i < remaining; i++) {
|
| groups.push('0');
|
| }
|
| groups = groups.concat(last);
|
| }
|
| else if (halves.length === 1) {
|
| groups = address.split(':');
|
| this.elidedGroups = 0;
|
| }
|
| else {
|
| throw new address_error_1.AddressError('Too many :: groups found');
|
| }
|
| groups = groups.map((group) => parseInt(group, 16).toString(16));
|
| if (groups.length !== this.groups) {
|
| throw new address_error_1.AddressError('Incorrect number of groups found');
|
| }
|
| return groups;
|
| }
|
| |
| |
| |
| |
| |
|
|
| canonicalForm() {
|
| return this.parsedAddress.map(paddedHex).join(':');
|
| }
|
| |
| |
| |
|
|
| decimal() {
|
| return this.parsedAddress.map((n) => parseInt(n, 16).toString(10).padStart(5, '0')).join(':');
|
| }
|
| |
| |
| |
|
|
| bigInt() {
|
| return BigInt(`0x${this.parsedAddress.map(paddedHex).join('')}`);
|
| }
|
| |
| |
| |
| |
| |
| |
|
|
| to4() {
|
| const binary = this.binaryZeroPad().split('');
|
| return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16).padStart(8, '0'));
|
| }
|
| |
| |
| |
|
|
| to4in6() {
|
| const address4 = this.to4();
|
| const address6 = new Address6(this.parsedAddress.slice(0, 6).join(':'), 6);
|
| const correct = address6.correctForm();
|
| let infix = '';
|
| if (!/:$/.test(correct)) {
|
| infix = ':';
|
| }
|
| return correct + infix + address4.address;
|
| }
|
| |
| |
| |
| |
| |
|
|
| inspectTeredo() {
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| const prefix = this.getBitsBase16(0, 32);
|
| const bitsForUdpPort = this.getBits(80, 96);
|
|
|
| const udpPort = (bitsForUdpPort ^ BigInt('0xffff')).toString();
|
| const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
|
| const bitsForClient4 = this.getBits(96, 128);
|
|
|
| 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);
|
| const groupIndividual = (0, common_1.testBit)(flagsBase2, 8);
|
| const universalLocal = (0, common_1.testBit)(flagsBase2, 9);
|
| const nonce = BigInt(`0b${flagsBase2.slice(2, 6) + flagsBase2.slice(8, 16)}`).toString(10);
|
| return {
|
| prefix: `${prefix.slice(0, 4)}:${prefix.slice(4, 8)}`,
|
| server4: server4.address,
|
| client4: client4.address,
|
| flags: flagsBase2,
|
| coneNat,
|
| microsoft: {
|
| reserved,
|
| universalLocal,
|
| groupIndividual,
|
| nonce,
|
| },
|
| udpPort,
|
| };
|
| }
|
| |
| |
| |
| |
|
|
| inspect6to4() {
|
| |
| |
| |
|
|
| const prefix = this.getBitsBase16(0, 16);
|
| const gateway = ipv4_1.Address4.fromHex(this.getBitsBase16(16, 48));
|
| return {
|
| prefix: prefix.slice(0, 4),
|
| gateway: gateway.address,
|
| };
|
| }
|
| |
| |
| |
|
|
| to6to4() {
|
| if (!this.is4()) {
|
| return null;
|
| }
|
| const addr6to4 = [
|
| '2002',
|
| this.getBitsBase16(96, 112),
|
| this.getBitsBase16(112, 128),
|
| '',
|
| '/16',
|
| ].join(':');
|
| return new Address6(addr6to4);
|
| }
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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(':'));
|
| }
|
| |
| |
| |
| |
| |
| |
| |
|
|
| 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('.'));
|
| }
|
| |
| |
| |
| |
| |
|
|
| toByteArray() {
|
| const valueWithoutPadding = this.bigInt().toString(16);
|
| const leadingPad = '0'.repeat(valueWithoutPadding.length % 2);
|
| const value = `${leadingPad}${valueWithoutPadding}`;
|
| const bytes = [];
|
| for (let i = 0, length = value.length; i < length; i += 2) {
|
| bytes.push(parseInt(value.substring(i, i + 2), 16));
|
| }
|
| return bytes;
|
| }
|
| |
| |
| |
| |
| |
|
|
| toUnsignedByteArray() {
|
| return this.toByteArray().map(unsignByte);
|
| }
|
| |
| |
| |
| |
| |
|
|
| static fromByteArray(bytes) {
|
| return this.fromUnsignedByteArray(bytes.map(unsignByte));
|
| }
|
| |
| |
| |
| |
| |
|
|
| static fromUnsignedByteArray(bytes) {
|
| const BYTE_MAX = BigInt('256');
|
| let result = BigInt('0');
|
| let multiplier = BigInt('1');
|
| for (let i = bytes.length - 1; i >= 0; i--) {
|
| result += multiplier * BigInt(bytes[i].toString(10));
|
| multiplier *= BYTE_MAX;
|
| }
|
| return Address6.fromBigInt(result);
|
| }
|
| |
| |
| |
|
|
| isCanonical() {
|
| return this.addressMinusSuffix === this.canonicalForm();
|
| }
|
| |
| |
| |
|
|
| isLinkLocal() {
|
|
|
| if (this.getBitsBase2(0, 64) ===
|
| '1111111010000000000000000000000000000000000000000000000000000000') {
|
| return true;
|
| }
|
| return false;
|
| }
|
| |
| |
| |
|
|
| isMulticast() {
|
| const type = this.getType();
|
| return type === 'Multicast' || type.startsWith('Multicast ');
|
| }
|
| |
| |
| |
| |
| |
| |
|
|
| is4() {
|
| return this.v4;
|
| }
|
| |
| |
| |
| |
| |
| |
| |
|
|
| isMapped4() {
|
| return this.isInSubnet(IPV4_MAPPED_SUBNET);
|
| }
|
| |
| |
| |
|
|
| isTeredo() {
|
| return this.isInSubnet(TEREDO_SUBNET);
|
| }
|
| |
| |
| |
|
|
| is6to4() {
|
| return this.isInSubnet(SIX_TO_FOUR_SUBNET);
|
| }
|
| |
| |
| |
|
|
| isLoopback() {
|
| return this.getType() === 'Loopback';
|
| }
|
| |
| |
| |
|
|
| isULA() {
|
| return this.isInSubnet(ULA_SUBNET);
|
| }
|
| |
| |
| |
|
|
| isUnspecified() {
|
| return this.getType() === 'Unspecified';
|
| }
|
| |
| |
| |
|
|
| isDocumentation() {
|
| return this.isInSubnet(DOCUMENTATION_SUBNET);
|
| }
|
|
|
|
|
| |
| |
| |
| |
|
|
| href(optionalPort) {
|
| if (optionalPort === undefined) {
|
| optionalPort = '';
|
| }
|
| else {
|
| optionalPort = `:${optionalPort}`;
|
| }
|
| return `http://[${this.correctForm()}]${optionalPort}/`;
|
| }
|
| |
| |
| |
| |
| |
| |
| |
|
|
| link(options) {
|
| if (!options) {
|
| options = {};
|
| }
|
| if (options.className === undefined) {
|
| options.className = '';
|
| }
|
| if (options.prefix === undefined) {
|
| options.prefix = '/#address=';
|
| }
|
| if (options.v4 === undefined) {
|
| options.v4 = false;
|
| }
|
| let formFunction = this.correctForm;
|
| if (options.v4) {
|
| formFunction = this.to4in6;
|
| }
|
| const form = formFunction.call(this);
|
| const safeHref = helpers.escapeHtml(`${options.prefix}${form}`);
|
| const safeForm = helpers.escapeHtml(form);
|
| if (options.className) {
|
| const safeClass = helpers.escapeHtml(options.className);
|
| return `<a href="${safeHref}" class="${safeClass}">${safeForm}</a>`;
|
| }
|
| return `<a href="${safeHref}">${safeForm}</a>`;
|
| }
|
| |
| |
| |
|
|
| group() {
|
| if (this.elidedGroups === 0) {
|
|
|
| return helpers.simpleGroup(this.addressMinusSuffix).join(':');
|
| }
|
| assert(typeof this.elidedGroups === 'number');
|
| assert(typeof this.elisionBegin === 'number');
|
|
|
| const output = [];
|
| const [left, right] = this.addressMinusSuffix.split('::');
|
| if (left.length) {
|
| output.push(...helpers.simpleGroup(left));
|
| }
|
| else {
|
| output.push('');
|
| }
|
| const classes = ['hover-group'];
|
| for (let i = this.elisionBegin; i < this.elisionBegin + this.elidedGroups; i++) {
|
| classes.push(`group-${i}`);
|
| }
|
| output.push(`<span class="${classes.join(' ')}"></span>`);
|
| if (right.length) {
|
| output.push(...helpers.simpleGroup(right, this.elisionEnd));
|
| }
|
| else {
|
| output.push('');
|
| }
|
| if (this.is4()) {
|
| assert(this.address4 instanceof ipv4_1.Address4);
|
| output.pop();
|
| output.push(this.address4.groupForV6());
|
| }
|
| return output.join(':');
|
| }
|
|
|
|
|
| |
| |
| |
| |
| |
|
|
| regularExpressionString(substringSearch = false) {
|
| let output = [];
|
|
|
| const address6 = new Address6(this.correctForm());
|
| if (address6.elidedGroups === 0) {
|
|
|
| output.push((0, regular_expressions_1.simpleRegularExpression)(address6.parsedAddress));
|
| }
|
| else if (address6.elidedGroups === constants6.GROUPS) {
|
|
|
| output.push((0, regular_expressions_1.possibleElisions)(constants6.GROUPS));
|
| }
|
| else {
|
|
|
| const halves = address6.address.split('::');
|
| if (halves[0].length) {
|
| output.push((0, regular_expressions_1.simpleRegularExpression)(halves[0].split(':')));
|
| }
|
| assert(typeof address6.elidedGroups === 'number');
|
| output.push((0, regular_expressions_1.possibleElisions)(address6.elidedGroups, halves[0].length !== 0, halves[1].length !== 0));
|
| if (halves[1].length) {
|
| output.push((0, regular_expressions_1.simpleRegularExpression)(halves[1].split(':')));
|
| }
|
| output = [output.join(':')];
|
| }
|
| if (!substringSearch) {
|
| output = [
|
| '(?=^|',
|
| regular_expressions_1.ADDRESS_BOUNDARY,
|
| '|[^\\w\\:])(',
|
| ...output,
|
| ')(?=[^\\w\\:]|',
|
| regular_expressions_1.ADDRESS_BOUNDARY,
|
| '|$)',
|
| ];
|
| }
|
| return output.join('');
|
| }
|
| |
| |
| |
| |
| |
|
|
| regularExpression(substringSearch = false) {
|
| return new RegExp(this.regularExpressionString(substringSearch), 'i');
|
| }
|
| }
|
| 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');
|
| |