[Data] Fix CIDR mask to avoid using big integers (#109789) (#110045)

This commit is contained in:
Michael Dokolin 2021-08-25 17:01:24 +02:00 committed by GitHub
parent d4514a50d3
commit 1d6ca80c7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 49 deletions

View file

@ -10,44 +10,41 @@ import ipaddr from 'ipaddr.js';
import { IpAddress } from '../../utils';
export class CidrMask {
private static getNetmask(size: number, prefix: number) {
return new Array(size).fill(255).map((byte, index) => {
const bytePrefix = 8 - Math.min(Math.max(prefix - index * 8, 0), 8);
// eslint-disable-next-line no-bitwise
return (byte >> bytePrefix) << bytePrefix;
});
}
private address: number[];
private netmask: number;
private netmask: number[];
private prefix: number;
constructor(cidr: string) {
try {
const [address, netmask] = ipaddr.parseCIDR(cidr);
const [address, prefix] = ipaddr.parseCIDR(cidr);
this.address = address.toByteArray();
this.netmask = netmask;
this.netmask = CidrMask.getNetmask(this.address.length, prefix);
this.prefix = prefix;
} catch {
throw Error('Invalid CIDR mask: ' + cidr);
}
}
private getBroadcastAddress() {
/* eslint-disable no-bitwise */
const netmask = (1n << BigInt(this.address.length * 8 - this.netmask)) - 1n;
const broadcast = this.address.map((byte, index) => {
const offset = BigInt(this.address.length - index - 1) * 8n;
const mask = Number((netmask >> offset) & 255n);
return byte | mask;
});
/* eslint-enable no-bitwise */
// eslint-disable-next-line no-bitwise
const broadcast = this.address.map((byte, index) => byte | (this.netmask[index] ^ 255));
return new IpAddress(broadcast).toString();
}
private getNetworkAddress() {
/* eslint-disable no-bitwise */
const netmask = (1n << BigInt(this.address.length * 8 - this.netmask)) - 1n;
const network = this.address.map((byte, index) => {
const offset = BigInt(this.address.length - index - 1) * 8n;
const mask = Number((netmask >> offset) & 255n) ^ 255;
return byte & mask;
});
/* eslint-enable no-bitwise */
// eslint-disable-next-line no-bitwise
const network = this.address.map((byte, index) => byte & this.netmask[index]);
return new IpAddress(network).toString();
}
@ -60,6 +57,6 @@ export class CidrMask {
}
toString() {
return `${new IpAddress(this.address)}/${this.netmask}`;
return `${new IpAddress(this.address)}/${this.prefix}`;
}
}

View file

@ -37,21 +37,6 @@ describe('IpAddress', () => {
});
});
describe('valueOf', () => {
it.each`
address | expected
${'0.0.0.0'} | ${'0'}
${'0.0.0.1'} | ${'1'}
${'126.45.211.34'} | ${'2116932386'}
${'ffff::'} | ${'340277174624079928635746076935438991360'}
`(
'should return $expected as a decimal representation of $address',
({ address, expected }) => {
expect(new IpAddress(address).valueOf().toString()).toBe(expected);
}
);
});
describe('toString()', () => {
it.each`
address | expected

View file

@ -32,16 +32,4 @@ export class IpAddress {
return this.value.toString();
}
valueOf(): number | bigint {
const value = this.value
.toByteArray()
.reduce((result, octet) => result * 256n + BigInt(octet), 0n);
if (value > Number.MAX_SAFE_INTEGER) {
return value;
}
return Number(value);
}
}