📚 네트워크 · 패킷 분석 › 01. TCP/IP 구조 이해 — 30편
이전 글: 29. TCP Segment · 다음 글: 31. Ethernet 프레임과 MAC 주소 · ARP 동작 원리
UDP Datagram은 UDP(User Datagram Protocol)가 만드는 전송 단위입니다. 8바이트 고정 헤더 뒤에 애플리케이션이 한 번에 보낸 데이터가 그대로 붙습니다.
UDP Datagram = UDP 헤더(8바이트 고정) + 페이로드(애플리케이션 메시지 1개)
29. TCP Segment와의 가장 큰 차이는 "애플리케이션이 보낸 한 번의 메시지 = Datagram 한 개"라는 점입니다. TCP는 바이트 흐름을 자기 판단으로 잘라 보내지만, UDP는 애플리케이션이 sendto()로 넘긴 덩어리를 자르지도 합치지도 않습니다. 이 글은 Datagram이라는 단위와 크기에 집중하며, UDP라는 프로토콜의 성격과 쓰임새는 39. UDP란 무엇인가, 헤더 필드 비교는 40. TCP와 UDP 헤더 비교 — 신뢰성과 속도의 차이에서 다룹니다.
| 헤더 필드 | 크기 | Datagram 단위와의 관계 |
|---|---|---|
| Source Port | 16비트 | 응답을 받을 포트. 응답이 필요 없으면 0일 수 있음 |
| Destination Port | 16비트 | 받을 서비스 |
| Length | 16비트 | 헤더 + 페이로드 전체 길이. 최소 8 |
| Checksum | 16비트 | IPv4에서는 0이면 미사용, IPv6에서는 필수 |
UDP에는 연결 수립, 분할, 재조립, 재전송이 없습니다. 애플리케이션이 보낸 메시지에 헤더만 붙여 IP로 내려보냅니다. 메시지가 링크 MTU보다 크면 UDP가 아니라 IP 계층이 단편화합니다.
[애플리케이션] sendto() 3회: 100바이트, 300바이트, 3,000바이트
│
↓
[UDP] 메시지마다 헤더 8바이트만 붙임 (자르지 않음)
├→ Datagram A: Length 108
├→ Datagram B: Length 308
└→ Datagram C: Length 3,008
│
↓
[IP] MTU 1500 기준
├→ A, B: IP 패킷 1개씩
└→ C: IP 조각(Fragment) 3개로 분할 (UDP 헤더는 첫 조각에만 있음)
│
↓
[수신 측] IP가 C의 조각을 모두 모아야 UDP에 전달
→ 조각 하나라도 잃으면 Datagram C 전체가 사라짐
→ 수신 애플리케이션은 recvfrom() 3회로 100 / 300 / 3,000바이트를 그대로 받음
여기서 두 가지 결과가 나옵니다.
| 항목 | 값 / 특징 | 근거 |
|---|---|---|
| 헤더 크기 | 8바이트 고정 | 옵션 없음 |
| 이론상 최대 Length | 65,535바이트 | 16비트 필드 |
| IPv4에서 실제 최대 페이로드 | 65,507바이트 | 65,535 − IP 헤더 20 − UDP 헤더 8 |
| 단편화 없이 보내는 페이로드(이더넷, IPv4) | 1,472바이트 이하 | 1,500 − 20 − 8 |
| 메시지 경계 | 보존 | 한 번 보낸 것 = 한 Datagram |
| 순서·유실 | 보장하지 않음 | 필요하면 애플리케이션이 처리 |
TCP Segment와 나란히 놓으면 차이가 분명합니다.
| 비교 | TCP Segment | UDP Datagram |
|---|---|---|
| 누가 크기를 정하나 | TCP (MSS·윈도우 기준) | 애플리케이션 |
| 메시지 경계 | 없음 (바이트 스트림) | 보존 |
| 너무 큰 데이터 | TCP가 여러 Segment로 분할 | IP가 단편화 |
| 길이 확인 | IP 길이에서 계산 | Length 필드에 직접 기록 |
| 한 패킷만 봐도 의미가 있나 | 스트림 재조립이 필요할 수 있음 | 대부분 Datagram 하나로 메시지 완결 |
실습 예시 — 본인 소유 VM 두 대에서 크기가 다른 Datagram을 보내 Length 필드와 단편화를 관찰합니다. 인터페이스 ens33, 포트 9999는 예시입니다.
# 도구 설치
# Rocky Linux
sudo dnf install -y tcpdump nmap-ncat
# Ubuntu
sudo apt install -y tcpdump netcat-openbsd
# [서버 192.168.10.20] 캡처 (UDP 9999 또는 IP 조각)
sudo tcpdump -nn -v -i ens33 'udp port 9999 or (ip[6:2] & 0x1fff != 0)'
# [클라이언트 192.168.10.10] 작은 Datagram 1개 (5바이트: "test" + 줄바꿈)
echo test | nc -u -w1 192.168.10.20 9999
# [클라이언트] 3,000바이트 Datagram 1개 → IP 단편화 발생
head -c 3000 /dev/zero | nc -u -w1 192.168.10.20 9999
tcpdump 출력 형식 예시(값은 환경마다 다름):
IP (... proto UDP (17), length 33) 192.168.10.10.40001 > 192.168.10.20.9999: UDP, length 5
IP (... flags [+], proto UDP (17), length 1500) 192.168.10.10.40002 > 192.168.10.20.9999: UDP, bad length 3000 > 1472
IP (... offset 1480, flags [+], proto UDP (17), length 1500) 192.168.10.10 > 192.168.10.20: ip-proto-17
IP (... offset 2960, proto UDP (17), length 68) 192.168.10.10 > 192.168.10.20: ip-proto-17
| 출력 요소 | 읽는 법 |
|---|---|
UDP, length 5 | UDP 페이로드 5바이트 (Length 필드 값은 13) |
IP length 33 | IP 헤더 20 + UDP 헤더 8 + 데이터 5 |
flags [+] | More Fragments. 뒤에 조각이 더 있음 |
offset 1480 이후 줄 | 두 번째 조각부터는 UDP 헤더가 없어 포트가 표시되지 않음 |
실제 출력 형식은 tcpdump 버전과 옵션에 따라 조금 다를 수 있고, nc 구현에 따라 입력을 여러 Datagram으로 나눠 보낼 수도 있으므로 Length 값을 먼저 확인합니다. Wireshark에서는 udp.length, 재조립 여부는 ip.flags.mf, ip.frag_offset로 확인하며, 패킷 단위 해석은 03. Wireshark 패킷 분석 영역 120. UDP Header 분석에서 다룹니다.
| 흔적 위치 | 확인할 수 있는 것 |
|---|---|
| 패킷 캡처 | Datagram별 Length, 단편화 여부, 요청·응답 크기 비율 |
| 방화벽 로그 | UDP "세션"(실제 연결은 없고 방화벽이 타임아웃으로 묶은 흐름)의 패킷 수·바이트 수 |
| IDS/IPS | 조각 재조립 관련 이벤트, 비정상 크기의 DNS·NTP 등 |
관제자가 확인할 질문
오탐 주의: DNSSEC 응답, 대용량 레코드 조회, 일부 VPN·터널 트래픽은 정상적으로 큰 Datagram이나 단편화를 만듭니다. UDP에는 연결 종료 개념이 없으므로 방화벽의 세션 시간·패킷 수는 방화벽 타임아웃 설정에 따라 달라지는 값이라는 점도 기억해야 합니다.