TCP 3 way hand shake

Previous Next

TCP 3-way-hand-shake

목차

  1. TCP Header
  2. TCP 3-Way Handshake
  3. TCP 4-Way Handshake
  4. SYN Flooding 공격

TCP Header

header


TCP FLAG


SYN(Synchronize sequence number) - 연결요청 패킷


ACK(Acknowledgement) - 응답 패킷

연결을 성립하려면 서로 통신이 가능한지를 먼저 파악하기 위해 패킷을 먼저 주고 받습니다.
Hand-Shake 과정에서는 SYN와 ACK 두 종류의 패킷을 주고 받습니다.
그 이유는 요청응답에 대한 패킷을 주고 받아야 하기 때문에 두 종류입니다.


FIN(Finish) - 연결 종료 요청 패킷


RST(Reset) - 연결 재설정 플래그


PSH(Push) - 넣기 플래그


URG(Urgent) - 긴급 데이터 플래그



TCP 3-Way Handshake

스크린샷 2022-09-26 오후 10 18 03

  요청자     수신자  
Start State Action Move To State Start State Action Move To State
CLOSED 요청자는 수신자가 수동 OPEN을 수행하고 연결을 수락할 준비가 될 때까지 아무 것도 할 수 없습니다. (시도할 수 있지만 수신자가 준비될 때까지 아무 것도 수행되지 않습니다.) CLOSED 수신자는 수동 OPEN을 수행하여 연결을 위한 전송 제어 블록(TCB)을 만들고 요청자로부터 연결 요청(SYN)을 받을 준비를 합니다. LISTEN
CLOSED 1단계 전송: 요청자는 활성 OPEN을 수행하여 연결을 위한 전송 제어 블록(TCB)을 생성하고 수신자에 SYN 메시지를 보냅니다. SYN-SENT LISTEN 수신자는 요청자의 커넥션 요청을 기다립니다.
SYN-SENT 요청자는 자신이 보낸 SYN과 수신자의 SYN에 대한 ACK를 받기를 기다립니다. LISTEN 1단계 수신, 2단계 전송: 수신자가 요청자로부터 SYN을 수신합니다. 수신자가 보낼 SYN과 요청자의 SYN에 대한 ACK가 포함된 단일 SYN+ACK 메시지를 요청자에 다시 보냅니다. SYN-RECEIVED
SYN-SENT 2단계 수신, 3단계 전송: 요청자는 요청자의 SYN에 대한 ACK가 포함된 SYN+ACK를 수신자에서 수신하고 수신자로부터 SYN을 받습니다. 수신자의 SYN에 대한 ACK를 수신자에게 보냅니다. 요청자는 이제 연결 설정이 완료되었습니다. ESTABLISHED SYN-RECEIVED 수신자는 이전에 보낸 SYN에 대한 ACK를 기다립니다.
ESTABLISHED 요청자는 수신자가 정상적으로 작동할 수 있도록 연결 설정이 완료되기를 기다리고 있습니다.   SYN-RECEIVED 3단계 수신: 수신자는 SYN에 대한 ACK를 수신하고 이제 연결 설정이 완료됩니다. ESTABLISHED
ESTABLISHED 요청자는 정상적인 데이터 전송 작업을 수행할 준비가 되었습니다.   ESTABLISHED 수신자가 정상적인 데이터 전송 작업을 수행할 준비가 되었습니다.  

TCP-connection-1

Q. 왜 3-way ? 2-way로는 불가능?

TCP 커넥션은 양방향성(bidirectional) connection이기 때문이다.
요청자가 수신자에게 존재를 알리고 패킷을 보낼 수 있다는 것을 알리듯, 수신자도 요청자에게 존재를 알리고 패킷을 보낼 수 있다는 신호를 보내야 한다.

비유를 들자면 아래와 같은 과정이다.

  1. 요청자가 자신의 목소리가 들리는지 물어본다(SYN)
  2. 수신자는 요청자의 목소리가 들린다고 말한다.(SYN+1) 그리고 자신의 목소리가 들리는지 물어본다.(ACK)
  3. 요청자는 수신자의 목소리가 들린다고 말한다.(ACK+1)


full-duplex(전이중) 통신의 구성

이를 통해 full-duplex 통신이 구축됩니다.


1st. SYN

PORT 상태

Q. 왜 초기 Sequence Number(ISN)는 임의의 랜덤 숫자?

Connection을 맺을 때 사용하는 포트(Port)는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용된다.
따라서 두 통신 호스트가 과거에 사용된 포트 번호 쌍을 사용하는 가능성이 존재한다.
수신자 측에서는 패킷의 SYN을 보고 패킷을 구분하게 된다.
난수가 아닌 순차적인 Number가 전송된다면 이전의 Connection으로부터 오는 패킷으로 인식할 수 있다.
이런 문제가 발생할 가능성을 줄이기 위해서 난수로 ISN을 설정한다.


2nd. SYN + ACK

PORT 상태


3rd. ACK

PORT 상태



요청자 & 수신자 State

상태 설명
CLOSED 연결 수립을 시작하기 전의 기본 상태 (연결 없음)
LISTEN 포트가 열린 상태로 연결 요청 대기 중
SYN-SENT SYN 요청을 한 상태
SYN-RECEIVED SYN 요청을 받고 상대방의 응답을 기다리는 중
ESTABLISEHD 연결의 수립이 완료된 상태, 서로 데이터를 교환할 수 있다.



3-way handshake 이후 데이터 송수신 과정


Sequence Number(이하 SeqNumber)

32 bits


Acknowledgement Number(이하 AckNumber)

32 bits

images_pu1etproof_post_eb19f6d3-6e98-47b4-8cd4-ee1b2bb5d749_pasted image 0 (3)

초기 SeqNumber 3001과 AckNumber 4001은 연결을 수립하는 3-way handshaking 과정에서 결정된다.

  1. COM1은 COM2로 200 byte의 데이터를 전송한다.
  2. COM2은 데이터를 수신하고, 다음에 수신하고자 하는 데이터 번호 3201을 AckNumber에 넣는다.
  3. COM1은 COM2로부터 3201번부터 200byte의 데이터를 전송한다.
  4. COM2는 데이터를 수신하고, 다음에 수신하고자 하는 데이터 번호 3401을 AckNumber에 넣는다.
  5. 1~4 과정을 데이터 전송이 완료될 때까지 반복한다.

그러나 데이터가 항상 올바르게 전달되지는 않는다. -> 이 때, 일련번호와 확인응답번호를 사용해, 데이터가 손상되거나 유실된 경우 데이터를 재전송한다. (재전송 제어)



TCP 4-Way Handshake

요청자(Active Close)

수신자(Passive Close)

클라이언트와 서버, 둘 중에 어느 쪽이든 연결 종료 요청을 시작할 수 있기 때문에 이런 용어를 사용 먼저 연결 생성 요청을 했던 쪽이 먼저 연결 종료 요청을 보낼 수도 있고, 반대로 처음에는 연결 생성 요청을 당했던 쪽이 이번에는 먼저 연결 종료 요청을 보낼 수도 있다. 예: 서버가 먼저 종료하겠다고 FIN을 보낼 수 있고, 이런 경우 서버가 FIN_WAIT1 상태가 된다.

4-way

Q. TCP의 연결 설정 과정(3단계)과 연결 종료 과정(4단계)이 단계가 차이나는 이유?

요청자가 데이터 전송을 마쳤다고 하더라도 수신자는 아직 보낼 데이터가 남아있을 수 있기 때문에 일단 FIN에 대한 ACK만 보내고, 데이터를 모두 전송한 후에 자신도 FIN 메시지를 보내기 때문이다.


1st. FIN(요청자의 FIN)

스크린샷 2022-09-27 오후 4 15 28

Q. 왜 승인 번호를 함께 묶어서 FIN+ACK로 보내고 있는 것일까?

Half-Close 기법.

Half-Close 기법은 말 그대로 연결을 종료하려고 할 때 완전히 종료하는 것이 아니라 반만 종료하는 것이다.
Half-Close를 사용하면 요청자가 처음 보내는 FIN 패킷에 승인 번호를 함께 담아서 보내게 되는데,
이때 이 승인 번호의 의미는 “일단 연결은 종료할 건데 귀는 열어둔다. 이 승인 번호까지 처리했으니까 마저 보낼 거 있으면 보내”라는 의미가 된다.
즉, 반만 닫겠다는 말의 의미는 연결을 종료할 때 전송 스트림과 수신 스트림 중 하나만 우선 닫겠다는 것을 의미하는 것이다.
이후 수신자는 미처 못 보낸 데이터가 있다면 열심히 보낼 것이고, 이에 요청자는 아직 살아있는 수신 스트림을 사용하여 데이터를 처리한 후 ACK 패킷을 응답으로 보낼 수 있다.
이후 수신자가 모든 데이터를 처리하고나면 다시 요청자에게 FIN 패킷을 보냄으로써 모든 데이터가 처리되었다는 신호를 보내준다.
그럼 요청자는 그때 나머지 반을 닫으면서 조금 더 안전하게 연결을 종료할 수 있는 것이다.

PORT 상태


2nd. ACK(수신자의 ACK)

스크린샷 2022-09-27 오후 4 13 27

PORT 상태

FIN_WAIT_2

요청자는 수신자로부터 승인 번호를 받고 자신이 보냈던 시퀀스 번호와 승인 번호의 차가 1이 맞는지 확인한다. 하지만 아직 수신자의 데이터 전송이 전부 끝나지 않았을 수도 있기에 FIN_WAIT2 상태로 들어가서 수신자가 연결 종료를 허락하는 FIN 패킷을 보내줄 때까지 기다린다.

방금 CLOSE_WAIT 섹션에서 설명했듯이 여기서부터는 수신자가 다시 FIN 패킷을 보내줄 때까지 요청자는 계속 대기하는 시간이다. 하지만 CLOSE_WAIT와 다르게 무한정 대기만 하는 것은 아니고 커널 파라미터로 타임아웃이 정해져있는 경우, 일정 시간이 경과하면 자동으로 다음 단계로 넘어갈 수 있다.


3rd. FIN(수신자의 FIN)

스크린샷 2022-09-27 오후 4 12 42

PORT 상태


4th. ACK(요청자의 ACK)

스크린샷 2022-09-27 오후 4 11 18

이때, TIME_WAIT의 역할은 의도하지 않은 에러로 인해 연결이 데드락에 빠지는 것을 방지한다. TIME_WAIT에서 대기하는 시간은 2 MSL(Maximum Segement Lifetime)으로 정의되어 있으며, 정확한 MSL의 시간 값은 커널 파라미터로 정의되어있다.

chanyoung@MacBook-Pro-2 ~ % sysctl net.inet.tcp | grep msl
net.inet.tcp.msl: 15000

15초로 설정되어있다. 즉, TIMEWAIT 상태에서 30초 정도 대기한다는 것이다. 참고로 이 값은 변경할 수 없기 때문에 TIMEWAIT에서 소비되는 시간은 변경할 수 없다. 하지만 CLOSE_WAIT와 마찬가지로 여기서도 데드락이 발생할 수 있다.

PORT 상태



요청자(Active Close) & 수신자(Passive Close) State

상태 설명
CLOSED 연결 수립을 시작하기 전의 기본 상태 (연결 없음)
ESTABLISEHD 연결의 수립이 완료된 상태, 서로 데이터를 교환할 수 있다.
CLOSE-WAIT 상대방의 FIN(종료 요청)을 받은 상태. 상대방 FIN에 대한 ACK를 보내고 애플리케이션에 종료를 알린다.
LAST-ACK CLOSE-WAIT 상태를 처리 후 자신의 FIN 요청을 보낸 후 FIN에 대한 ACK를 기다리는 상태.
FIN-WAIT-1 자신이 보낸 FIN에 대한 ACK를 기다리거나 상대방의 FIN을 기다린다.
FIN-WAIT-2 자신이 보낸 FIN에 대한 ACK를 받았고 상대방의 FIN을 기다린다. 수신자가 다시 FIN 패킷을 보내줄 때까지 요청자는 계속 대기하는 시간.
CLOSING 상대방의 FIN에 ACK를 보냈지만 자신의 FIN에 대한 ACK를 못받은 상태
TIME-WAIT 모든 FIN에 대한 ACK를 받고 연결 종료가 완료된 상태. 새 연결과 겹치지 않도록 일정 시간 동안 기다린 후 CLOSED로 전이한다.


CLOSE_WAIT

No, there is no timeout for CLOSE_WAIT. 저마다 강조하는 바를 살펴봐도 CLOSE_WAIT는 커널 옵션이나 설정으로 타임아웃을 줄 수 없으며 로컬 어플리케이션의 문제이기 때문에 정상적인 문제 해결이 필요하다는 지적

CLOSE_WAIT 원인

예시

  1. 파일서버가 필요해 별도 웹 서버를 구성하지 않고 로컬 톰캣의 웹 서버를 사용
  2. Static HTML 파일을 올려두고 톰캣에서 구동중인 웹앱의 HttpClient에서 로컬 자기 자신(동일한 톰캣)을 호출해 HTML을 받아가도록 구성
  3. 그러나, 부하를 높이니 점점 느려지다 HTML 조차 내려주지 못하는 행업 상태 발생
  4. 모든 소켓이 CLOSE_WAIT 상태에 빠짐

대부분의 쓰레드가 검색 결과를 받아오지 못하고 대기중(WAITING)인 상태
이 검색 결과는 로컬에서 받아오는 것입니다. 즉, 로컬은 행업 상태여서 검색 결과를 보내주지 못하는 상황이고, 쓰레드는 검색 결과를 받기 위해 대기하는 상황입니다.
원래 일정 시간이 경과하면 타임아웃으로 끊어야 하는데, 행업 상태에 빠지다보니 이 조차도 처리되지 않고 서로가 서로를 기다리는 상황. 즉, 보낼 수도 없고 받을 수도 없는 일종의 교착 상태(deadlock)가 원인.


TIME_WAIT

TIME_WAIT는 왜 필요할까?

스크린샷 2022-09-27 오후 5 30 12

스크린샷 2022-09-27 오후 5 31 42


TCP TIMESTAMP

wrapped sequence number 문제를 해결하기 위해, RFC 1323에서는 PAWS(Protection against Wrapped Sequence Numbers)라는 방법을 제안

$ sysctl -w ipv4.tcp_timestamps="1"
$ sysctl -w net.ipv4.tcp_tw_reuse="1"

처음에 TIME_WAIT이 짧을때 두 가지 문제가 발생할 수 있다고 언급했는데 이 부분에 대해서는 다음과 같이 해결 가능

연결 종료의 4-way handshake 과정 요약

FIN+ACK, seq = K, ack = L
ACK, seq = L, ack = K + 1
FIN+ACK, seq = L, ack = K + 1
ACK, seq = K, ack = L + 1



SYN Flooding 공격

SYN Flooding 공격이란?

synflood



SYN Flooding 공격 방지

스크린샷 2022-10-10 오후 3 15 42


정상적인 세션 연결과정

SYN Cookie를 사용했을 때 올바른 요청이라면 아래와 같은 순서로 정상적인 세션 연결과정을 거칩니다.

  1. Client의 SYN 패킷 수신
  2. L4(방화벽)은 응답으로 SYN/ACK 패킷에 추가로 Cookie 값을 넣어 Client에 송신
  3. Client는 SYN/ACK에 대한 응답으로 ACK Number 필드에 Cookie+1한 값을 L4에 송신
  4. L4는 수신한 ACK 패킷의 ACK Number - 1한 값이 Cookie 값과 일치하면 리소스 서버와 TCP Connection을 설정시켜줌
    • L4는 정상적인 Client로부터 timestamp 내에 응답이 오면 해당 Client의 원래 Cookie 값을 알아낼 수 있어 값 비교가 가능

이처럼 정상적인 연결의 경우 SYN Cookie 값에 대한 유효성이 확인되었기에 L4는 클라이언트가 리소스 서버와 세션을 맺도록 중간다리 역할을 해줌

스크린샷 2022-10-10 오후 3 22 08


스크린샷 2022-10-10 오후 3 31 18