logo hsb.horse
← 블로그 목록으로 돌아가기

블로그

TypeScript에서 CIDR 범위의 IP 주소 결정 구현

CloudFront Function 등 외부 모듈을 사용할 수 없는 환경용으로 CIDR 범위 내의 IP 주소 판정을 자체 구현. 비트 연산을 사용한 클래스 구문의 구현을 정리.

게시일:

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")); // true
console.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 제어를 할 때 활용할 수 있다.