CIDR 표기법과 서브넷 마스크: /8부터 /32까지 읽는 법
192.168.1.0/24에서 슬래시 뒤에 붙는 숫자는 주소 개수가 아니라 비트 개수입니다. IPv4 주소를 이루는 32비트 중 몇 비트가 네트워크 몫인지를 알려 주고, 남은 비트는 전부 호스트 몫입니다. CIDR 표기법은 사실상 이 한 문장이 전부입니다.
나머지는 여기서 자연히 따라 나옵니다. /24는 호스트 비트를 8개 남기므로 블록에 2⁸ = 256개 주소가 들어갑니다. /26은 6개를 남기므로 64개가 들어갑니다. 호스트 쪽에 비트를 하나 내줄 때마다 블록 크기는 두 배가 되고, 하나 가져올 때마다 블록 개수가 두 배가 됩니다. 실제로 장비에 배정할 수 있는 개수는 보통 전체보다 2개 적습니다. 첫 주소는 네트워크를 가리키고 마지막 주소는 브로드캐스트이기 때문입니다. /26의 사용 가능 호스트는 64개가 아니라 62개입니다.
그런데 이 빼기 2 규칙을 의도적으로 깨는 접두사가 두 개 있습니다. 와일드카드 마스크도 조심해야 합니다. 서브넷 마스크와 생김새만 비슷할 뿐 같은 값이 아닌데, 사람들은 둘을 서로의 입력란에 수시로 잘못 넣습니다. 블록 하나의 답만 급하다면 서브넷 계산기가 바로 출력해 줍니다. 다만 계산기 없이 같은 답에 도달하는 절차를 알아 두면 설계 단계가 훨씬 빨라집니다.
CIDR 표기법이 실제로 말하는 것
서브넷 마스크 자체도 32비트 숫자이고, 주소와 똑같은 방식으로 표기합니다. 비트 구성은 1이 연속으로 이어지다가 0이 연속으로 이어지는 형태입니다. 1은 네트워크 비트를, 0은 호스트 비트를 표시합니다. /26을 전부 펼쳐 쓰면 이렇게 됩니다.
11111111.11111111.11111111.11000000
255 . 255 . 255 . 192
각 옥텟을 10진수로 되돌리면 255.255.255.192입니다. CIDR 표기법은 32개 비트를 전부 적는 대신 앞쪽 1의 개수만 셉니다. 192.168.1.0/26과 192.168.1.0 255.255.255.192는 같은 내용을 문법만 달리해 적은 것이고, 장비가 둘 중 무엇을 요구하는지는 지금 입력하는 명령어에 전적으로 달려 있습니다.
요령은 이 개수 세기가 전부입니다. /8, /16, /24는 옥텟 경계에 딱 떨어지기 때문에 10진수로 봐도 깔끔합니다. 255.0.0.0, 255.255.0.0, 255.255.255.0이 그렇습니다. 하지만 표기법이 옥텟 경계를 요구하는 것은 아닙니다. /22와 /27도 똑같이 유효합니다. 이들은 옥텟 한가운데를 가르며 255.255.252.0 같은 마스크를 내놓는데, 2진수로 적어 보기 전까지는 임의의 값처럼 보입니다.
1993년 이전에는 주소의 앞쪽 비트가 크기를 결정했습니다. 클래스 A는 /8, 클래스 B는 /16, 클래스 C는 /24였고 그 사이는 없었습니다. 호스트가 300대인 조직은 클래스 B를 받아 65,000개가 넘는 주소를 낭비하거나, 클래스 C 블록 두 개를 받아 경로를 두 개 유지해야 했습니다. CIDR(RFC 1519, 이후 RFC 4632로 개정)이 이 결합을 끊었습니다. 접두사가 주소와 함께 다니므로 블록은 2의 거듭제곱이면 어떤 크기든 됩니다. 클래스는 자격증 시험과 오래된 문서에 여전히 등장하지만, 클래스풀 라우팅 자체는 그때 폐기됐습니다. 네트워크가 어디서 끝나는지는 첫 옥텟이 아니라 마스크가 결정합니다.
서브넷 마스크 치트 시트, /8부터 /32까지
마지막 열은 일부러 넣었습니다. 일반 공식 2ⁿ − 2가 내놓는 값인데, 맨 아래 두 행을 제외하면 실제 사용 가능 개수와 일치합니다.
| 접두사 | 서브넷 마스크 | 와일드카드 마스크 | 전체 주소 | 사용 가능 호스트 | 단순 2ⁿ − 2 계산값 |
|---|---|---|---|---|---|
| /8 | 255.0.0.0 | 0.255.255.255 | 16777216 | 16777214 | 16777214 |
| /9 | 255.128.0.0 | 0.127.255.255 | 8388608 | 8388606 | 8388606 |
| /10 | 255.192.0.0 | 0.63.255.255 | 4194304 | 4194302 | 4194302 |
| /11 | 255.224.0.0 | 0.31.255.255 | 2097152 | 2097150 | 2097150 |
| /12 | 255.240.0.0 | 0.15.255.255 | 1048576 | 1048574 | 1048574 |
| /13 | 255.248.0.0 | 0.7.255.255 | 524288 | 524286 | 524286 |
| /14 | 255.252.0.0 | 0.3.255.255 | 262144 | 262142 | 262142 |
| /15 | 255.254.0.0 | 0.1.255.255 | 131072 | 131070 | 131070 |
| /16 | 255.255.0.0 | 0.0.255.255 | 65536 | 65534 | 65534 |
| /17 | 255.255.128.0 | 0.0.127.255 | 32768 | 32766 | 32766 |
| /18 | 255.255.192.0 | 0.0.63.255 | 16384 | 16382 | 16382 |
| /19 | 255.255.224.0 | 0.0.31.255 | 8192 | 8190 | 8190 |
| /20 | 255.255.240.0 | 0.0.15.255 | 4096 | 4094 | 4094 |
| /21 | 255.255.248.0 | 0.0.7.255 | 2048 | 2046 | 2046 |
| /22 | 255.255.252.0 | 0.0.3.255 | 1024 | 1022 | 1022 |
| /23 | 255.255.254.0 | 0.0.1.255 | 512 | 510 | 510 |
| /24 | 255.255.255.0 | 0.0.0.255 | 256 | 254 | 254 |
| /25 | 255.255.255.128 | 0.0.0.127 | 128 | 126 | 126 |
| /26 | 255.255.255.192 | 0.0.0.63 | 64 | 62 | 62 |
| /27 | 255.255.255.224 | 0.0.0.31 | 32 | 30 | 30 |
| /28 | 255.255.255.240 | 0.0.0.15 | 16 | 14 | 14 |
| /29 | 255.255.255.248 | 0.0.0.7 | 8 | 6 | 6 |
| /30 | 255.255.255.252 | 0.0.0.3 | 4 | 2 | 2 |
| /31 | 255.255.255.254 | 0.0.0.1 | 2 | 2 | 0 |
| /32 | 255.255.255.255 | 0.0.0.0 | 1 | 1 | −1 |
표를 통째로 외울 일은 없고, 값들 사이의 규칙만 보면 됩니다. 한 행 내려갈 때마다 블록은 절반이 됩니다. /24는 256개, /25는 128개, /26은 64개입니다. 와일드카드 열은 서브넷 마스크의 모든 비트를 뒤집은 값이고, 그래서 255.255.255.192와 0.0.0.63은 언제나 같은 행에 나타납니다. 굵게 표시한 두 행은 표준 공식이 현실을 더 이상 설명하지 못하는 지점이며, 뒤쪽 절에서 따로 다룹니다.
외워 둘 값은 마스크 열의 마지막 옥텟뿐입니다. 계속 반복되기 때문입니다. 128, 192, 224, 240, 248, 252, 254, 255. 유효한 마스크의 끝자리로 올 수 있는, 0이 아닌 바이트 값은 이 여덟 개가 전부입니다. 왜 그런지 직접 변환해 보고 싶다면 진법 변환기에서 각 값을 2진수로 확인할 수 있습니다.
표를 거꾸로 읽기: 서브넷 마스크에서 CIDR로
점 10진수 마스크가 주어지면 1인 비트의 개수를 세면 됩니다. 255는 각각 8을 보태고, 나머지는 눈여겨봐야 할 옥텟 하나가 채웁니다.
| 마스크 마지막 옥텟 | 128 | 192 | 224 | 240 | 248 | 252 | 254 | 255 |
|---|---|---|---|---|---|---|---|---|
| 더해지는 비트 수 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
따라서 255.255.255.192는 8 + 8 + 8 + 2 = /26입니다. 그리고 255.255.252.0은 8 + 8 + 6 + 0 = /22인데, 252를 2진수로 쓰면 11111100이기 때문입니다.
255도 0도 아닌 옥텟이 곧 경계 옥텟이고, 유효한 마스크에 그런 옥텟은 하나뿐입니다. 그 옥텟의 값에서 블록 크기까지 곧바로 나옵니다.
서브넷 마스크와 네트워크를 손으로 계산하는 법
기계적인 절차는 세 단계이고 어떤 접두사에도 통합니다. 아래 예제는 192.168.1.130/26을 쓰지만 주소만 갈아 끼우면 그대로 적용됩니다.
1단계: 블록 크기 구하기
블록 크기는 256 − 경계 마스크 옥텟입니다.
/26의 마스크는 255.255.255.192이므로 블록 크기는 256 − 192 = 64입니다. 이 크기의 서브넷은 네 번째 옥텟에서 64의 배수 자리에 놓입니다. 0, 64, 128, 192입니다. 다른 시작점은 존재하지 않습니다.
블록 크기와 주소 개수는 결국 같은 숫자입니다. 비트 대신 마스크에서 출발해 얻었을 뿐입니다.
2단계: 주소가 어느 블록에 속하는지 찾기
주소의 경계 옥텟을 블록 크기로 나눈 뒤 소수점 이하를 버립니다.
주소는 192.168.1.130이고 블록 크기는 64이므로 130 ÷ 64 = 2.03…, 버림하면 2입니다. 다시 곱하면 2 × 64 = 128입니다. 이 주소는 128에서 시작하는 블록에 속합니다.
오류는 대부분 여기서, 그것도 언제나 같은 방향으로 발생합니다. 건네받은 주소를 블록의 시작이라고 가정해 버리는데, 실제로는 그렇지 않은 경우가 훨씬 많습니다. 192.168.1.130은 그 /24 안의 세 번째 /26에 들어 있는 호스트 주소입니다.
3단계: 네트워크, 브로드캐스트, 첫 호스트와 마지막 호스트
블록의 시작이 네트워크 주소입니다. 브로드캐스트는 블록 시작에 블록 크기를 더하고 1을 뺀 값입니다. 그 사이에 놓인 주소는 전부 배정할 수 있습니다.
Network 192.168.1.128
Broadcast 192.168.1.191
Usable 192.168.1.129 - 192.168.1.190
Usable 62 (of 64 total)
Netmask 255.255.255.192
Wildcard 0.0.0.63
브로드캐스트는 128 + 64 − 1 = 191입니다. 첫 호스트는 네트워크 + 1, 마지막 호스트는 브로드캐스트 − 1이고, 사용 가능 개수는 64 − 2 = 62로 치트 시트의 /26 행과 일치합니다.
한 문장으로 줄이면 이렇습니다. 블록 크기는 256에서 마스크 옥텟을 뺀 값이고, 주소를 그 배수로 내림하면 그것이 네트워크이며, 다음 블록 시작에서 1을 뺀 값이 브로드캐스트입니다.
이 방법은 네 번째 옥텟 전용이 아닙니다. /22의 마스크는 255.255.252.0이므로 경계 옥텟은 세 번째이고, 그 자리의 블록 크기는 256 − 252 = 4입니다. 따라서 블록은 10.0.0.0, 10.0.4.0, 10.0.8.0에서 시작하고, 10.0.0.0/22 블록은 브로드캐스트 10.0.3.255까지 이어지며 사용 가능 주소는 10.0.0.1부터 10.0.3.254까지입니다. 하나의 브로드캐스트 도메인 안에 연속된 /24 네 개가 들어간 셈입니다. 단계는 똑같이 셋, 옥텟만 다릅니다.
2진수와 10진수를 오가는 대목에서 자꾸 막힌다면 진법 변환 가이드를 먼저 보세요. 변환만 따로 떼어 훨씬 깊게 다룹니다.
손으로 낸 답을 스크립트로 검산하고 싶다면 파이썬 표준 라이브러리로 충분합니다.
import ipaddress
net = ipaddress.ip_network("192.168.1.130/26", strict=False)
print(net) # 192.168.1.128/26
print(net.network_address) # 192.168.1.128
print(net.broadcast_address) # 192.168.1.191
print(net.netmask) # 255.255.255.192
print(net.hostmask) # 0.0.0.63
print(net.num_addresses) # 64
print(len(list(net.hosts()))) # 62
strict=False는 네트워크 주소 대신 호스트 주소를 넘길 수 있게 해 주는 옵션입니다. 기본값인 strict=True에서는 같은 호출이 ValueError를 냅니다.
빼기 2 규칙이 더 이상 참이 아닌 지점
이 뺄셈에는 이유가 있습니다. 일반적인 서브넷에서 호스트 비트가 전부 0인 패턴은 네트워크 자신을 가리키고, 전부 1인 패턴은 지정 브로드캐스트 주소입니다. 둘 다 인터페이스에 설정할 수 없으므로, 2ⁿ개 주소를 가진 블록이 호스트에 내주는 것은 2ⁿ − 2개입니다. /24가 254개, /26이 62개인 이유가 이것입니다.
그 이유가 곧 한계이기도 합니다. 블록이 너무 작아 예약 주소 두 개를 담을 수 없게 되면, 그 둘을 빼는 계산은 의미를 잃습니다.
/31은 주소가 두 개이고 사용 가능 호스트도 두 개입니다. RFC 3021은 점대점 링크를 위해 /31을 정의합니다. 이런 링크에는 종단이 정확히 두 개뿐이고 공유 세그먼트가 없으므로, 브로드캐스트 주소가 할 일도 없고 네트워크 주소가 식별할 대상도 없습니다. 두 주소를 양쪽 끝에 하나씩 배정합니다. 여기에 2ⁿ − 2를 적용하면 0이 나오지만, 이는 공식이 자기 적용 범위 밖에서 답을 낸 것입니다. 다만 조건이 붙고, 그 조건은 문서상의 단서가 아니라 실제 제약입니다. /31은 진짜로 점대점인 인터페이스에서만 쓸 수 있습니다. 다중 접속 LAN 세그먼트에는 여전히 /30이나 그보다 짧은 접두사가 필요하고, 윈도우는 NIC에 /31을 받아들이지 않습니다.
/32는 주소가 하나이고 사용 가능 호스트도 하나입니다. 단일 호스트 경로에 쓰입니다. 루프백 인터페이스, 정적 경로, 애니캐스트 주소, 주소 하나짜리 방화벽 규칙 같은 곳입니다. 브로드캐스트 주소가 없으므로 공식의 − 2는 −1이라는 값을 내놓습니다.
파이썬도 두 경우 모두 같은 답을 냅니다.
import ipaddress
p2p = ipaddress.ip_network("203.0.113.4/31")
print([str(h) for h in p2p.hosts()]) # ['203.0.113.4', '203.0.113.5']
host = ipaddress.ip_network("10.0.0.1/32")
print([str(h) for h in host.hosts()]) # ['10.0.0.1']
예외 두 개를 따로 외우는 것보다 뺄셈이 무슨 계산인지 기억해 두는 편이 낫습니다. 특정한 주소 두 개를 덜어 내는 계산이니, 덜어 내기 전에 그 두 주소가 있는지부터 보면 됩니다. /31과 /32에는 브로드캐스트 주소가 아예 없으니 뺄 것도 없습니다.
전체 주소, 사용 가능 호스트, 서브넷 개수는 서로 다른 세 숫자
이 셋을 뒤섞어 쓰는 일이 끊이지 않습니다. 셋 다 같은 접두사에서 나온 2의 거듭제곱이니 헷갈릴 만도 합니다.
- 전체 주소 수는 /p에서
2^(32 − p)입니다. /26이면 64개입니다. - 사용 가능 호스트 수는 거기서 2를 뺀 값이며, /31과 /32만 예외입니다. /26이면 62개입니다.
- 서브넷 개수는 상위 /p를 하위 /q로 쪼갤 때
2^(q − p)입니다. /24를 /26으로 쪼개면 비트 두 개를 빌리므로2² = 4개입니다.
셋은 서로 다른 질문에 답합니다. “/26이면 4개”라는 말은 /24를 쪼갠다는 전제가 깔려 있을 때만 맞습니다. 쪼개는 데는 주소 비용도 듭니다. 하위 서브넷마다 자기 몫의 네트워크 주소와 브로드캐스트 주소를 예약하기 때문입니다. /24에서 잘라낸 /26 네 개의 사용 가능 주소는 4 × 62 = 248개로, 상위 블록의 254개와 비교하면 6개가 분할 자체에 쓰인 셈입니다.
와일드카드 마스크와 서브넷 마스크: 어느 명령어가 어느 쪽을 요구하나
와일드카드 마스크는 서브넷 마스크를 비트 단위로 반전한 값입니다. 서브넷 마스크가 1인 자리에서 와일드카드는 0입니다. 치트 시트의 /26 행을 보면 마스크는 255.255.255.192, 와일드카드는 0.0.0.63입니다. 한쪽의 모든 비트를 뒤집으면 다른 쪽이 되며, 그래서 둘은 늘 붙어 다닙니다.
다만 둘은 정반대 의미로 쓰입니다. 서브넷 마스크는 비트 AND로 적용되므로 1인 비트는 “이 비트는 네트워크의 일부”라는 뜻입니다. 와일드카드는 매칭 필터이므로 0인 비트가 “이 비트는 반드시 일치해야 한다”, 1인 비트가 “상관없다”는 뜻입니다. 바탕에 깔린 연산은 같고 극성만 반대입니다. 비트 수준의 동작이 흐릿하다면 비트 연산 가이드가 AND, OR, NOT을 더 일반적인 맥락에서 설명합니다.
장비가 어느 쪽을 요구하는지는 취향의 문제가 아닙니다. 192.168.1.128/26 블록을 예로 들면 이렇습니다.
! wants the subnet mask
ip address 192.168.1.129 255.255.255.192
! wants the wildcard mask
access-list 10 permit 192.168.1.128 0.0.0.63
network 192.168.1.128 0.0.0.63 area 0
! Cisco ASA — wants the subnet mask, unlike IOS ACLs
access-list OUT permit ip 192.168.1.128 255.255.255.192 any
# Linux iproute2 — takes the prefix directly
ip addr add 192.168.1.129/26 dev eth0
Cisco IOS의 ACL과 OSPF network 구문은 와일드카드 마스크를 받고, ASA는 대신 서브넷 마스크를 받습니다. 같은 제품군 안에서 한 벤더가 두 가지 관례를 쓰는 셈이고, 이 영역에서 복사해 붙여 넣다 나는 사고가 유독 잦은 이유가 여기에 있습니다. 다른 플랫폼도 저마다 관례가 있으니, 익숙하지 않은 입력란에 값을 붙여 넣기 전에 그 칸이 둘 중 무엇을 기대하는지 확인하세요.
위험한 것은 실패하는 방식입니다. IOS ACL에 255.255.255.192를 붙여 넣으면 라우터는 이를 와일드카드로 읽습니다. 전부 1인 옥텟 세 개는 “상관없다”는 뜻이므로 앞의 세 옥텟은 아예 대조되지 않고, 규칙은 의도했던 블록을 한참 벗어난 범위까지 미칩니다. 문법 오류도 없고 로그 한 줄도 남지 않습니다. 범위만 잘못된 permit 구문이 조용히 자리를 잡습니다. 반대 방향의 실수는 그나마 잡힐 여지가 있습니다. 0.0.0.63은 앞쪽에 1이 연속으로 이어지지 않으므로 유효한 서브넷 마스크가 아니기 때문입니다. 특정 플랫폼이 이를 거부할지 조용히 받아들일지는 운영 환경에서 알아낼 일이 아닙니다.
ACL 와일드카드에는 구멍이 있어도 되지만 서브넷 마스크에는 안 되는 이유
서브넷 마스크는 반드시 1이 한 번 연속으로 이어진 뒤 0이 이어지는 형태여야 합니다. 관례라서가 아니라, AND 연산이 주소를 정확히 두 부분으로 가르려면 그 형태여야 하기 때문입니다. 255.0.255.0 같은 값은 중간에 구멍이 있어 일관된 경계를 전혀 기술하지 못하며, 장비는 이를 거부합니다. 파이썬도 마찬가지입니다.
import ipaddress
ipaddress.ip_network("10.0.0.0/255.0.255.0")
# ValueError: '10.0.0.0/255.0.255.0' does not appear to be an IPv4 or IPv6 network
유효한 마스크는 /0부터 /32까지 33개뿐입니다. 그 밖의 값은 전부 오타입니다.
ACL 와일드카드에는 그런 제약이 없습니다. 주소를 네트워크 부분과 호스트 부분으로 가르는 용도가 아니기 때문입니다. 와일드카드는 비트 단위 매칭 필터이므로 구멍이 있어도 합법이고, 가끔은 유용하기까지 합니다. 구멍이 있는 와일드카드 하나로, 예컨대 어떤 범위 안의 홀수 번째 주소를 전부 잡아낼 수 있습니다. 표현력이 이렇게 다르다는 것은 둘이 애초에 같은 종류의 대상이 아니라는 뜻입니다. 점 10진수로 적어 놓았을 때 비슷해 보일 뿐입니다.
사설, CGNAT, 그 밖의 예약 대역
접두사는 블록이 얼마나 큰지만 알려 줍니다. 그 블록을 써도 되는지는 주소가 어느 대역에 놓여 있느냐가 결정합니다.
| 블록 | 범위 | 예약 근거 |
|---|---|---|
| 10.0.0.0/8 | 10.0.0.0 – 10.255.255.255 | RFC 1918 사설 |
| 172.16.0.0/12 | 172.16.0.0 – 172.31.255.255 | RFC 1918 사설 |
| 192.168.0.0/16 | 192.168.0.0 – 192.168.255.255 | RFC 1918 사설 |
| 100.64.0.0/10 | 100.64.0.0 – 100.127.255.255 | RFC 6598 캐리어급 NAT |
| 169.254.0.0/16 | 169.254.0.0 – 169.254.255.255 | RFC 3927 링크 로컬 |
| 255.255.255.255/32 | 단일 주소 | 제한 브로드캐스트 |
RFC 1918 대역은 공용 인터넷에서 절대 라우팅되지 않으며, 그래서 여기서 주소를 할당해도 안전합니다. 나머지는 사정이 조금씩 다릅니다.
100.64.0.0/10은 캐리어급 NAT 공간입니다. ISP가 이 대역의 주소를 배정했다면 그쪽 NAT 뒤에 있는 것이고, 터널 없이는 어떤 인바운드 연결도 들어오지 못합니다. RFC 1918 의미의 사설 공간이 아니며 내부 주소 설계에 가져다 쓸 수 있는 대역도 아닙니다. 사업자가 라우터 반대편에서 이미 쓰고 있을 수 있기 때문입니다.
169.254.0.0/16은 링크 로컬입니다. DHCP가 실패하면 호스트가 이 대역의 주소를 스스로 배정하므로, 인터페이스에 169.254 주소가 보인다면 그것은 설정이 아니라 진단 결과입니다. DHCP 요청에 아무도 응답하지 않았다는 뜻입니다. 이 대역으로 향하는 트래픽은 라우터를 넘어가지 않습니다.
문서와 운영 절차서의 예제용으로는 RFC 5737이 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24를 예약해 두었습니다. 복사해 붙여 넣은 예제가 실제 호스트를 가리키는 일이 없도록 하기 위해서입니다.
172.16.0.0/12는 /16 하나가 아니라 열여섯 개
사람들이 가장 자주 틀리는 예약 대역이며, 원인은 접두사에 있습니다. /12는 두 번째 옥텟에서 네 비트를 빌려 오므로 블록은 172.16.0.0부터 172.31.255.255까지 걸쳐 있습니다. 172.16.x.x 하나가 아니라 연속된 /16 열여섯 개입니다.
그 결과는 양방향으로 나타납니다. 172.20.5.1 같은 주소는 172.16으로 시작하지 않지만 대역 한복판에 놓여 있으므로 엄연한 사설 주소입니다. 반대로 172.15.x.x와 172.32.x.x는 남의 것인 공인 주소입니다. 그래서 172.0.0.0/8을 기준으로 작성한 방화벽 규칙이나 “내부 대역은 신뢰” 검사는 인터넷의 상당 부분을 조용히 신뢰하게 됩니다.
이런 경계를 확인해야 한다면 치트 시트에 산술이 다 들어 있습니다. /12의 주소 개수는 2^(32−12)개이고, 두 번째 옥텟은 256 − 240 = 16 간격으로 움직이며, 16 + 16 = 32이므로 블록은 172.32.0.0 직전에서 끝납니다.
VLSM: 블록 하나를 크기가 다른 서브넷으로 쪼개기
크기가 같은 서브넷은 편하지만 대개 틀린 선택입니다. 192.168.1.0/24 하나를 받은 지사에 규모가 서로 전혀 다른 세그먼트 네 개가 필요할 수 있습니다. 워크스테이션 100대, IP 전화 50대, 서버 열두 대, 관리 인터페이스 몇 개입니다. 이 /24를 똑같은 /26 네 개로 쪼개면 워크스테이션 세그먼트는 62대에서 넘쳐 버리고, 관리 세그먼트는 장비 열 대를 위해 62개 주소를 깔고 앉습니다.
가변 길이 서브넷 마스킹(VLSM)은 각 세그먼트에 실제로 필요한 접두사를 주는 방식입니다. 같은 /24를 /25 하나, /26 하나, /28 두 개로 잘라 보겠습니다.
큰 블록부터 순서대로 할당합니다. 모든 블록은 자기 크기의 배수 자리에서 시작해야 하므로, 가장 큰 블록이 먼저 자리를 고릅니다.
| 세그먼트 | 필요 호스트 | 접두사 | 네트워크 | 사용 가능 범위 | 브로드캐스트 | 서브넷 마스크 |
|---|---|---|---|---|---|---|
| 워크스테이션 | 100 | /25 | 192.168.1.0 | 192.168.1.1 – 192.168.1.126 | 192.168.1.127 | 255.255.255.128 |
| 음성 | 50 | /26 | 192.168.1.128 | 192.168.1.129 – 192.168.1.190 | 192.168.1.191 | 255.255.255.192 |
| 서버 | 12 | /28 | 192.168.1.192 | 192.168.1.193 – 192.168.1.206 | 192.168.1.207 | 255.255.255.240 |
| 관리 | 10 | /28 | 192.168.1.208 | 192.168.1.209 – 192.168.1.222 | 192.168.1.223 | 255.255.255.240 |
| 미할당 | — | /27 | 192.168.1.224 | 192.168.1.225 – 192.168.1.254 | 192.168.1.255 | 255.255.255.224 |
앞의 세 단계로 따라가면 이렇습니다.
- /25의 블록 크기는
256 − 128 = 128이므로 0에서 시작하고 브로드캐스트는0 + 128 − 1 = 127입니다. 사용 가능 범위는 1부터 126까지, 즉 126개이며 워크스테이션 100대를 넣고도 여유가 남습니다. 치트 시트의 /25 행과도 맞습니다. 전체 128개, 사용 가능 126개입니다. - 다음 빈 주소는 128입니다. /26의 블록 크기는 64이고 128은 64의 배수이므로 그대로 들어갑니다. 네트워크는 192.168.1.128, 브로드캐스트는
128 + 64 − 1 = 191, 사용 가능 범위는 129부터 190까지입니다. IP 전화 50대에 62개를 쓰는 셈입니다. 치트 시트 /26 행은 전체 64개, 사용 가능 62개입니다. - 다음 빈 주소는 192입니다. /28의 블록 크기는 16이고
192 = 16 × 12이므로 들어맞습니다. 네트워크는 192.168.1.192, 브로드캐스트는 207, 사용 가능 범위는 193부터 206까지로 서버 열두 대에 14개입니다. 치트 시트 /28 행은 전체 16개, 사용 가능 14개입니다. - 다음 빈 주소는 208이고
208 = 16 × 13이므로 두 번째 /28은 192.168.1.208에 놓이며, 브로드캐스트는 223, 사용 가능 범위는 209부터 222까지입니다.
여기까지 256개 중 128 + 64 + 16 + 16 = 224개를 배정했고 192.168.1.224부터 192.168.1.255까지가 남습니다. 이 32개 주소는 마침 정렬이 딱 맞는 /27 하나이며, 나중에 점대점 링크를 뽑아 쓸 자리입니다. 안에 /31 열여섯 개가 들어가므로 라우터 링크마다 하나씩 배정할 수 있습니다.
순서를 뒤집으면 무엇을 잃는지는 직접 배치해 보면 드러납니다. /28 두 개를 대신 맨 앞에 두었다고 해 봅시다. 192.168.1.0/28과 192.168.1.16/28입니다. 다음 빈 주소는 192.168.1.32인데 /25는 128의 배수에서 시작해야 하므로 거기서 시작할 수 없습니다. 192.168.1.128까지 건너뛰어야 합니다. 32부터 127까지의 주소가 사라지는 것은 아니지만, 정렬이 맞는 더 작은 조각으로만 쓸 수 있습니다. 192.168.1.32의 /27과 192.168.1.64의 /26이 그것입니다. 결국 남는 공간은 위쪽에 연속된 블록 하나로 모이지 못하고 흩어집니다. 여기에 세그먼트를 하나만 더 요구해도 같은 배치는 아예 들어가지 않게 됩니다.
크기 순으로 배치하면 이런 일이 생기지 않습니다. 블록을 하나 놓고 나면 다음 빈 주소는 그 블록 크기의 배수이고, 더 큰 2의 거듭제곱의 배수는 그보다 작은 모든 거듭제곱의 배수이기도 합니다. 그래서 뒤따르는 더 작은 블록은 앞 블록이 끝난 자리가 어디든 정렬이 맞습니다. 건너뛸 일이 없습니다. 설계를 스위치에 반영하기 전에 서브넷 계산기의 분할 표에 한 번 돌려 보면, 세그먼트마다 정렬을 손으로 대조하는 것보다 빠릅니다.
운영 환경까지 살아남는 다섯 가지 실수
1. 입력한 주소를 네트워크 주소로 착각하는 경우
증상: 방화벽 규칙이 아무것도 매칭하지 못하거나, 경로가 세그먼트의 엉뚱한 절반을 덮습니다.
원인: 192.168.1.130/26을 네트워크 192.168.1.0, 브로드캐스트 192.168.1.255로 읽었습니다. 10진수로 눈에 들어오는 것이 /24 경계이기 때문입니다.
해결: 2단계를 적용하세요. 블록 크기는 64이고 130 ÷ 64를 버림하면 2이므로 네트워크는 2 × 64 = 128입니다. 블록은 192.168.1.128부터 192.168.1.191까지이고, 192.168.1.0은 완전히 다른 서브넷입니다. 접두사가 /24보다 길 때는 마스킹해 확인하기 전까지 받은 주소를 호스트 주소로 가정하세요.
2. 2ⁿ − 2를 /31에 적용하는 경우
증상: 정상적으로 올라와 트래픽까지 흘리고 있는 점대점 링크에 대해 IPAM 도구나 스프레드시트가 사용 가능 호스트 0개를 보고합니다. 원인: 빼기 2 규칙은 뺄 네트워크 주소와 브로드캐스트 주소가 존재한다고 전제합니다. /31에는 그 둘이 없습니다. 해결: /31과 /32는 이상 현상이 아니라 공식의 경계 조건으로 다루세요. RFC 3021은 /31의 두 주소를 모두 배정 가능하게 정의했고, /32는 주소가 하나뿐인 단일 호스트 경로입니다. 0이나 −1을 보고하는 도구는 공식을 정의역 밖에 적용한 것입니다. 이 예외는 진짜로 점대점인 링크에서만 성립하므로, 해당 인터페이스의 /31 지원 여부를 먼저 확인하세요.
3. 172.16.0.0/12를 172.16.x.x로만 취급하는 경우
증상: 한 사무실에서만 내부 서비스에 접근이 안 되거나, “사설 대역 전부 차단” 규칙이 새어 나갑니다. 원인: /12를 /16인 것처럼 읽었습니다. 해결: 대역은 172.16.0.0부터 172.31.255.255까지입니다. ACL과 허용 목록은 옥텟 패턴이 아니라 172.16.0.0/12 접두사를 기준으로 작성하고, 172.15.x.x와 172.32.x.x는 그 바깥의 공용 인터넷에 있다는 점을 기억하세요. 손으로 대조한다면 경계 옥텟은 두 번째이고 16씩 움직입니다.
4. 서브넷 마스크를 요구하는 칸에 와일드카드를 붙여 넣는 경우
증상: ACL이 의도보다 훨씬 넓게, 혹은 훨씬 좁게 허용하는데 설정에서는 이상한 점이 전혀 보이지 않습니다. 원인: IOS ACL과 OSPF network 구문은 와일드카드를, ASA는 서브넷 마스크를 받는데 0.0.0.63과 255.255.255.192는 얼핏 보면 구분이 되지 않습니다. 해결: 붙여 넣은 뒤가 아니라 붙여 넣기 전에 그 칸을 확인하세요. 쓸 만한 단서가 하나 있습니다. 접두사 길이가 /8 이상이면 서브넷 마스크는 255로 시작하고 와일드카드는 0으로 시작합니다. ACL이나 OSPF network 구문에 들어 있는 값이 255로 시작한다면, 그것은 와일드카드 칸에 들어간 서브넷 마스크입니다.
5. 불연속 마스크를 직접 쓰거나 실수로 생성하는 경우
증상: 장비가 설정 한 줄을 거부하거나, 자체 제작한 스크립트가 그럴듯해 보이지만 틀린 마스크를 내놓습니다. 원인: 255.0.255.0 같은 값은 중간에 구멍이 있어 유효한 서브넷 마스크가 아닙니다. 스크립트 쪽은 더 미묘합니다. 자바스크립트(JavaScript)에서 시프트 연산자는 오른쪽 피연산자를 32로 나눈 나머지로 취급하므로, 범위를 벗어난 접두사가 예외를 내는 대신 그럴듯해 보이는 잘못된 마스크를 조용히 내놓습니다(33은 /1이 되고 −1은 /31이 됩니다). 해결: 시프트 전에 접두사 범위를 검사하고, 1이 연속으로 이어진 뒤 0이 이어지는 형태가 아닌 마스크는 거부하세요. 두 실패 방식 모두 조용하기 때문에, 잘못된 입력을 추측으로 넘기는 라이브러리보다 예외를 내는 라이브러리가 여기서는 훨씬 낫습니다.
FAQ
서브넷과 VLAN은 무엇이 다른가요?
VLAN은 스위치에 설정하는 2계층 브로드캐스트 도메인이고, 서브넷은 3계층 주소 범위입니다. 보통 일대일로 대응시키지만 그것을 강제하는 규칙은 없습니다. 하나의 VLAN에 서브넷 두 개를 올릴 수도 있고, VLAN 하나를 여러 사이트에 트렁크로 연장할 수도 있습니다. 서브넷 주소를 재배치해도 VLAN ID는 그대로입니다.
/24를 /26으로 쪼개면 서브넷이 몇 개 나오나요?
네 개입니다. 개수는 빌려 온 비트 수만큼의 2의 거듭제곱이고, /26은 /24보다 두 비트 길므로 2² = 4개이며 각각 64개 주소짜리입니다. 하위 서브넷마다 자기 네트워크 주소와 브로드캐스트 주소를 예약하므로, /26 네 개의 사용 가능 주소는 248개로 상위 /24의 254개에 못 미칩니다.
IPv6에서도 CIDR 표기법이 똑같이 동작하나요?
슬래시가 앞쪽 네트워크 비트 수를 센다는 점은 같습니다. /64는 128비트 중 64비트가 네트워크라는 뜻입니다. 이어지지 않는 것은 빼기 2 규칙입니다. IPv6에는 브로드캐스트 주소가 없으므로 전체에서 빼는 값도 없습니다. 위의 치트 시트와 그 뒤의 계산기는 IPv4 전용입니다.
0.0.0.0/0은 무슨 뜻인가요?
네트워크 비트가 0개이므로 모든 IPv4 주소와 일치합니다. 라우팅 테이블에서는 기본 경로이며, 더 구체적인 접두사가 하나도 맞지 않을 때 사용됩니다. 바인드 주소로 쓰면 “모든 인터페이스”라는 뜻이고, 그래서 0.0.0.0에서 대기 중인 서비스는 그 장비가 연결된 모든 네트워크에서 접근할 수 있습니다.
같은 네트워크의 서브넷 두 개가 겹치면 어떻게 되나요?
포워딩은 언제나 가장 긴 일치 접두사를 우선하므로 라우터는 더 구체적인 경로를 선택하고, 겹치는 구간 안의 호스트들은 어느 목적지가 로컬인지에 대해 서로 다른 판단을 합니다. 증상은 부분적으로 나타납니다. 어떤 목적지는 되고 어떤 목적지는 안 되며, 어느 쪽이 되는지는 어디서 테스트하느냐에 따라 달라집니다.
클래스 A, B, C 주소는 왜 CIDR로 대체되었나요?
클래스로 고를 수 있는 크기가 /8, /16, /24 세 가지뿐이었기 때문입니다. 주소 300개가 필요한 조직은 클래스 B를 받아 대부분을 낭비하거나 클래스 C 경로를 두 개 운영해야 했습니다. CIDR은 접두사 길이를 자유롭게 열어 주소 고갈 속도를 늦췄고, 사업자가 여러 고객 블록을 하나의 경로로 요약할 수 있게 했습니다.
192.168.0.0/16 같은 사설 대역은 원하는 대로 서브네팅해도 되나요?
그렇습니다. RFC 1918 공간은 어떤 접두사 길이로든 마음대로 나눌 수 있고, 네트워크 바깥에서는 아무도 보지 못합니다. 제약은 내부에 있습니다. 파트너 네트워크나 나중에 피어링할 클라우드 VPC와 대역이 겹치면 되돌리는 비용이 크고, 그래서 주소 설계는 대개 가정용 공유기가 이미 쓰고 있는 블록을 피하는 방향으로 갑니다.
정리하면 이렇습니다. 접두사는 네트워크 비트 수를 세고, 블록 크기는 256 − 경계 마스크 옥텟입니다. 주소를 블록 크기의 배수로 내림하면 네트워크이고, 거기에 블록 크기에서 1을 뺀 값을 더하면 브로드캐스트입니다. 예약된 두 주소만큼 2를 빼되, /31이나 /32가 이미 뺄 이유를 없애 버린 경우에는 빼지 마세요. 와일드카드와 서브넷 마스크는 생김새로 구분하세요. 큰 블록을 작은 블록보다 먼저 할당하세요.
손에 익고 나면 여기 나온 계산은 대부분 도구 없이 끝납니다. 그래도 라우터에 올리기 전에 설계를 점검하거나 블록의 2진 경계를 한눈에 보고 싶다면 서브넷 계산기가 브라우저 안에서 계산을 끝내 줍니다.