Without a Break

TCP Connection Establishment and Termination 본문

Network/네트워크보안과프로그래밍

TCP Connection Establishment and Termination

와븨 2022. 10. 7. 20:53

개요

  • TCP는 연결형 프로토콜: 종단이 서로 데이터를 송신하기 전에 이들 사이에 연결을 확립
플래그 3문자 약어 설명
S SYN 순서번호의 동기화
F FIN 송신자는 데이터 송신을 종료
R RST 연결의 재설정 (강제 종료)
P PSH 수신 프로세스가 가능한 빨리 데이터를 보낸다
.   위의 4개의 플래그가 설정된 것이 없다

 

 

연결 확립과 종료

연결 확립 프로토콜

  1. [SYN] 요구 측의 종단은 접속하고자 하는 서버의 포트번호와 클라이언트의 초기순서번호(ISN)를 지정한 SYN 세그먼트를 보낸다.
  2. [SYN+ACK] 서버는 서버의 초기순서번호(ISN)를 포함한 자신의 SYN 세그먼트로 응답한다.
  3. [ACK] 클라이언트는 서버로부터 보내 온 SYN에 대하여 서버의 ISN+1 ACK로 확인응답을 보내야 한다.

=> 이와 같이 3개의 세그먼트에 의해 연결이 확립되어 이 연결 확립 과정은 three-way handshake라 부름

 

일반적인 연결 종료 프로토콜

  1. 능동 폐쇄(active close) 클라이언트가 close를 호출해 해당 연결로 더 이상 보낼 데이터가 없다고 선언하면, TCP는 close 호출 전에 클라이언트에게 처리 요청 받을 보낼 데이터를 모두 보낸 뒤 FIN 송신
  2. 수동 폐쇄(passive close) 서버 TCP는 앞의 데이터를 모두 받고 FIN을 수신하면 응용에 EOF를 전달하여 연결이 닫힘을 알리고, 클라이언트 TCP에 FIN의 수신을 알림 (FIN을 담은 세그먼트의 순서 번호+1에 대한 ACK)
  3. (active close) 서버는 read 함수에서 EOF가 리턴 된 걸 확인하면, 보통 해당 연결에 대한 close를 호출하도록 프로그램 되어 있다. 이 경우 FIN을 송신함
  4. (passive close) 클라이언트는 FIN을 수신하면, FIN을 담은 세그먼트의 순서번호에 1을 더한 ACK를 보낸다.

=> 위 종료 프로토콜에서 클라이언트와 서버가 바뀌어도 아무 문제가 없음 (다만, 요청-응답 응용에서 클라이언트가 먼저 닫는 경우가 많다)

 

 

연결 확립의 타임아웃

연결을 확립할 수 없는 예 : 서버 호스트의 다운

  • [tos 0x10] : IP 데이터그램의 서비스 유형 필드. telnet, rlogin에서 대화용 로그인이익 때문에 클라이언트의 지연을 최소화하기 위함
  • 클라이언트의 TCP가 연결을 설정하기 위해 SYN을 보냄 (첫번째 세그먼트 보낸 후 2번째 연결을 위한 시도 5.8초 후, 두번째 세그먼트를 보낸 후 3번째 연결을 위한 시도는 24초 후에 보냄)

 

 

최대 세그먼트 크기

  • Maximum Segment Size(MSS): TCP가 상대편에 한번에 보낼 수 있는 데이터의 최대 크기
  • 연결이 확립될 때 각 종단은 MSS를 통지 (TCP 옵션)
  • MSS = MTU - IP헤더 - TCP헤더 ex) 이더넷 : 1460바이트
  • Default MSS 설정 : 각 종단은 받기를 원하는 MSS를 알리는 옵션을 갖는다. => 시스템 별 default MSS가 다를 수 있음

 

 

절반 폐쇄

: TCP 연결의 한 쪽 종단이 다른 쪽 종단으로부터 데이터를 전송 받고 있는 상태에서도 데이터의 출력을 종료할 수 있는 기능

 

BSD Sockets API는 응용이 close를 대신 shutdown을 호출하여 절반 폐쇄함

  • BSD Sockets API에서 close() 함수를 호출하는 것은 절반 폐쇄가 아님
  • 절반 폐쇄가 있음에도 많은 응용은 연결 종료 시 close를 이용하여 양방향 폐쇄를 수행

서버가 EOF를 받았음에도 보낼 데이터가 남아있었고, 응용이 shutdown으로 절반 폐쇄 했기 때문에 계속 데이터를 수신하는 것이 가능함

  • 만약 클라이언트가 close했는데 서버가 write하면 데이터 전달 실패됨

 

 

TCP 상태 천이도

TIME_WAIT (2MSL Wait) State (대기상태)

MSS : 세그먼트가 네트워크 상에 존재할 최대 시간

  • RFC 793에서는 2분으로 명시했지만, 구현은 다른 값을 사용하기도 함
  • IP 데이터그램이 TTL로 패킷의 수명을 제약하지만, 실제 시간이 아니라 hop 수 임에 주의

TCP가 능동적 폐쇄를 한 뒤 마지막 ACK를 보냈다면, 해당 연결은 2MSL동안 TIME_WAIT 상태임

  • 이는 다시 말해 해당 연결을 2MSL동안 재사용할 수 없음을 의미
  • 이유 : 마지막 ACK가 만야 ㄱ손시로디면, 재전송을 해야 하기 때문
  • 다른 효과 : 해당 연결에 대응하는 소켓 페어의 재사용을 막기 위함 (네트워크에 남아있는 패킷이 이상행동을 일으킬 수 있으므로. 그런 패킷 도착 시 discard)
  • 표준과 달리 BSD 및 BSD를 따라한 구현들을 연결뿐만 아니라 로컬 포트번호의 재사용을 막음 (TCP 표준은 같은 연결을 다시 못 맺을 뿐이지만, 구현들을 해당 포트 자체를 못 쓰게 함)
  • SO_REUSEADDR 소켓 옵션을 가진 API에서는 해당 포트의 재사용을 허용할 수 있지만, 연결의 재사용은 원래 TCP 표준에서는 허용하지 않았음
  • 서버의 경우 이 상태가 문제를 일으킴. 서버를 갑자기 종료시킨 뒤 재시작하면, 해당 포트를 최대 4분 동안 못 쓰는 상황이 발생

 

FIN_WAIT_2 상태

  • FIN_WAIT_2 상태에서 서버가 FIN을 보내주지 않으면, 연결이 계속 같은 상태에 빠짐
  • BSD에서 유래된 구현들은 응용 close 함수를 호출하여 능동적 폐쇄한 경우, 타이머를 설정해 타임아웃동안 연결이 휴지상태이면, 해당 연결을 CLOSED로 처리해버림

 

 

재설정(reset) 세그먼트

  • 참조 연결에 대해서 바르지 않은 세그먼트가 도착할 때 발생 (*참조 연결 : 4-tuple이 명시된 연결)

연결 중단

  • 정규 해제 : 상대편에 FIN 신호를 보내서 연결을 종료한 상황. FIN은 큐에 대기한 데이터를 모두 전송한 후에야 전송되므로, 데이터에 대한 손실이 없음
  • 중단해제 : FIN 대신에 재설정을 전송하여 연결을 중단한 상황

연결 중단을 할 경우에 응용이 얻는 장점

  • 대기 중인 데이터를 바로 버리고 즉시 재설정 신호(RST)를 전송해 연결을 재설정 가능
  • RST의 수신측 TCP는 응용에 'RST 송신측이 연결을 중단했음'을 알릴 수 있음
  • 따라서, API는 응용이 연결 중단을 할 수 있는 방법을 제공해야 함
  • BSD는 SO_LINGER 옵션이 대표적인데, 여기서 linger는 중단 전에 기다릴 시간을 의미

 

절반 개방 연결

  • 절반 개방 : 호스트 A가 호스트 B에게 세그먼트를 따로 보내지 않고 연결을 종료 또는 중단
  • 절반만 개방된 상태이더라도, B가 데이터 전송을 시도하지 않으면 B는 고장을 알 수 없음 => 절반 개방된 연결로 B가 세그먼트를 보내는 경우, A의 TCP는 RST로 응답해야 함

 

TIME_WAIT Assassination (TWA)

  • 아래와 같이 Client가 TIME_WAIT 상태에 있는데, Server가 오래전에 보낸 패킷이 늦게 도착하고 이를 응답하는 바람에 Server가 RST를 보내서 Client의 TIME_WAIT를 의도치 않게 꺼버리는 문제
  • 대부분의 구현은 TIME_WAIT 상태 동안 도착한 RST 세그먼트를 무시함

 

 

동시 개방

  • TCP의 상태 천이 다이어그램을 보면, 호스트 A와 호스트 B가 서로 간에 각각 SYN을 보내서 연결을 만들려고 할 수 있음
  • 이 때 TCP표준은 두 개의 연결을 만드는 게 아니라 하나의 연결만이 이루어지도록 설계됨
  • 보통 동시 개방은 이론상의 시나리오였으나, 각각 NAT를 거쳐야 글로벌 인터넷을 사용가능한 두 호스트가 상호 같에 outbound TCP 연결 (즉, peer-to-peer 연결)을 만들 필요가 있을 때 사용되며, 이를 TCP Hole Punching 이라고 부름

 

 

동시 폐쇄

  • 양쪽 종단으로부터 능동적 폐쇄를 수행할 수 있음
  • 동시 폐쇄는 일반적인 폐쇄와 같은 수의 세그먼트 교환

 

 

TCP

TCP 옵션

  • TCP 헤더에 옵션을 추가
  • RFC 793,1323은 추가적인 TCP 옵션을 정의
  • 옵션의 유형은 kind의 값으로 구분
  • NOP : 송신측이 필드를 4바이트의 배수가 되도록 채우기 위함

 

TCP 서버 설계

1. 병행성을 갖도록 설계

  • 서버는 새로운 연결 요청이 도착하면 그 연결을 받아들이고 새로운 클라이언트를 처리하기 위해 새로운 프로세스 또는 스레드를 가동(folk()로 복제)

2. TCP 서버 포트 번호

netstat 옵션 동작
-a 네트워크상의 모든 종단점을 표시
-n DNS 서버를 사용하여 IP 주소를 dotted decimal로 출력하고 서비스 이름을 숫자로 포트번호를 출력
-f inet TCP와 UDP 종단점만 표시

3. 외부 IP 주소의 제한

  • TCP 서버가 자신에 대해 확립할 수 있는 제한 음식
  • Iport는 서버의 알려진 포트, localIP는 로컬 인터페이스의 IP 주소
로컬 주소 외부 주소 설명
localIP.lport foreignIP.fport 하나의 클라이언트에 제한
localIP.lport *.* 하나의 로컬 인터페이스에 도착하는 연결에 제한
*.lport *.* lprot에 보네는 모든 연결을 수신

4. 수신 연결 큐

  • 병행 서버는 각 클라이언트를 다루기 위해 새 프로세스를 만들 수 있지만, listen을 위한 서버는 accept 함수를 사용해 한 개의 연결 요청만을 처리할 수 있음
  • 이러한 연결들은 (1)SYN은 받았지만 아직 연결 설립이 되지 않은 연결, 또는 (2) 핸드셰이킹이 끝났지만 listen을 위한 서버가 아직 accept하지 못한 연결 중 하나
  • BSD Sockets API에서 응용이 연결 도착을 알 게 되었을 때에는 이미 TCP의 three-way 핸드 셰이킹이 끝나있는 상태임에 주의할 것