TCP 플래그는 어떻게 읽어야 할까요?¶
Flags [S.]같은 짧은 표시는 작아 보이죠? 근데 연결의 분위기는 그 몇 비트 안에 거의 다 들어 있어요.
TCP 3-way handshake에서는 SYN, SYN-ACK, ACK 가 연결을 여는 신호라는 걸 먼저 봤고, TCP 헤더는 왜 이렇게 칸이 많을까요?에서는 그 신호들이 TCP 헤더의 Flags 칸 안에 1비트씩 들어간다는 것도 펼쳐봤어요.
근데 막상 캡처 화면을 보면 또 이런 생각이 들어요.
"좋아요,
SYN이니ACK니 하는 말은 알겠어요. 근데Flags [S],Flags [S.],Flags [F.],Flags [R]는 그때그때 어떤 분위기로 읽어야 하죠?"
근데 이 글이 필요한 이유는 플래그 이름 자체보다 캡처 위 분위기 판단 쪽에 있어요.
Flags [S]면 지금 연결 시작 장면인가?Flags [R]면 이건 거절인지, 이미 끝난 연결에 대한 응답인지?Flags [F.]가 보이면 지금은 정상 종료 쪽으로 읽어야 하나?
즉 플래그는 작은 비트인데, 연결의 분위기를 제일 빠르게 드러내는 표식이에요. 오늘은 TCP 플래그를 헤더의 8비트 깃발 칸으로 다시 보고, tcpdump나 Wireshark에서 자주 만나는 조합을 한 줄씩 해석하는 치트시트처럼 정리해볼게요. 기본 의미는 RFC 9293 3.1절 을 뼈대로 보고, ECE / CWR 같은 ECN 관련 비트는 RFC 3168 쪽 감각만 가볍게 덧붙일게요.
이 글의 범위
여기서는 TCP 플래그를 읽는 감각에 집중해요. sequence 번호와 ACK 번호가 헤더의 어느 줄에 들어가는지, window나 옵션이 전체 헤더에서 어떻게 보이는지는 TCP 헤더는 왜 이렇게 칸이 많을까요?에서 이미 펼쳐놨어요. 오늘은 그중에서도 Flags 칸만 확대해서, 캡처에서 어떻게 읽을지를 선명하게 만드는 편이라고 생각하면 돼요.
그래서 TCP 플래그는 한마디로 뭐예요?¶
TCP 플래그는 지금 이 세그먼트가 연결에서 어떤 역할을 맡는지 짧게 찍어두는 상태 비트예요.
이게 중요한 이유는, 긴 숫자와 옵션을 다 읽기 전에 플래그만 봐도 어느 정도 분위기가 먼저 잡히기 때문이에요.
- 지금 연결을 여는 중인지
- 이미 열린 연결에서 확인만 주고받는 중인지
- 정상 종료인지
- 아니면 즉시 중단 / 거절인지
를 제일 먼저 말해주는 칸이 바로 Flags예요.
| 기본편에서 잡은 감각 | 비유에서는 | 실제로는 |
|---|---|---|
| 연결 시작 | 문을 열기 전에 거는 시작 표식 | SYN |
| 받았다는 확인 | 방금 본 번호를 확인하는 표시 | ACK |
| 연결 종료 | 더 보낼 게 없다는 마감 표시 | FIN |
| 비정상 중단 | 지금 대화를 즉시 접는 표시 | RST |
| 바로 넘겨달라는 힌트 | 이 메모는 버퍼에 오래 묵히지 말아달라는 표시 | PSH |
플래그 칸 전체 그림¶
TCP 헤더의 Flags 는 8비트예요. 길이는 짧지만, 캡처를 읽을 때는 엄청 자주 등장해요.
여기서 먼저 잡아야 할 감각은 세 가지예요.
- 각 플래그는 1비트짜리 켜짐/꺼짐 표시라는 점
- 캡처 화면의
Flags [S.]같은 표기는 어떤 비트가 같이 켜졌는지를 보기 좋게 풀어쓴 표현이라는 점 - 실전에서는
SYN,ACK,FIN,RST,PSH정도를 가장 자주 읽는다는 점
자주 보는 플래그는 각각 무슨 말일까요?¶
| 플래그 | 축약 표기 | 의미 | 언제 자주 보나 |
|---|---|---|---|
SYN |
S |
연결 시작, 초기 sequence 번호 제안 | 3-way handshake 첫 단계 |
ACK |
. |
상대가 보낸 흐름을 확인하고 다음 번호를 알림 | 연결이 열린 뒤 거의 항상 |
FIN |
F |
더 보낼 데이터가 없음 | 정상 종료 |
RST |
R |
연결을 즉시 리셋 / 거절 | 포트 닫힘, 비정상 중단 |
PSH |
P |
데이터를 너무 오래 묵히지 말고 위로 넘겨달라는 힌트 | 대화형 트래픽, 응답 전송 |
URG |
U |
Urgent Pointer가 유효함 | 요즘 웹 트래픽에선 드묾 |
ECE |
E |
ECN 혼잡 신호 반사 | ECN 환경에서 가끔 |
CWR |
W |
혼잡 윈도우를 줄였다는 응답 | ECN 환경에서 가끔 |
SYN — 연결을 열 때 보는 시작 신호¶
SYN 은 "우리 연결 시작해볼까요?" 에 가까운 비트예요. TCP 3-way handshake에서 봤던 첫 번째 패킷이 바로 이 친구죠.
RFC 9293 3.4절 기준으로 SYN 은 단순 표식이 아니라 sequence 공간을 1칸 차지하는 제어 비트예요. 그래서 SYN seq=1000 다음에 상대가 ack=1001 로 답하는 거예요.
ACK — 연결이 열린 뒤엔 거의 기본값처럼 붙어요¶
ACK 는 단순히 "받았어요" 가 아니라 "나는 다음에 이 번호부터 기대해요" 라는 뜻이죠. 연결이 성립된 뒤에는 대부분의 세그먼트에 ACK 가 붙어요.
그래서 캡처에서 Flags [.] 하나만 보여도, 그건 "평범한 확인/데이터 흐름 안쪽 세그먼트일 가능성" 을 먼저 떠올리면 돼요.
FIN — 정리하고 나간다는 정상 마감 표시¶
FIN 은 "이쪽에서 더 보낼 데이터는 없어요" 라는 종료 표시예요. 이것도 SYN 처럼 sequence 공간을 1칸 써요. 그래서 데이터가 없어 보이는데도 ACK 숫자가 1 늘어나는 장면이 생길 수 있어요.
RST — 예의 바른 종료가 아니라 즉시 중단이에요¶
RST 는 FIN 처럼 차분하게 닫는 표식이 아니에요. 지금 이 연결은 인정하지 않겠어요 또는 바로 접을게요 쪽에 더 가까워요.
포트가 닫혀 있거나, 이미 없어진 연결로 패킷이 들어왔거나, 중간 장비가 세션을 끊을 때 자주 보여요.
PSH — "지금 이 데이터는 좀 바로 넘겨줘" 정도의 힌트예요¶
PSH 는 초심자가 가장 많이 오해하는 플래그예요. "긴급하다" 는 뜻도 아니고, "즉시 ACK 해라" 는 명령도 아니에요. RFC 9293 3.9.1절 쪽 감각으로 보면, 받는 쪽이 이 데이터를 버퍼에 오래 묵히지 말고 애플리케이션 쪽으로 빨리 밀어 올려달라는 힌트에 더 가까워요.
그러니까 PSH 를 봤다고 "엄청 특수한 패킷이네" 라고까지 읽을 필요는 없어요. 응답 본문이나 대화형 트래픽에서 생각보다 자연스럽게 붙을 수 있어요. 다만 언제 PSH 를 붙이는지는 구현마다 조금씩 다를 수 있다는 점도 같이 기억해두면 좋아요.
URG, ECE, CWR — 보이면 읽되, 기본 캡처 해석의 주인공은 아니에요¶
URG는 Urgent Pointer를 같이 봐야 의미가 있어요.ECE,CWR는 ECN 흐름을 읽을 때 중요해요.
여기서는 범위를 한 번만 조심해서 볼게요. ECE 와 CWR 는 이미 혼잡이 났다는 뜻으로만 읽으면 안 돼요. 특히 SYN / SYN-ACK 구간에서는 ECN을 쓸 수 있는지 협상하는 신호로도 보일 수 있어요.
다만 일반적인 웹 트래픽 입문 글에서는, 보이더라도 먼저 SYN / ACK / FIN / RST / PSH 부터 읽는 습관을 들이면 충분해요.
캡처에서는 이런 조합으로 자주 보여요¶
실전에서는 플래그를 하나씩 따로 보기보다, 같이 켜진 조합으로 읽는 일이 더 많아요.
| 캡처 표기 | 어떻게 읽으면 되나 | 자주 보는 장면 |
|---|---|---|
Flags [S] |
새 연결 시작 요청 | 클라이언트가 먼저 두드림 |
Flags [S.] |
SYN + ACK, 시작 번호 확인 + 자기 번호 제안 |
서버가 handshake 2번째 답장 |
Flags [.] |
ACK 만 켜진 기본 확인 상태 |
연결 성립 후 평범한 흐름 |
Flags [P.] |
PSH + ACK, 데이터는 있는데 확인도 같이 함 |
요청/응답 본문 전송 |
Flags [F.] |
FIN + ACK, 보낼 건 끝났고 지금까지 흐름도 확인 |
정상 종료 |
Flags [R] 또는 Flags [R.] |
리셋 / 거절 / 즉시 중단 | 포트 닫힘, 세션 불일치 |
sequenceDiagram
participant 클라이언트 as 💻 클라이언트
participant 서버 as 🌍 서버
클라이언트->>서버: Flags [S]
서버-->>클라이언트: Flags [S.]
클라이언트->>서버: Flags [.]
클라이언트->>서버: Flags [P.]
서버-->>클라이언트: Flags [.]
클라이언트->>서버: Flags [F.]
서버-->>클라이언트: Flags [F.]
클라이언트->>서버: Flags [.]
핸드셰이크, 데이터, 종료까지 한 컷으로 줄이면 이런 느낌이에요. 물론 실제 캡처에서는 여기에 sequence 번호, ACK 번호, window, payload 길이까지 같이 보이지만, 분위기를 제일 먼저 알려주는 건 플래그 조합이에요.
tcpdump 한 줄은 이렇게 읽어요¶
예를 들어 tcpdump 류 출력에서 이런 줄을 본다고 해볼게요.
IP 192.168.0.10.51515 > 93.184.216.34.443: Flags [S], seq 1000, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0
IP 93.184.216.34.443 > 192.168.0.10.51515: Flags [S.], seq 5000, ack 1001, win 65535, options [mss 1460,sackOK,TS val 10 ecr 1,nop,wscale 7], length 0
IP 192.168.0.10.51515 > 93.184.216.34.443: Flags [P.], seq 1001:1081, ack 5001, win 501, length 80
IP 93.184.216.34.443 > 192.168.0.10.51515: Flags [F.], seq 5001, ack 1081, win 1024, length 0
이 한 줄씩에서 먼저 읽으면 좋은 건 이거예요.
Flags [S]— 연결 시작Flags [S.]— 상대도 시작 번호를 내밀며 답장Flags [P.]— 데이터가 실린 ACK 세그먼트Flags [F.]— 정상 종료 쪽으로 넘어가는 신호
여기서 포인트는, 플래그를 길이(length), seq/ack 숫자, 옵션과 같이 본다는 거예요. Flags [P.] 만 보고 "무조건 특수한 패킷이네" 라고 읽지 말고, 실제로 데이터가 실렸는지, 어느 흐름의 몇 번째 자리인지까지 같이 봐야 해요.
근데 왜 굳이 플래그를 이렇게 잘 읽어야 할까요?¶
1. 어디서 막혔는지 훨씬 빨리 좁혀져요¶
SYN만 가고SYN-ACK가 안 오면 연결 시작 단계부터 의심하고,RST가 오면 거절 또는 비정상 중단을 먼저 떠올리고,F.흐름이 오가면 정상 종료 쪽으로 읽을 수 있어요.
즉, 플래그만 잘 읽어도 "지금 연결을 열고 있나, 데이터 주고받는 중인가, 정리하고 끝내는 중인가, 아니면 중간에 튕겼나" 가 금방 보여요.
2. 같은 ACK 라도 장면이 달라져요¶
ACK 는 워낙 흔해서 별 의미 없어 보일 수 있어요. 근데요, S. 안의 ACK, P. 안의 ACK, F. 안의 ACK 는 전부 장면이 달라요. ACK는 배경음처럼 자주 나오지만, 누구와 같이 붙어 있느냐가 해석을 바꿔요.
3. FIN 과 RST 는 분위기부터 달라요¶
둘 다 연결이 끝난다는 점만 보면 비슷해 보일 수 있죠. 근데 FIN 은 마감, RST 는 급정지예요. 이 차이를 읽으면 장애 원인을 훨씬 빨리 좁힐 수 있어요.
잘못 읽기 쉬운 함정 여섯 가지¶
하나, ACK 를 보면 "이제 연결 끝났다"고 읽기.
아니에요. ACK 는 연결이 열린 뒤엔 거의 기본처럼 계속 붙어요.
둘, PSH 를 보면 "긴급 패킷"이라고 읽기.
PSH 는 우선순위 경보라기보다, 버퍼에 오래 묵히지 말아달라는 힌트에 가까워요.
셋, RST 와 FIN 을 비슷한 종료라고 읽기.
FIN 은 차분한 종료고, RST 는 즉시 중단이에요. 분위기가 완전히 달라요.
넷, SYN 은 그냥 표식이고 숫자엔 영향 없다고 생각하기.
SYN 은 sequence 공간을 1칸 써요. FIN 도 마찬가지예요.
다섯, Flags [.] 는 데이터가 없는 빈 패킷이라고 단정하기.
ACK 만 켜진 상태일 수는 있지만, 실제로 데이터 유무는 length나 seq 범위를 같이 봐야 해요.
여섯, ECE / CWR 를 보면 무조건 이상하다고 생각하기.
ECN이 켜진 환경에서는 자연스러울 수 있어요. 다만 입문 단계에서는 먼저 핵심 5~6개 플래그를 읽는 쪽이 훨씬 중요해요.
자, 정리해볼까요?¶
오늘 우리가 본 것
- TCP 플래그는 연결의 현재 역할을 알려주는 1비트짜리 표식들이에요.
- 실전에서는
SYN,ACK,FIN,RST,PSH를 가장 자주 읽어요. - 캡처의
Flags [S],Flags [S.],Flags [.],Flags [F.],Flags [R]는 어떤 비트가 같이 켜졌는지를 줄여 쓴 표현이에요. SYN과FIN은 sequence 공간을 1칸 쓰고,RST는 정상 종료가 아니라 즉시 중단 쪽에 가까워요.- 플래그는 혼자 보지 말고, seq/ack 숫자, 길이, 옵션과 같이 봐야 제대로 읽혀요.
결국 TCP 플래그 읽기는 "알파벳 외우기" 보다, 지금 이 연결 장면이 어디쯤 왔는지 읽는 감각에 더 가까워요.
이어서 보면 좋은 글¶
- 플래그가 TCP 헤더의 정확히 어느 칸에 들어가는지 다시 보고 싶다면 — TCP 헤더는 왜 이렇게 칸이 많을까요?
SYN,SYN-ACK,ACK흐름 자체를 다시 큰 그림으로 보고 싶다면 — TCP 3-way handshake는 왜 세 번이나 주고받을까요?FIN이후 왜 TIME-WAIT가 남는지까지 이어서 보고 싶다면 — TCP Teardown과 TIME-WAIT - 연결은 왜 바로 안 사라질까요?- 재전송 장면에서
ACK가 왜 그렇게 중요해지는지 다시 보고 싶다면 — TCP 재전송과 신뢰성 ECE,CWR가 길 붐빔 신호와 어떤 관계가 있는지 더 보고 싶다면 — TCP 혼잡 제어는 왜 흐름 제어와 따로 봐야 할까요?- 이런 플래그가 실제 캡처 줄에서 어떤 식으로 보이는지 바로 이어서 보고 싶다면 — tcpdump 한 줄은 어떻게 읽어야 할까요?
댓글