28. MTU와 IP 단편화 — 큰 패킷이 쪼개질 때

changseop lee·7일 전

📚 네트워크 · 패킷 분석 › 01. TCP/IP 구조 이해 — 28편
이전 글: 27. Ethernet Frame · 다음 글: 29. TCP Segment
참고(리눅스 시스템 기초): Linux 네트워크 구조 — 인터페이스와 커널 네트워크 스택 개요

1. 왜 알아야 하는가

링크마다 한 번에 실어 보낼 수 있는 크기에는 한계가 있습니다. 이 한계를 넘는 IP 패킷은 쪼개지거나(단편화), 버려지고 오류 메시지가 돌아오거나 둘 중 하나입니다.

관제 관점에서 단편화는 두 가지 이유로 중요합니다.

  1. 장애 판단: "ping은 되는데 웹 페이지가 안 열린다", "VPN만 붙으면 특정 사이트가 멈춘다" 같은 현상의 상당수가 MTU 문제입니다. 보안 장비에서 ICMP를 과도하게 막은 것이 원인인 경우도 있어, 보안 정책과 직접 연결됩니다.
  2. 탐지 회피 원리: 정상 트래픽에서 IP 단편화는 생각보다 드뭅니다. 반대로 IDS가 조각을 다시 조립하는 방식과 목적지 호스트가 조립하는 방식이 다르면 탐지를 빗나갈 수 있어, 과거부터 회피 기법으로 연구되어 왔습니다. 그래서 비정상적인 단편화 자체가 관찰 대상이 됩니다.

2. 핵심 개념

2-1. MTU와 MSS

  • MTU(Maximum Transmission Unit): 링크 계층이 한 프레임에 담을 수 있는 IP 패킷 최대 크기입니다. 일반 Ethernet은 1500바이트입니다. Ethernet 헤더(14)와 FCS(4)는 MTU에 포함되지 않아, VLAN 태그가 없는 프레임 전체는 최대 1518바이트입니다.
  • MSS(Maximum Segment Size): TCP가 한 세그먼트에 담는 데이터 최대 크기입니다. IPv4 헤더 20 + TCP 헤더 20을 빼면 1500 - 40 = 1460이 기본값입니다. MSS는 Handshake의 SYN 옵션으로 서로 알립니다.
구간 예시MTU비고
일반 Ethernet1500기본값
PPPoE 회선1492PPPoE 헤더 8바이트만큼 감소
VPN·터널(GRE, IPsec 등)1500보다 작음캡슐화 헤더만큼 감소, 방식마다 다름
점보 프레임9000 전후데이터센터 내부 등 장비 전체가 지원할 때만
루프백(lo)65536 (Linux 기본)실제 링크가 아니라 캡처 시 크기가 크게 보임

경로 전체에서 가장 작은 MTU를 Path MTU라고 합니다. 양 끝단이 1500이라도 중간에 터널이 있으면 Path MTU는 그보다 작습니다.

2-2. 단편화에 쓰이는 IPv4 헤더 필드

필드크기역할
Identification16비트같은 원본 패킷에서 나온 조각을 묶는 번호 (조각끼리 같은 값)
Flags – DF (Don't Fragment)1비트1이면 쪼개지 말 것. 넘치면 버리고 ICMP 오류 반환
Flags – MF (More Fragments)1비트1이면 뒤에 조각이 더 있음. 마지막 조각만 0
Fragment Offset13비트이 조각 데이터가 원본 데이터의 어디부터인지, 8바이트 단위
Total Length16비트이 조각 자체의 길이(헤더 포함)

Fragment Offset이 8바이트 단위이기 때문에, 마지막 조각을 제외한 모든 조각의 데이터 길이는 8의 배수여야 합니다. MTU 1500에서 IP 헤더 20을 빼면 1480이고, 1480 = 8 × 185이므로 조건을 만족합니다.

2-3. 누가 쪼개고 누가 붙이나

  • IPv4: 출발지 호스트뿐 아니라 중간 라우터도 DF가 0이면 쪼갤 수 있습니다.
  • 재조립은 최종 목적지만 합니다. 중간 라우터는 조각을 붙이지 않고 그대로 전달합니다. (방화벽·IDS·NAT 장비는 검사를 위해 내부적으로 재조립하기도 합니다.)
  • 조각 중 하나라도 도착하지 않으면 목적지는 일정 시간 기다린 뒤 전체를 버립니다. TCP라면 재전송이 필요해집니다.
  • IPv6는 중간 라우터가 쪼개지 않고, 출발지만 확장 헤더로 단편화합니다(다음 글에서 다룸).

2-4. PMTUD — 쪼개지 않고 맞추는 방법

현대 OS의 TCP는 대부분 DF=1로 보내고 Path MTU를 스스로 찾는 방식(PMTUD, Path MTU Discovery) 을 씁니다. 단편화는 성능과 신뢰성에 불리하기 때문입니다.

  1. 출발지가 DF=1인 1500바이트 패킷 전송
  2. MTU가 더 작은 구간의 라우터가 패킷을 버리고 ICMP Type 3 Code 4 (Fragmentation Needed and DF set) 를 반환, 이 메시지에 다음 구간 MTU가 담김
  3. 출발지는 해당 목적지에 대한 Path MTU를 낮춰 기억하고 작은 크기로 재전송

이 과정은 ICMP가 돌아와야만 동작합니다. 중간 방화벽이 ICMP를 전부 막으면 출발지는 이유를 모른 채 큰 패킷만 계속 잃게 되는데, 이를 PMTUD 블랙홀이라고 합니다. Handshake와 작은 요청은 되는데 큰 응답만 멈추는 증상이 대표적입니다. 이를 피하려고 경로 장비에서 SYN의 MSS 값을 낮춰 주는 MSS Clamping을 쓰기도 합니다.


3. 동작 원리

ICMP 데이터 3000바이트 + ICMP 헤더 8바이트 = IP 데이터 3008바이트짜리 패킷을 MTU 1500 링크로 DF=0으로 보낸다고 해 보겠습니다.

IP 단편화 구조
그림 1. 세 조각은 같은 ID를 공유하고, offset과 MF 플래그로 순서·끝을 표시합니다

원본 IPv4 패킷: IP 헤더 20 + 데이터 3008  (ID=0x1a2b)
                        ↓  MTU 1500 → 조각당 데이터 최대 1480 (8의 배수)
┌─────────────────────────────────────────────────────────────────┐
│ 조각1: ID=0x1a2b  MF=1  Offset=0    (0/8)     데이터 1480  TotalLen 1500 │
│ 조각2: ID=0x1a2b  MF=1  Offset=185  (1480/8)  데이터 1480  TotalLen 1500 │
│ 조각3: ID=0x1a2b  MF=0  Offset=370  (2960/8)  데이터   48  TotalLen   68 │
└─────────────────────────────────────────────────────────────────┘
                        ↓  각 조각은 독립된 IP 패킷으로 전달
               목적지: 같은 (출발지, 목적지, 프로토콜, ID) 조각 수집
                        ↓  Offset 순서대로 배치, MF=0 조각으로 끝 확인
               재조립 완료 → 3008바이트 → ICMP 계층으로 전달

여기서 관제에 중요한 사실은 첫 번째 조각에만 상위 계층(TCP/UDP/ICMP) 헤더가 들어 있다는 점입니다. 두 번째 조각부터는 포트 번호가 없습니다. 포트 기반 방화벽 규칙이나 5-tuple 로그가 조각을 온전히 판단하려면 재조립이나 상태 추적이 필요한 이유입니다.


4. 실제 명령어 / 실습

실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu), 인터페이스 이름은 ens33 예시입니다. 대상은 같은 대역의 게이트웨이나 다른 VM(192.168.10.1)으로 합니다.

4-1. 도구 설치

# Rocky Linux (tracepath는 iputils에 포함)
sudo dnf install -y tcpdump iputils iproute

# Ubuntu
sudo apt update && sudo apt install -y tcpdump iputils-ping iputils-tracepath iproute2

4-2. 인터페이스 MTU 확인

ip link show ens33          # "mtu 1500" 확인
ip -s link show ens33       # 송수신 오류·드롭 카운터도 함께

4-3. DF 비트로 경로 한계 시험

ping의 -s는 ICMP 데이터 크기입니다. 1472 + ICMP 헤더 8 + IP 헤더 20 = 1500이 됩니다.

# DF=1로 전송 (-M do): 1500 딱 맞음 → 성공해야 정상
ping -M do -s 1472 -c 3 192.168.10.1

# 1바이트 초과 → 로컬에서 이미 거부됨
ping -M do -s 1473 -c 3 192.168.10.1

4-4. 단편화된 패킷 직접 만들어 관찰

# 터미널 1: 조각만 캡처 (MF=1 이거나 Offset≠0 인 IPv4 패킷)
sudo tcpdump -i ens33 -nn -v 'ip[6:2] & 0x3fff != 0'

# 터미널 2: DF를 끄고(-M dont) 큰 ping 1회
ping -M dont -s 3000 -c 1 192.168.10.1

ip[6:2]는 IP 헤더 6번째 바이트부터 2바이트(Flags + Fragment Offset)이고, 0x3fff는 MF 비트와 13비트 Offset만 골라내는 마스크입니다. DF 비트(0x4000)는 제외됩니다.

📷 [실습 화면 삽입] tcpdump -v 출력에서 세 조각의 id, offset, flags [+], length 값이 3장 예시와 일치하는 부분

4-5. Path MTU와 커널 통계

tracepath -n 192.168.10.1                 # 경로상 pmtu 표시
ip route get 192.168.10.1                 # 경로 캐시에 낮아진 mtu가 기록돼 있으면 함께 표시됨
nstat -az IpFragCreates IpFragOKs IpFragFails IpReasmReqds IpReasmOKs IpReasmFails
sysctl net.ipv4.ip_no_pmtu_disc net.ipv4.ipfrag_time

5. 결과 확인

ping -M do -s 1473 출력 형식 예시(값은 환경마다 다름):

ping: local error: message too long, mtu=1500

tcpdump -v 조각 출력 형식 예시(값은 환경마다 다름):

IP (tos 0x0, ttl 64, id 6699, offset 0, flags [+], proto ICMP (1), length 1500)
    192.168.10.20 > 192.168.10.1: ICMP echo request, id 7, seq 1, length 1480
IP (tos 0x0, ttl 64, id 6699, offset 1480, flags [+], proto ICMP (1), length 1500)
    192.168.10.20 > 192.168.10.1: ip-proto-1
IP (tos 0x0, ttl 64, id 6699, offset 2960, flags [none], proto ICMP (1), length 68)
    192.168.10.20 > 192.168.10.1: ip-proto-1

tcpdump는 offset을 바이트로 환산해서(185 × 8 = 1480) 보여 주고, Wireshark는 Fragment Offset: 1480처럼 바이트로 표시하는 경우가 많습니다. 헤더 원값은 8로 나눈 185·370이라는 점을 구분해야 합니다. 두 번째 조각부터는 ICMP 헤더가 없어 ip-proto-1로만 표시되는 것도 확인할 수 있습니다.

확인 항목기대값
세 조각의 id모두 동일
flags앞 두 조각 [+](MF=1), 마지막 [none]
offset0 → 1480 → 2960 (바이트 환산)
length 합계 - 헤더1480 + 1480 + 48 = 3008
  • ip link로 ens33 MTU를 확인했다
  • -M do -s 1472 성공, -s 1473 실패를 확인하고 계산 근거(1472+8+20)를 설명할 수 있다
  • 조각의 Identification이 모두 같음을 확인했다
  • Offset이 8바이트 단위라는 것을 원값과 환산값으로 검산했다
  • 두 번째 조각부터 상위 계층 헤더가 없다는 것을 확인했다
  • nstat에서 IpFragCreates / IpReasm 카운터 변화를 확인했다

6. 패킷 / 로그 분석

6-1. 필터

도구필터의미
Wiresharkip.flags.mf == 1 or ip.frag_offset > 0모든 IPv4 조각
Wiresharkip.flags.df == 1DF가 설정된 패킷
Wiresharkicmp.type == 3 && icmp.code == 4Fragmentation Needed (PMTUD 신호)
tcpdump'ip[6:2] & 0x3fff != 0'모든 IPv4 조각
tcpdump'icmp[0] == 3 and icmp[1] == 4'Fragmentation Needed

Wireshark는 기본적으로 조각을 재조립해 마지막 조각 위치에 [Reassembled IPv4 in frame: N]처럼 표시합니다. 조각 하나하나를 보려면 IPv4 프로토콜 설정의 재조립 옵션을 끄고 비교해 보는 것이 좋습니다.

6-2. 정상일 수 있는 경우 vs 의심해야 하는 경우

관찰정상일 수 있는 경우의심해야 하는 경우
UDP 조각DNS 대용량 응답(EDNS), 일부 VPN·터널, NFS 등출발지 다수에서 조각만 대량 유입 → 조각 재조립 자원을 소모시키는 DoS 원리
아주 작은 첫 조각거의 없음첫 조각에 TCP 헤더조차 다 담기지 않을 만큼 작음 → 포트 필터 우회 시도 형태
조각끼리 Offset이 겹침정상 스택에서는 발생하지 않음재조립 방식 차이를 노린 IDS 회피 형태, 과거 OS 취약점(Teardrop류) 원리
재조립 결과가 65,535 초과발생할 수 없음과거 Ping of Death 원리, 현대 OS는 폐기
ICMP Type 3 Code 4터널·PPPoE 구간이 있는 정상 PMTUD내부 경로와 무관한 출발지에서 대량 수신 → 위조 ICMP 가능성 확인
큰 응답만 끊김—ICMP 전면 차단으로 인한 PMTUD 블랙홀 (보안 정책 점검 대상)
# pcap에서 조각 수와 출발지별 분포 확인
tshark -r capture.pcap -Y 'ip.flags.mf == 1 || ip.frag_offset > 0' \
  -T fields -e ip.src -e ip.id | sort | uniq -c | sort -rn | head

📷 [실습 화면 삽입] Wireshark에서 재조립 옵션을 끈 상태와 켠 상태의 패킷 목록 비교 — Fragmented IP protocol 표시와 Reassembled 표시


7. 보안관제 관점

흔적이 남는 곳

  • IDS/IPS: Suricata·Snort 계열은 조각을 재조립한 뒤 검사하며, 재조립 과정의 이상(겹침, 비정상 크기 등)에 대한 이벤트를 따로 제공하는 경우가 많습니다. 세부 설정은 06. 방화벽 · IDS/IPS 분석 시리즈에서 다룹니다.
  • 방화벽: 상태 기반 방화벽은 첫 조각의 포트 정보로 후속 조각을 판단하거나, 내부 재조립 후 정책을 적용합니다. 조각 폐기·재조립 실패 카운터가 남는 장비가 많습니다.
  • 호스트: nstat의 IpReasmFails가 급증하면 조각 유실 또는 비정상 조각 유입을 의심할 수 있습니다.

관제 판단 포인트

  • 일반 기업망의 TCP 트래픽은 PMTUD 덕분에 거의 단편화되지 않습니다. TCP 조각이 지속적으로 보이면 경로 MTU 설정 문제이거나 의도적으로 만든 트래픽일 가능성을 모두 검토합니다.
  • 보안 정책에서 ICMP를 막을 때 Type 3(Destination Unreachable), 특히 Code 4까지 막으면 서비스 장애로 이어집니다. "보안 강화"가 장애 원인이 되는 대표 사례입니다. ICMP 자체는 06. ICMP와 ping 에서 다뤘습니다.
  • 조각 필드의 정밀 해석(Wireshark 필드 단위)은 03. Wireshark 패킷 분석 시리즈의 09. IP 헤더 분석 에서 이어집니다.

한계와 오탐 주의

  • 조각 트래픽 = 공격이 아닙니다. 대용량 DNS 응답이나 터널 환경에서는 정상적으로 발생합니다. 출발지, 양, 조각 형태(겹침·극소 조각)를 함께 봐야 합니다.
  • 캡처 장비가 조각 일부를 놓치면 재조립 실패처럼 보일 수 있습니다.

8. 핵심 정리

  • MTU는 링크가 담을 수 있는 IP 패킷 최대 크기(Ethernet 1500)이고, TCP MSS는 여기서 IP·TCP 헤더를 뺀 값(기본 1460)입니다.
  • 단편화는 Identification(같은 원본 묶음), MF(뒤에 더 있음), Fragment Offset(8바이트 단위 위치)으로 표현되며 재조립은 최종 목적지가 합니다.
  • 첫 조각에만 포트 정보가 있어, 조각 트래픽은 포트 기반 필터와 로그 판단을 어렵게 만듭니다.
  • 현대 TCP는 DF=1과 PMTUD로 단편화를 피하며, ICMP Type 3 Code 4를 막으면 PMTUD 블랙홀이 생깁니다.
  • 관제에서는 조각의 존재 자체보다 극소 조각·Offset 겹침·대량 조각 유입 같은 비정상 형태와 재조립 실패 지표에 주목합니다.

다음 글: 13. IPv6 기초 — 관제에서 놓치기 쉬운 두 번째 주소 체계

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글