CloudFront Functionのような外部モジュールを使いづらい環境で、CIDR範囲内のIPアドレス判定を自前実装する。
実装
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; }}使い方
const cidr = new CIDR("192.168.1.0/24");
// IPアドレスが範囲内かチェックconsole.log(cidr.isInCidrRange("192.168.1.100")); // trueconsole.log(cidr.isInCidrRange("192.168.2.1")); // false
// CIDR範囲内の全IPアドレスを取得const ips = cidr.getCidrRange();console.log(ips.length); // 256ポイント
IPアドレスとlong値の相互変換
IPアドレス(例: 192.168.1.1)を32ビット整数に変換することで、ビット演算が可能になる。
CIDR判定
サブネットマスクとのAND演算で、IPアドレスがCIDR範囲内かを判定する。
(ipLong & subnet) === (baseIp & subnet)範囲内の全IPを列挙
開始IPと終了IPを計算し、その間のすべてのIPアドレスを生成する。
まとめ
外部ライブラリが使えない環境でも、ビット演算を使えばCIDR判定を自前実装できる。
CloudFront Functionやその他の制約のある環境で、IP制御を行う際に活用できる。
hsb.horse