コンテンツにスキップ

IPアドレス判定

CloudFront Functionのような外部モジュールを使いづらいものを実装するときに、自前実装でなんとかできるように書いてみた。

cidr.ts
export class CIDR {
#cidr: string;
#baseIp: number;
#subnet: number;
constructor(cidr: string) {
this.#cidr = cidr;
const [baseIp, mask] = cidr.split("/");
this.#baseIp = this.#ipToLong(baseIp);
this.#subnet = this.#cidrToSubnet(Number.parseInt(mask, 10));
}
get cidr() {
return this.#cidr;
}
isInCidrRange(ip: string): boolean {
const ipLong = this.#ipToLong(ip);
const subnet = this.#subnet;
return (ipLong & subnet) === (this.#baseIp & subnet);
}
getCidrRange(): string[] {
const subnet = this.#subnet;
const startIp = this.#baseIp & subnet;
const endIp = startIp + (~subnet >>> 0);
const ips: string[] = [];
for (let i = startIp; i <= endIp; i++) {
ips.push(this.#longToIp(i));
}
return ips;
}
#ipToLong(ip: string): number {
return (
ip
.split(".")
.reduce((acc, octet) => (acc << 8) + Number.parseInt(octet, 10), 0) >>>
0
);
}
#longToIp(long: number): string {
const max = 255;
return [
(long >>> 24) & max,
(long >>> 16) & max,
(long >>> 8) & max,
long & max,
].join(".");
}
#cidrToSubnet(cidr: number): number {
return (-1 << (32 - cidr)) >>> 0;
}
}