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