네트워크를 공부하다 보면 패킷 구조 그림을 자주 보게 됩니다.
Ethernet Header, IPv4 Header, TCP Header가 차례대로 붙어 있고,
각 헤더 안에는
MAC 주소, IP 주소, 포트 번호, Sequence Number, Acknowledgment Number 같은 값들이 들어 있습니다.
처음에는 이 구조가 단순히 책에 있는 그림처럼 느껴질 수 있습니다.
하지만 실제 네트워크 통신에서도 이 구조는 그대로 사용됩니다.
이번 글에서는 macOS에서 Wireshark GUI를 사용해 실제 TCP 패킷을 캡처하고,
책에서 보던 Ethernet Header, IPv4 Header, TCP Header가 실제 패킷 안에서 어떻게 보이는지 확인해보겠습니다.
그리고 Wireshark 화면 아래쪽에 표시되는 16진수 덤프도 함께 해석해보겠습니다.
Wireshark가 보기 좋게 정리해준 값만 보는 것이 아니라,
패킷의 원본 바이트가 어떤 규칙으로 Ethernet, IP, TCP 헤더로 나뉘는지도 확인하는 것이 목표입니다.
이번 실습에서 확인할 것
이번 실습에서 확인할 핵심 구조는 다음과 같습니다.
Ethernet II
→ Internet Protocol Version 4
→ Transmission Control Protocol
→ 실제 데이터
첫 번째로 Ethernet II를 확인합니다.
여기서는 출발지 MAC 주소, 목적지 MAC 주소,
그리고 Ethernet Header 뒤에 어떤 프로토콜이 들어 있는지 확인합니다.
두 번째로 Internet Protocol Version 4를 확인합니다.
여기서는 출발지 IP 주소, 목적지 IP 주소, TTL, Protocol, Total Length 등을 확인합니다.
세 번째로 Transmission Control Protocol을 확인합니다.
여기서는 출발지 포트, 목적지 포트,
Sequence Number, Acknowledgment Number, Flags, Window Size 등을 확인합니다.
마지막으로 Wireshark 하단에 보이는 16진수 덤프를 해석합니다.
16진수 덤프는 Wireshark가 해석하기 전의 원본 패킷 바이트입니다.
이 값을 직접 나눠보면,
Wireshark가 어떤 기준으로 Ethernet Header, IPv4 Header, TCP Header를 구분하는지 이해할 수 있습니다.
패킷은 데이터만 보내는 것이 아니다
웹사이트에 접속할 때 우리는 보통 주소창에 주소를 입력하거나,
터미널에서 curl 명령어를 실행합니다.
겉으로 보기에는 단순히 요청 하나를 보내는 것처럼 보입니다.
하지만 실제 네트워크 내부에서는 데이터 앞에 여러 계층의 헤더가 붙습니다.
구조는 다음과 같습니다.
Ethernet Header
→ IP Header
→ TCP Header
→ Application Data
Ethernet Header는 같은 네트워크 구간에서 다음 장비로 보내기 위한 정보입니다.
IP Header는 출발지 컴퓨터와 목적지 컴퓨터를 찾기 위한 정보입니다.
TCP Header는 어떤 프로그램끼리 통신하는지,
데이터 순서와 응답을 어떻게 맞출지 관리하는 정보입니다.
따라서 패킷은 단순한 데이터 덩어리가 아니라,
각 계층의 정보가 차례대로 붙은 구조라고 볼 수 있습니다.
Wireshark 캡처 시작
먼저 Wireshark를 실행합니다.
초기 화면에는 여러 네트워크 인터페이스가 보입니다.

맥북에서 Wi-Fi를 사용 중이라면 보통 Wi-Fi 또는 en0 인터페이스를 선택하면 됩니다.
인터페이스를 고를 때는 그래프가 움직이는 것을 선택합니다.
그래프가 움직인다는 것은 그 인터페이스를 통해 실제 패킷이 지나가고 있다는 의미입니다.
Wi-Fi 또는 en0를 더블클릭하면 캡처가 시작됩니다.
캡처가 시작되면 화면에 패킷들이 계속 올라옵니다.

DNS, TCP, TLS, ARP, mDNS, ICMPv6 같은 이름들이 보일 수 있습니다.
정상입니다.
내가 아무것도 하지 않는 것처럼 보여도,
맥북은 백그라운드에서 계속 네트워크 통신을 하고 있기 때문입니다.
IPv4 TCP 패킷 만들기
이번 실습에서는 IPv4 Header와 TCP Header를 확인할 것입니다.
그래서 터미널에서 IPv4를 사용하는 HTTPS 요청을 하나 만들어줍니다.
Wireshark 캡처를 켜둔 상태에서 터미널을 열고 다음 명령어를 실행합니다.
curl -4 https://example.com
여기서 중요한 옵션은 -4입니다.
이 옵션을 붙이지 않으면 환경에 따라 IPv6 패킷이 잡힐 수 있습니다.
IPv6도 IP 계층 프로토콜이지만,
IPv4와 헤더 구조가 다릅니다.
이번 실습에서는 IPv4 Header를 확인하는 것이 목적이므로 -4 옵션을 붙여줍니다.
명령어를 실행하면 터미널에 HTML 내용이 출력될 수 있습니다.
이 출력 내용 자체는 중요하지 않습니다.
중요한 것은 이 요청 때문에 Wireshark에 TCP 패킷이 잡힌다는 점입니다.
Wireshark에서 IPv4 TCP 패킷만 보기
이제 Wireshark 화면으로 돌아갑니다.
상단 Display Filter 입력창에 다음 필터를 입력합니다.
tcp && ip
이 필터는 TCP이면서 IPv4인 패킷만 보여달라는 의미입니다.
필터를 적용하면 화면에 TCP 패킷들만 남습니다.
패킷이 너무 많이 보인다면 다음 필터를 사용할 수도 있습니다.
tcp && ip && tcp.port == 443
tcp.port == 443은 출발지 포트 또는 목적지 포트 중 하나가 443번인 TCP 패킷만 보여달라는 의미입니다.
443번 포트는 HTTPS 통신에서 주로 사용하는 포트입니다.
이번 실습에서는 https://example.com으로 요청을 보냈기 때문에,
443번 포트가 포함된 패킷을 보면 실습 트래픽을 찾기 쉽습니다.
SYN 패킷 선택
필터를 적용한 뒤 TCP SYN 패킷 하나를 선택합니다.
SYN은 TCP 연결을 처음 시작할 때 보내는 패킷입니다.
이번 글에서는 헤더 구조와 16진수 덤프를 함께 확인해야 하므로,
SYN 패킷을 선택하는 것이 좋습니다.
SYN 패킷은 아직 실제 데이터를 보내는 단계가 아닙니다.
그래서 Ethernet Header, IPv4 Header, TCP Header 구조를 나누어 보기 쉽습니다.
또한 TCP Options가 포함되어 있는 경우가 많아,
MSS, Window Scale, SACK Permitted 같은 값도 함께 확인할 수 있습니다.
패킷 상세 화면 펼치기
패킷 하나를 클릭하면 Wireshark 아래쪽에 패킷 상세 정보가 표시됩니다.

여기서 다음 항목을 펼칩니다.
Ethernet II
Internet Protocol Version 4
Transmission Control Protocol
이 세 항목이 이번 실습의 핵심입니다.
책에서 보던 Ethernet Header, IPv4 Header, TCP Header를 실제 패킷에서 확인하는 부분입니다.
또한 Wireshark 화면 가장 아래 오른쪽에는 16진수 값들이 표시됩니다.

이 값은 선택한 패킷의 원본 바이트입니다.
Wireshark는 이 원본 바이트를 읽고,
그 값을 사람이 보기 쉽게 Ethernet, IPv4, TCP 항목으로 해석해줍니다.
Ethernet II 헤더 해석
먼저 Ethernet II 항목을 확인합니다.
이번 캡처에서 Ethernet II는 다음과 같이 표시되었습니다.
Ethernet II, Src: 7e:23:0c:58:6d:09, Dst: Mercury_5e:1c:e8 (50:46:ae:5e:1c:e8)
여기서 확인한 값은 다음과 같습니다.
Destination MAC: 50:46:ae:5e:1c:e8
Source MAC: 7e:23:0c:58:6d:09
Type: IPv4 (0x0800)
Destination MAC은 이 Ethernet Frame을 받을 다음 장비의 MAC 주소입니다.
여기서 중요한 점은 Destination MAC이 최종 웹 서버의 MAC 주소가 아닐 가능성이 높다는 것입니다.
내 맥북은 외부 인터넷 서버로 바로 Ethernet Frame을 보내는 것이 아니라,
현재 네트워크에서 먼저 공유기나 게이트웨이 같은 다음 장비로 보냅니다.
따라서 Destination MAC은 최종 목적지 서버가 아니라,
현재 네트워크 구간에서 다음으로 전달받을 장비의 주소라고 볼 수 있습니다.
Wireshark가 Destination을 Mercury_5e:1c:e8처럼 표시한 것은,
MAC 주소 앞부분을 보고 제조사 정보를 추정해서 보여준 것입니다.
실제 MAC 주소는 괄호 안의 50:46:ae:5e:1c:e8입니다.
한번 직접 보면
route -n get default
arp -n (위의 결과물에서 ip주소)

저는 와이파이를 써서 공유기와 연결되어 있는데 보면 와이어샤크에 나온 dst 맥주소는 웹서버 맥주소가 아닌
저희집 공유기 맥 주소인 것을 확인 할 수 있었습니다.
Wireshark 화면을 보면 Destination MAC의 LG bit가 Globally unique address로 표시됩니다.
이 말은 해당 MAC 주소가 공장에서 부여된 전역적으로 고유한 주소 형식이라는 뜻입니다.
또한 IG bit가 Individual address로 표시됩니다.
이 말은 이 프레임이 브로드캐스트나 멀티캐스트가 아니라,
특정 장비 하나에게 가는 유니캐스트 프레임이라는 뜻입니다.
Source MAC은 이 프레임을 보낸 장비의 MAC 주소입니다.
이번 캡처에서는 7e:23:0c:58:6d:09로 표시되었습니다.
마지막으로 Type은 IPv4 (0x0800)입니다.
이 값이 중요합니다.
Ethernet Header만 보면 그 뒤에 어떤 데이터가 오는지 알 수 없습니다.
그래서 Ethernet Header 안의 Type 필드를 보고 다음 프로토콜을 판단합니다.
이번 패킷에서는 Type 값이 0x0800이므로,
Ethernet Header 뒤에는 IPv4 패킷이 들어 있다는 것을 알 수 있습니다.
IPv4 헤더 해석
다음으로 Internet Protocol Version 4 항목을 확인합니다.
이번 캡처에서 IPv4 Header의 주요 값은 다음과 같습니다.
Version: 4
Header Length: 20 bytes
Differentiated Services Field: 0x00
DSCP: CS0
ECN: Not-ECT
Total Length: 64
Identification: 0x0000
Flags: 0x2, Don’t fragment
Fragment Offset: 0
Time to Live: 64
Protocol: TCP (6)
Header Checksum: 0x4d5f, correct
Source Address: 172.30.1.5
Destination Address: 172.66.147.243
Version 값은 4입니다.
즉 이 패킷은 IPv4 패킷입니다.
Header Length는 20 bytes입니다.
IPv4 Header의 기본 길이는 20바이트입니다.
이번 캡처에서도 Header Length가 20바이트로 표시되므로,
IPv4 Options는 붙어 있지 않은 기본 IPv4 Header라고 볼 수 있습니다.
옵션이 있으면 최대 60바이트까지 커질 수 있습니다.
Total Length는 64입니다.
이 값은 IPv4 Header부터 그 뒤의 TCP Header까지 포함한 길이입니다.
주의할 점은 Total Length가 Ethernet Header까지 포함한 길이가 아니라는 점입니다.
이번 패킷의 IP Total Length는 64바이트이고,
이 64바이트 안에는 IPv4 Header 20바이트와 TCP Header 44바이트가 들어 있습니다.
계산하면 다음과 같습니다.
IPv4 Total Length 64 bytes
= IPv4 Header 20 bytes
+ TCP Header 44 bytes
+ Application Data 0 bytes
이번 패킷은 TCP SYN 패킷이므로 실제 Application Data는 없습니다.
Identification은 0x0000입니다.
Identification은 IP 패킷이 단편화되었을 때,
쪼개진 조각들이 원래 같은 IP 패킷에서 나온 것인지 구분하기 위한 값입니다.
이번 패킷에서는 단편화가 발생하지 않았습니다.
Flags는 Don’t fragment(DF)로 표시되었습니다.
Don’t fragment(DF)는 이 IP 패킷을 중간에서 쪼개지 말라는 의미입니다.
Fragment Offset은 0입니다.
Fragment Offset은 쪼개진 IP 조각이 원래 데이터의 어느 위치에 해당하는지를 나타냅니다.
이번 패킷은 단편화된 패킷이 아니므로 Fragment Offset은 0입니다.
Time to Live는 64입니다.
TTL은 패킷이 네트워크 안에서 무한히 떠돌지 않도록 제한하는 값입니다.
라우터를 하나 지날 때마다 TTL은 1씩 줄어듭니다.
TTL이 0이 되면 패킷은 폐기됩니다.
Protocol은 TCP (6)입니다.
이 값도 중요합니다.
IPv4 Header는 자기 뒤에 어떤 전송 계층 프로토콜이 오는지 Protocol 필드로 알려줍니다.
이번 패킷에서는 Protocol 값이 6이므로,
IPv4 Header 뒤에는 TCP Header가 온다는 것을 알 수 있습니다.
참고로 UDP값은 17입니다.
Header Checksum은 0x4d5f이고 correct로 표시되었습니다.
IPv4 Header Checksum은 IPv4 Header 자체가 손상되지 않았는지 확인하기 위한 값입니다.
Wireshark가 correct라고 표시했으므로,
캡처된 IPv4 Header Checksum은 정상으로 해석됩니다.
Source Address는 172.30.1.5입니다.
이 주소는 내 맥북이 현재 네트워크에서 사용 중인 IPv4 주소입니다.
172.30.x.x 대역은 사설 IP 주소 범위에 포함됩니다.
제 맥북이 내부 네트워크에서 사용하는 주소라고 볼 수 있습니다.
Destination Address는 172.66.147.243입니다.
이 주소는 내 맥북이 TCP 연결을 시도한 외부 서버의 IPv4 주소입니다.
여기서 주의할 점은 172로 시작한다고 해서 무조건 사설 IP가 아니라는 것입니다.
사설 IP로 예약된 172 대역은 172.16.0.0부터 172.31.255.255
즉 172.16.0.0/12 범위 까지입니다.
172.66.147.243은 이 범위에 포함되지 않으므로 공인 IP 주소입니다.
TCP 헤더 해석
이번 캡처에서 TCP Header는 16진수 덤프 기준으로 다음과 같이 시작합니다.
fa a1 01 bb bc d7 85 13 00 00 00 00 b0 c2 ff ff 80 89 00 00
이 부분은 TCP 기본 헤더 20바이트입니다.
해석하면 다음과 같습니다.
Source Port: 64161
Destination Port: 443
Sequence Number raw: 3168240915
Acknowledgment Number raw: 0
Header Length: 44 bytes
Flags: SYN, ECE, CWR
Window: 65535
Checksum: 0x8089
Urgent Pointer: 0
Source Port는 64161입니다.
이 포트는 내 맥북에서 임시로 사용한 포트입니다.
클라이언트가 서버에 접속할 때 운영체제가 임시 포트를 하나 선택합니다.
이런 포트를 임시 포트 또는 ephemeral port라고 부릅니다.
Destination Port는 443입니다.
443번 포트는 HTTPS 통신에서 주로 사용하는 포트입니다.
따라서 이 패킷은 내 맥북의 64161번 포트에서 외부 서버의 443번 포트로 TCP 연결을 시작하려는 패킷입니다.
Acknowledgment Number는 0입니다.
이 패킷은 TCP 연결을 시작하는 첫 번째 SYN 패킷입니다.
아직 상대방에게 받은 데이터가 없기 때문에 확인 응답할 번호도 없습니다.
그래서 ACK 번호는 0입니다.
Header Length는 44 bytes입니다.
TCP Header의 기본 길이는 20바이트입니다.
그런데 이번 패킷에서는 44바이트입니다.
이 말은 기본 TCP Header 20바이트 뒤에 TCP Options 24바이트가 붙어 있다는 뜻입니다.
따라서 TCP Header는 항상 20바이트라고 보면 안 됩니다.
정확히는 TCP Header의 최소 길이가 20바이트이고,
Options가 붙으면 그보다 더 길어질 수 있습니다.
이번 패킷에서는 다음과 같이 구성됩니다.
TCP Header 전체 44 bytes
= 기본 TCP Header 20 bytes
+ TCP Options 24 bytes
Flags는 SYN, ECE(ECN echo), CWR(Congestion windonw Reduced)입니다.
이 중에서 가장 중요한 것은 SYN입니다.
SYN은 TCP 연결을 시작하겠다는 의미입니다.
따라서 이 패킷은 TCP 3-way handshake의 첫 번째 패킷입니다.
ECE와 CWR은 ECN과 관련된 플래그입니다.
ECN은 Explicit Congestion Notification의 줄임말입니다.
패킷 손실이 발생하기 전에 네트워크 혼잡 상태를 명시적으로 알려주기 위한 기능입니다.
이번 글의 핵심은 TCP SYN 패킷을 확인하는 것이므로,
여기서는 SYN 플래그가 켜져 있다는 점이 가장 중요합니다.
Window 값은 65535입니다.
TCP 기본 헤더 안의 Window Size 필드는 2바이트입니다.
2바이트, 즉 16비트로 표현할 수 있는 최대값은 65535입니다.
이번 캡처에서는 Window 필드가 ff ff로 들어 있었고,
이를 10진수로 바꾸면 65535가 됩니다.
다만 TCP Options에 Window Scale 값 6이 포함되어 있으므로,
연결이 성립된 뒤에는 Window Size 값을 2^6, 즉 64배 확장해서 해석할 수 있습니다.
주의할 점은 Window Scale이 "이 패킷 하나에 몇 바이트를 보낼 수 있는가"를 의미하지 않는다는 것입니다.
패킷 하나에 실을 수 있는 데이터 크기와 더 가까운 값은 MSS입니다.
Window Scale은 TCP Window Size 필드의 값을 더 크게 해석하기 위한 배율 옵션입니다.
상대방에게
"내가 ACK를 보내기 전까지 어느 정도의 데이터를 연속으로 받을 수 있는지"를 더 큰 범위로 표현하기 위한 값입니다.
Checksum은 0x8089입니다.
TCP Checksum은 TCP Header와 데이터가 손상되지 않았는지 확인하기 위한 값입니다.
다만 Wireshark에서 TCP Checksum이 unverified로 보일 수 있습니다.
unverified는 무조건 오류라는 뜻이 아닙니다.
네트워크 카드의 체크섬 오프로딩 기능 때문에,
Wireshark가 캡처 시점에서 TCP Checksum을 완전히 검증하지 못하는 경우가 있습니다.
Urgent Pointer는 0입니다.
Urgent Pointer는 TCP의 긴급 데이터와 관련된 필드입니다.
이번 패킷에서는 사용되지 않았습니다.
이번 패킷은 SYN 패킷이므로 실제 TCP 데이터는 없습니다.
따라서 TCP Segment Len은 0입니다.
데이터를 보내는 패킷이 아니라,
TCP 연결을 시작하기 위한 제어 패킷이라고 볼 수 있습니다.
TCP Options 해석
TCP Options는 TCP 기본 헤더 뒤에 붙는 추가 설정 영역입니다.
TCP 기본 헤더 20바이트만으로도 통신은 가능하지만,
더 효율적이고 안정적인 통신을 위해 연결을 시작할 때 여러 추가 기능을 협상할 수 있습니다.
이번 캡처에서 TCP Options는 총 24바이트입니다.
Wireshark 화면에서는 다음과 같이 표시되었습니다.
TCP Option - Maximum segment size: 1460 bytes
TCP Option - No-Operation (NOP)
TCP Option - Window scale: 6 (multiply by 64)
TCP Option - No-Operation (NOP)
TCP Option - No-Operation (NOP)
TCP Option - Timestamps: TSval 509832110, TSecr 0
TCP Option - SACK permitted
TCP Option - End of Option List (EOL)
TCP Option - End of Option List (EOL)
MSS는 Maximum Segment Size의 줄임말입니다.
TCP가 한 번에 실을 수 있는 최대 데이터 크기를 의미합니다.
이번 캡처에서는 MSS 값이 1460 bytes입니다.
이는 일반적인 Ethernet MTU 1500 환경에서 자주 볼 수 있는 값입니다.
Ethernet MTU가 1500바이트일 때,
IPv4 Header 20바이트와 TCP Header 20바이트를 제외하면,
TCP 데이터로 실을 수 있는 크기가 1460바이트가 됩니다.
Window Scale 값은 6입니다.
정확히 말하면 Window Scale shift count가 6입니다.
이 값은 Window Size를 2의 6제곱만큼 확장해서 해석할 수 있다는 의미입니다.
2^6 = 64
이후 TCP 연결에서 이쪽이 광고하는 Window Size 값은 64배 확장해서 해석될 수 있습니다.
예를 들어 이후 패킷에서 Window 필드가 65535이고 Window Scale 6이 적용된다면,
실제 계산 윈도우 크기는 다음과 같이 계산할 수 있습니다.
65535 × 64 = 4,194,240 bytes
다만 이것은 패킷 하나에 4MB를 담아 보낸다는 뜻이 아닙니다.
이 값은 상대방이 ACK를 받기 전까지 연속으로 보낼 수 있는 데이터 양,
즉 수신 윈도우 크기와 관련된 값입니다.
Timestamp 옵션은 TCP 패킷에 시간값을 넣기 위한 옵션입니다.
이번 캡처에서는 TSval이 509832110이고 TSecr은 0입니다.
TSval은 이쪽에서 보낸 타임스탬프 값입니다.
TSecr은 상대방에게서 받은 타임스탬프를 다시 되돌려주는 값입니다.
첫 SYN 패킷에서는 아직 상대방의 Timestamp를 받은 상태가 아니므로,
TSecr 값이 0으로 들어갈 수 있습니다.
SACK Permitted는 Selective Acknowledgment를 허용한다는 뜻입니다.
일부 데이터만 손실되었을 때,
수신자가 받은 부분과 못 받은 부분을 더 정확하게 알려줄 수 있게 해줍니다.
NOP는 No Operation의 줄임말입니다.
실제 기능을 수행한다기보다,
TCP Options의 길이를 맞추기 위한 정렬용 값으로 사용됩니다.
End of Option List는 옵션 목록이 끝났다는 뜻입니다.
이번 캡처에서는 EOL이 두 번 표시되었습니다.
실제로는 첫 번째 00이 옵션 끝을 의미하고,
그 뒤의 00은 4바이트 정렬을 맞추기 위한 padding처럼 볼 수 있습니다.
(TCP는 32비트 단위로 중요한 정보가 쪼개져 있습니다 즉 32비트 단위로 읽게 설계되었습니다)
Wireshark에서는 이 값을 End of Option List로 한 줄 더 표시한 것입니다.
16진수 덤프 전체 구조
이제 Wireshark 하단에 보이는 16진수 덤프를 해석해보겠습니다.
이번 캡처에서 확인한 16진수 값은 다음과 같습니다.

처음 보면 단순한 숫자 나열처럼 보입니다.
하지만 이 값은 실제 패킷의 원본 바이트입니다.
앞에서부터 순서대로 읽으면 Ethernet Header, IPv4 Header, TCP Header로 나눌 수 있습니다.
이번 패킷의 전체 구조는 다음과 같습니다.
Ethernet Header: 14 bytes
IPv4 Header: 20 bytes
TCP Header: 44 bytes
Application Data: 0 bytes
전체 길이를 계산하면 다음과 같습니다.
Ethernet Header 14 bytes
+ IPv4 Total Length 64 bytes
= 전체 캡처 바이트 78 bytes
여기서 IPv4 Total Length 64 bytes는 Ethernet Header를 포함하지 않습니다.
IPv4 Total Length는 IPv4 Header부터 시작하는 길이입니다.
또한 일반적인 Wireshark 캡처에서는 Ethernet FCS가 보이지 않는 경우가 많습니다.
대부분의 경우 네트워크 카드가 FCS를 처리한 뒤 운영체제에 넘기기 때문에,
Wireshark 화면에는 FCS가 표시되지 않을 수 있습니다.
16진수 덤프 계층별 분리
전체 16진수 덤프를 계층별로 나누면 다음과 같습니다.

여기서 중요한 점은 Wireshark가 아무렇게나 자르는 것이 아니라는 점입니다.
Ethernet Header의 Type 값을 보고 다음이 IPv4라는 것을 알 수 있습니다.
IPv4 Header의 Header Length 값을 보고 IPv4 Header가 어디까지인지 알 수 있습니다.
IPv4 Header의 Protocol 값을 보고 다음이 TCP라는 것을 알 수 있습니다.
TCP Header의 Header Length 값을 보고 TCP Header가 어디까지인지 알 수 있습니다.
각 계층의 헤더 안에는 다음 계층을 해석하기 위한 단서가 들어 있습니다.
Ethernet Header 16진수 해석
Ethernet Header는 처음 14바이트입니다.
50 46 ae 5e 1c e8 7e 23 0c 58 6d 09 08 00
이 값을 필드별로 나누면 다음과 같습니다.
50 46 ae 5e 1c e8
= Destination MAC
7e 23 0c 58 6d 09
= Source MAC
08 00
= EtherType
해석 결과는 다음과 같습니다.
Destination MAC: 50:46:ae:5e:1c:e8
Source MAC: 7e:23:0c:58:6d:09
EtherType: 0x0800
EtherType 0x0800은 IPv4를 의미합니다.
따라서 Ethernet Header 뒤에 IPv4 Header가 온다는 것을 알 수 있습니다.
IPv4 Header 16진수 해석
IPv4 Header는 Ethernet Header 다음 20바이트입니다.
45 00 00 40 00 00 40 00 40 06 4d 5f ac 1e 01 05 ac 42 93 f3
이 값을 필드별로 나누면 다음과 같습니다.
45
= Version + IHL
00
= DSCP + ECN
00 40
= Total Length
00 00
= Identification
40 00
= Flags + Fragment Offset
40
= TTL
06
= Protocol
4d 5f
= Header Checksum
ac 1e 01 05
= Source IP
ac 42 93 f3
= Destination IP
첫 번째 바이트는 45입니다.
16진수 45는 앞의 4와 뒤의 5를 나누어 해석합니다.
앞의 4는 Version입니다.
IPv4를 의미합니다.
뒤의 5는 IHL입니다.
IHL은 Internet Header Length의 줄임말입니다.
IPv4 Header 길이를 의미합니다.
IHL 값은 4바이트 단위로 계산합니다.
따라서 IHL이 5라면 다음과 같습니다.
5 × 4 bytes = 20 bytes
이번 IPv4 Header의 길이는 20바이트입니다.
다음 바이트 00은 DSCP와 ECN 값입니다.
이번 캡처에서는 DSCP(이 패킷을 얼마나 우선 처리할지 표시하는 값)는 CS0,
ECN은 Not-ECT(이 패킷은 ECN 혼잡 표시를 받을 준비가 안 되어 있음)로 표시되었습니다.
00 40은 Total Length입니다.
16진수 0x0040을 10진수로 바꾸면 64입니다.
따라서 IPv4 Total Length는 64바이트입니다.
00 00은 Identification입니다.
이번 패킷에서는 0으로 표시되었습니다.
40 00은 Flags와 Fragment Offset입니다.
이 값은 Don’t fragment와 Fragment Offset 0으로 해석됩니다.
즉 이 패킷은 단편화하지 말라는 설정이 되어 있고,
현재 단편화된 조각도 아닙니다.
flag는 3비트로 표시되고
첫번째 비트는 reserved, 두번째 비트는 don t fragment 세번째 비트는 more fragement입니다.
Fragment Offset은 13비트로 구성되어 있습니다.
40은 TTL입니다.
16진수 0x40은 10진수로 64입니다.
따라서 TTL 값은 64입니다.
06은 Protocol입니다.
16진수 0x06은 TCP를 의미합니다.
따라서 IPv4 Header 뒤에는 TCP Header가 온다는 것을 알 수 있습니다.
4d 5f는 IPv4 Header Checksum입니다.
Wireshark에서는 이 값을 correct로 표시했습니다.
ac 1e 01 05는 Source IP입니다.
각 바이트를 10진수로 바꾸면 다음과 같습니다.
ac = 172
1e = 30
01 = 1
05 = 5
따라서 Source IP는 172.30.1.5입니다.
ac 42 93 f3는 Destination IP입니다.
각 바이트를 10진수로 바꾸면 다음과 같습니다.
ac = 172
42 = 66
93 = 147
f3 = 243
따라서 Destination IP는 172.66.147.243입니다.
TCP Header 16진수 해석
TCP Header는 IPv4 Header 다음 44바이트입니다.
fa a1 01 bb bc d7 85 13 00 00 00 00 b0 c2 ff ff 80 89 00 00 02 04
05 b4 01 03 03 06 01 01 08 0a 1e 63 6b ae 00 00 00 00 04 02 00 00
먼저 기본 TCP Header 20바이트를 나누면 다음과 같습니다.
fa a1
= Source Port
01 bb
= Destination Port
bc d7 85 13
= Sequence Number
00 00 00 00
= Acknowledgment Number
b0 c2
= Data Offset + Flags
ff ff
= Window Size
80 89
= Checksum
00 00
= Urgent Pointer
fa a1은 Source Port입니다.
16진수 0xfaa1을 10진수로 바꾸면 64161입니다.
01 bb는 Destination Port입니다.
16진수 0x01bb를 10진수로 바꾸면 443입니다.
bc d7 85 13은 Sequence Number입니다.
16진수 0xbcd78513을 10진수로 바꾸면 3168240915입니다.
Wireshark 화면에서는 Sequence Number가 0으로 보일 수 있습니다.
그것은 relative sequence number입니다.
Wireshark가 보기 쉽게 첫 Sequence Number를 0으로 바꿔서 보여주는 것입니다.
실제 원본 Sequence Number는 3168240915입니다.
00 00 00 00은 Acknowledgment Number입니다.
값은 0입니다.
이 패킷은 첫 SYN 패킷이므로 아직 확인 응답할 번호가 없습니다.
b0 c2는 TCP Header Length와 Flags를 담고 있습니다.
먼저 b0의 앞쪽 4비트가 TCP Header Length입니다.
b는 16진수로 11입니다.
TCP Header Length는 4바이트 단위로 계산합니다.
따라서 다음과 같습니다.
11 × 4 bytes = 44 bytes
기본 TCP Header는 20바이트인데,
이번에는 44바이트이므로 TCP Options가 24바이트 붙어 있다는 뜻입니다.
c2는 Flags 값입니다.
Wireshark에서는 전체 Flags를 SYN, ECE, CWR로 해석했습니다.
SYN은 TCP 연결 시작을 의미합니다.
ECE와 CWR은 ECN 기능과 관련된 플래그입니다.
이번 분석에서 가장 중요한 값은 SYN입니다.
이 값 덕분에 이 패킷이 TCP 연결을 시작하는 첫 번째 패킷이라는 것을 알 수 있습니다.
ff ff는 Window Size입니다.
16진수 0xffff는 10진수로 65535입니다.
따라서 Window Size는 65535입니다.
80 89는 TCP Checksum입니다.
00 00은 Urgent Pointer입니다.
이번 패킷에서는 긴급 데이터 기능을 사용하지 않으므로 값은 0입니다.
TCP Options 16진수 해석
TCP Header가 44바이트였으므로,
기본 TCP Header 20바이트 뒤에는 TCP Options 24바이트가 붙어 있습니다.
옵션 부분은 다음과 같습니다.
02 04 05 b4 01 03 03 06 01 01 08 0a 1e 63 6b ae 00 00 00 00 04 02 00 00
이 값을 옵션별로 나누면 다음과 같습니다.
02 04 05 b4
= MSS Option
01
= NOP
03 03 06
= Window Scale Option
01
= NOP
01
= NOP
08 0a 1e 63 6b ae 00 00 00 00
= Timestamp Option
04 02
= SACK Permitted
00
= End of Option List
00
= Padding 또는 End of Option List
먼저 02 04 05 b4는 MSS Option입니다.
02는 MSS 옵션 번호입니다.
04는 옵션 길이입니다.
05 b4는 MSS 값입니다.
16진수 0x05b4를 10진수로 바꾸면 1460입니다.
따라서 MSS 값은 1460 bytes입니다.
MSS는 Maximum Segment Size의 줄임말입니다.
TCP가 한 번에 실을 수 있는 데이터 크기를 의미합니다.
1460 bytes는 일반적인 Ethernet MTU 1500 환경에서 자주 볼 수 있는 값입니다.
IP Header 20 bytes와 TCP Header 20 bytes를 제외하면,
데이터로 실을 수 있는 크기가 1460 bytes가 되기 때문입니다.
다음 01은 NOP입니다.
NOP는 No Operation의 줄임말입니다.
실제 기능을 수행하는 옵션이라기보다,
TCP Options의 길이를 맞추기 위한 정렬용 값으로 사용됩니다.
03 03 06은 Window Scale Option입니다.
03은 Window Scale 옵션 번호입니다.
03은 옵션 길이입니다.
06은 shift count입니다.
shift count가 6이라는 것은 윈도우 크기를 계산할 때 2의 6제곱,
즉 64배 확장할 수 있다는 뜻입니다.
그 다음 01 01은 NOP 두 개입니다.
08 0a 1e 63 6b ae 00 00 00 00은 Timestamp Option입니다.
08은 Timestamp 옵션 번호입니다.
0a는 옵션 길이 10바이트를 의미합니다.
1e 63 6b ae는 TSval입니다.
16진수 0x1e636bae를 10진수로 바꾸면 509832110입니다.
00 00 00 00은 TSecr입니다.
값은 0입니다.
첫 SYN 패킷에서는 아직 상대방의 Timestamp를 받은 상태가 아니므로,
TSecr 값이 0으로 들어갈 수 있습니다.
04 02는 SACK Permitted입니다.
SACK은 Selective Acknowledgment의 줄임말입니다.
일부 데이터만 손실되었을 때,
받은 부분과 못 받은 부분을 더 정확하게 알려줄 수 있게 해주는 기능입니다.
SACK Permitted는 이 TCP 연결에서 선택적 ACK를 사용할 수 있다는 의미입니다.
마지막 00은 End of Option List입니다.
옵션 목록이 끝났다는 뜻입니다.
그 뒤의 00은 길이를 맞추기 위한 Padding으로 볼 수 있습니다.
Wireshark에서는 이 값도 End of Option List로 표시할 수 있습니다.
전체 길이 검산
이번 패킷의 길이를 다시 계산해보면 다음과 같습니다.
Ethernet Header: 14 bytes
IPv4 Header: 20 bytes
TCP Header: 44 bytes
Application Data: 0 bytes
전체 캡처 바이트는 다음과 같습니다.
14 + 20 + 44 = 78 bytes
IPv4 Total Length는 다음과 같습니다.
20 + 44 = 64 bytes
여기서 차이가 나는 이유는 IPv4 Total Length가 Ethernet Header를 포함하지 않기 때문입니다.
Wireshark 하단의 16진수 덤프는 Ethernet Header부터 보여주지만,
IPv4 Header 안의 Total Length 값은 IPv4 Header부터 계산합니다.
이 차이를 이해하면 Total Length가 왜 64인지 헷갈리지 않습니다.
이번 패킷의 최종 해석
이번 캡처에서 확인한 패킷은 다음과 같이 정리할 수 있습니다.
내 맥북은 172.30.1.5 주소를 사용하고 있습니다.
내 맥북은 임시 포트 64161번을 사용해 외부 서버 172.66.147.243의 443번 포트로 TCP 연결을 시작했습니다.
Destination Port가 443이므로 HTTPS 통신을 위한 연결이라고 볼 수 있습니다.
TCP Flags에 SYN이 있으므로 이 패킷은 TCP 3-way handshake의 첫 번째 패킷입니다.
TCP Segment Len이 0이므로 실제 데이터는 아직 없습니다.
하지만 SYN은 Sequence Number 하나를 소비하므로,
Wireshark에서는 다음 Sequence Number가 1로 표시될 수 있습니다.
Ethernet Header의 Destination MAC은 최종 서버의 MAC 주소가 아니라,
현재 네트워크 구간에서 다음으로 패킷을 받을 장비의 MAC 주소입니다.
EtherType 0x0800을 통해 Ethernet 뒤에 IPv4가 온다는 것을 알 수 있습니다.
IPv4 Header의 Protocol 0x06을 통해 IPv4 뒤에 TCP가 온다는 것을 알 수 있습니다.
TCP Header의 Data Offset 값을 통해 TCP Header가 44바이트이고,
그 안에 24바이트의 TCP Options가 포함되어 있다는 것을 알 수 있습니다.
마무리
이번 실습에서는 Wireshark GUI를 사용해 실제 TCP SYN 패킷을 확인했습니다.
단순히 패킷 목록만 본 것이 아니라,
Ethernet II, IPv4, TCP Header를 펼쳐서 실제 값을 확인했습니다.
그리고 Wireshark 하단의 16진수 덤프를 직접 나누어 보면서,
원본 바이트가 어떻게 Ethernet Header, IPv4 Header, TCP Header로 해석되는지도 확인했습니다.
이번 캡처에서 가장 중요한 흐름은 다음과 같습니다.
EtherType 0x0800
→ 다음은 IPv4
IPv4 Protocol 0x06
→ 다음은 TCP
TCP Flags SYN
→ TCP 연결 시작 패킷
TCP Header Length 44 bytes
→ TCP Options 포함
TCP Segment Len 0
→ 아직 실제 데이터 없음
책에서 봤던 패킷 구조는 단순한 그림이 아니라,
실제 내 맥북에서 발생한 패킷 안에도 그대로 존재하는 구조였습니다.
Wireshark는 이 구조를 사람이 보기 쉽게 펼쳐서 보여주는 도구이고,
16진수 덤프는 그 해석의 출발점이 되는 원본 데이터입니다.
'Network' 카테고리의 다른 글
| TCP 흐름제어 (0) | 2026.07.05 |
|---|---|
| 리눅스에서 MTU와 패킷 단편화 실험 (0) | 2026.07.05 |
| TCP 혼잡제어 (0) | 2026.06.25 |
| What is Socket with Vibe Coding (0) | 2026.06.19 |
| T-Pot을 안전하게 운영하기 위한 DMZ 네트워크 설계 (0) | 2026.06.18 |