total_activ
네트워크보안 v.04 _ TCP/IP Networks 공부 (TCP 연결 수립&종료) 본문
1. 개요 / 2. 연결 확립과 종료
TCP는 연결형 프로토콜 : 종단이 서로 데이터를 송신하기 전에 이들 사이에 연결을 확립 (연결조건: 3handshacke / 종료조건: 4handshacke)
이 장은 연결의 확립 (establishment) 및 종료 (termination)의 절차를 다룸
svr4 % telnet bsdi discard //srv4: client, telnet: 원격접속, bsdi: server, discard: 패킷도착시 버림
Trying 192.82.148.3
Connect to bsdi. //접속
Escape character is ‘^]’ //^]: 종료
^]
telnet >quit
Connection closed.
// Discard service
// 서버는 클라이언트가 보낸 모든 데이터를 무시한다.
// 포트번호 : 7
발신지(source) > 목적지(destination): 플래그(flag)

tcpdump 출력
[3-WAY-Handshacke]
1 0.0 svr4.1037 > bsdi.discard:
S 1415531521 : 1415531521 (0) //flag: SYN, Sequence Num:14..21 (1개 받음)
win 4096 <mss 1024> // win: flow control을 위한 수선 buffer 크기(처리하기전에 쌓이는 buffer)
window size = 4096(최대 4개), max크기 = 1024 (수선할수 있는 최대 TCP 세그먼트 크기 = 패킷 최대 크기)
2 0.002402(0.0024) bsdi.discard > svr4.1037 :
S 1823083521 : 1823083521 (0) // flag: SYN, Sequence Num:18..21 (Random)
ack 1415531522 win 4096 // flag: ACK, 1번 ISN(svr4)+1을 통해서 받았음을 알림
<mss 1024>
3 0.007224(0.0048) svr4.1037 > bsdi.discard: // 더이상 mss 변동이 없기 때문에 win만 갱신함
.ack 1823083522 win 4096 // 2번 ISN(bsdi)+1해서 ACK 받음
-----------------------------------------------------------------------------------------------------------------------------------------------
[4-WAY-Handshacke]
4 4.155441(4.1482) svr4.1037 > bsdi.discard:
F 1415531522 : 1415531522 (0) // flag: F, 2번 SN 그대로이기 때문에 중간에 message 교환 없음
ack 1823083522 win 4096 // 3번 SN(bsdi)그대로 유지
5 4.156747(0.0013) bsdi.discard > svr4.1037
.ack 1415531523 win 4096 // 4번 SN(svr4)+1해서 ACK 받음
6 4.158144(0.0014) bsdi.discard > svr4.1037
F 1823083522: 1823083522 (0) // flag: F, 4번 SN(bsdi) 가져옴
ack 1415531523 win 4096
7 4.180662(0.0225) svr4.1037 > bsdi.discard:
.ack 182308353 win 4096 // 6번 SN(bsdi)+1해서 ACK 받음

연결 확립 프로토콜
1. [SYN] 요구 측의 종단은 접속하고자 하는 서버의 포트번호와 클라이언트의 초기순서번호 (Initial Sequence Number, ISN)를 지정한 SYN 세그먼트를 보낸다.
2. [SYN+ACK] 서버는 서버의 초기순서번호(ISN)를 포함한 자신의 SYN 세그먼트로 응답한다. 또 서버는 클라이언트의 ISN+1 ACK 를 보냄으로써 클라이언트의 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) / (EOF: End of File, EOD와 비슷)
3. (active close) 서버는 read 함수에서 EOF가 리턴 된 걸 확인하면, "보통" 해당 연결에 대한 close를 호출하도록 프로그램 되어 있다.
이 경우 FIN을 송신함
4. (passive close) 클라이언트는 FIN을 수신하면, FIN을 담은 세그먼트의 순서번호에 1을 더한 ACK를 보낸다.
# 위 종료 프로토콜에서 클라이언트와 서버가 바뀌어도 아무 문제가 없다. (다만, 요청-응답 응용에서 클라이언트가 먼저 닫는 경우가 많다)
3. 연결 확립의 타임아웃
연결 확립할 수 없는 예: 서버 호스트의 다운
1 0.0 bsdi.1024 > svr4.discard: S 291008001 : 291008001 (0) //ACK 받기위한 대기중
win 4096 <mss 1024>
[tos 0x10]
2 5.814797(5.8148) bsdi.1024 > svr4.discard: S 291008001 : 291008001 (0) //ACK 받기위한 대기중
win 4096 <mss 1024>
[tos 0x10]
3 29.81543(24.0006) bsdi.1024 > svr4.discard: S 291008001 : 291008001 (0) //ACK 받기위한 대기중
win 4096 <mss 1024>
[tos 0x10]
[tos 0x10] : IP 데이터그램의 서비스 유형필드
telnet, rlogin에서 대화용 로그인이기 때문에 클라이언트의 지연을 최소화하기 위함
클라이언트의 TCP가 연결을 설정하기 위해 SYN를 보낸다.
- 첫 번째 세그먼트를 보낸 후 2번째 연결을 위한 시도는 5.8초 후에 보낸다.
- 두 번째 세그먼트를 보낸 후 3번째 연결을 위한 시도는 24초 후에 보낸다.
일반적으로 버클리 시스템의 경우는 최대 76초 동안 연결을 시도한다.
4. 최대 세그먼트 크기
Maximum Segment Size (MSS): TCP가 상대편에 한번에 보낼 수 있는 데이터의 최대 크기
(MSS는 한 패킷에 각종 헤더를 제외한 순수 뎅이터 크기 vs MTU는 한패킷에 헤더값 포함)
연결이 확립될 때 각 종단은 MSS를 통지 (TCP 옵션)
MSS = MTU- IP 헤더 - TCP 헤더 (path MTU가 있을 수 있지만 자신이 받을 수 있는 크기는 이만큼이다라고 이야기해줌)
- (예) 이더넷 : 1460바이트
Default MSS 설정 : 각 종단은 받기를 원하는 MSS를 알리는 option을 갖는다.
- 시스템 별 default MSS가 다를 수 있음
1 0.0 sun.1093 > slip.discard : S 517312000: 517312000 (0)
<mss 1460> //1500-20-20
2 0.10(0.00) slip.discard > sun.1093: S 509556225 : 509556225 (0)
ack 517312001 <mss 256> // 296-40
3 0.10(0.00) sun.1093 > slip.discard : .ack 1

sun에서 MSS를 1460으로 보냈으나 slip에서 MSS를 256으로 통지하였기 때문에 sun은 통신시에 데이터를 256바이트 이상으로 못 보냄
통신상의 중간 라우터가 양단간의 MSS보다 작은 MTU를 갖는다면 전송되는 데이터는 단편화가 발생
5. TCP 절반 폐쇄
절반 폐쇄(half-close): TCP 연결의 한 쪽 종단이 다른 쪽 종단으로부터 데이터를 전송 받고 있는 상태에서도 데이터의 출력을 종료할 수 있는 기능
BSD Sockets API는 응용이 close를 대신 shutdown을 호출(두 번째 인자 howto – SHUT_WD)하여 절반 폐쇄함 (송신만: WD=1)
- close: 정식, shutdown : 강제(두개의 인자, sock + howto(송신만, 수신만등을 결정))
- BSD Sockets API에서 close() 함수를 호출하는 것은 절반 폐쇄가 아니다!
- 절반 폐쇄가 있음에도 많은 응용은 연결 종료 시 close를 이용하여 양방향 폐쇄 (앞에서 다룬 종료 프로토콜)를 수행
아래 예제는 서버가 EOF를 받았음에도 (1) 보낼 데이터가 남아있었고, (2) 응용이 shutdown으로 절반 닫기 했기 때문에 계속 데이터를 수신하는 것이 가능함 (만약 클라이언트가 close했는데 서버가 write하면 데이터 전달 실패됨)
절반 폐쇄 예

sort 프로그램은 입력되는 데이터가 읽혀질 때까지 데이터는 bsdi 서버에 전달된다. 입력데이터의 EOF에 도달하면 sun 클라이언트는 TCP연결상에서 절반 폐쇄를 실행한다. (보낼 데이터가 없고, 수신만 가능)
bsdi 서버는 파일을 정렬하고 결과를 sun 클라이언트 표준출력의 데이터로 전달한다.
bsdi 서버는 클라이언트에 데이터전달을 종료하면 종료를 수행한다.
6. TCP 상태 천이도
사진!!
일반적인 연결 확립과 종료에 대한 TCP 상태(클라이언트가 먼저 active close할 필요는 없으나 그렇다고 가정함)

TIME_WAIT (2MSL Wait) State (대기상태)
Maximum Segment Lifetime (MSL): 세그먼트가 네트워크 상에 존재할 최대 시간 (가정)
- RFC 793에서는 2분으로 명시했지만, 구현은 다른 값 (30초, 1분, 2분 등)을 사용하기도 함
- IP 데이터그램이 TTL로 패킷의 수명을 제약하지만, 실제 시간이 아니라 hop 수임에 주의
TCP가 능동적 폐쇄를 한 뒤 마지막 ACK를 보냈다면, 해당 연결은 2MSL동안 TIME_WAIT 상태임
- 이는 다시 말해 해당 연결을 2MSL동안 재사용할 수 없음을 의미함
- 이유: 마지막 ACK가 만약 손실되면, 재전송을 해야 하기 때문 (상대 측에서 FIN을 다시 보낼 것임)
- 다른 효과: 해당 "연결"에 대응하는 소켓 페어의 재사용을 막기 위함
(네트워크에 남아 있는 패킷이 이상행동을 일으킬 수 있으므로! 그런 패킷 도착 시 discard)
- 표준과 달리 BSD 및 BSD를 따라한 구현들은 "연결"뿐만 아니라 "로컬 포트 번호"의 재사용을 막음
(TCP 표준은 같은 연결을 다시 못 맺을 뿐이지만, 구현들은 해당 포트 자체를 못 쓰게 함)
- SO_REUSEADDR(강제사용) 소켓옵션을 가진 API에서는 해당 포트의 재사용을 허용할 수 있지만, 연결의 재사용은 원래 TCP 표준에서는 허용안함 (2판: RFC1122, RFC6191 통해 허용됨)
서버의 경우 이 상태가 문제를 일으킴; 서버를 갑자기 종료시킨 뒤 재시작하면, 해당 포트를 최대 4분 동안 못 쓰는 상황 (!!)이 발생하기 때문 (2분이라면 x2배 4분이 된다)
예) 먼저 서버를 동작시키고 클라이언트로 이를 연결한 후 서버를 종료
sun % sock v -s 6666
connection on from 140.252.13.35.1081 to 140.252.13.6666 클라이언트의 1081포트로 접속
^?
sun % sock -s 6666
Can’t bind local address : Address already in use
sun % netstat
Active Internet connections
Proto Recv-Q Send-Q Local Address Foreign Address (State)
tcp 0 0 sun.6666 bsdi.1081 TIME_WAIT
예) 클라이언트가 TIME_WAIT 상태에 있는 로컬 포트 번호로 연결을 재시도한 경우 (서버 측면)
sun % sock v -s 6666 //-s: 서버로 동작, 6666: port번호를 열음 (서버->클라이언트)
connection on from 140.252.13.35.1081 to 140.252.13.6666 //클라이언트의 1081포트로 접속
^? //강제종료, escape
sun % sock -s 6666
Can’t bind local address : Address already in use //재사용 안됨
sun % netstat
Active Internet connections
Proto Recv-Q Send-Q Local Address Foreign Address (State)
tcp 0 0 sun.6666 bsdi.1081 TIME_WAIT //마지막 ACK를 보내고 기다리는 중
sun % sock -v bsdi echo //Echo: 다시 되돌려주는 명령어 (클라이언트->서버)
connection on from 140.252.13.33.1162 to 140.252.13.35.7 //1162 포트로 접속
Hello there
Hello there
^D //강제 종료
sun % sock -b1162 bsdi echo // 1162: 지정하지 않으면 랜덤 port로 지정해서 접속 정상화됨
Can’t bind local address already in use
※ 참고: BSD 구현들은 TCP 표준 위반임에도, 같은 연결을 원래의 반대쪽 호스트에서 시작하면 허용함
※ TCP 표준은 TIME_WAIT 상태의 호스트가 재부팅되는 경우 2MSL 상태(날라감)를 저장하지 않을 것이 걱정되어, 재부팅 뒤 MSL 초 동안은 연결 생성을 금지함 (이를 quiet time이라고 부름) -> 상대가 금지 시킴
FIN_WAIT_2 상태
FIN_WAIT_2(서버가 FIN을 보내기전) 상태에서 서버가 FIN을 보내주지 않으면, 연결이 계속 같은 상태에 빠짐(잠원 점유, 전원 ON 유지)
BSD에서 유래된 구현들은 응용 close 함수를 호출하여 능동적 폐쇄한 경우, 타이머를 설정해 타임아웃 (2판: Linux의 경우 1분) 동안 연결이 휴지 상태 (idle)이면, 해당 연결을 CLOSED로 처리해버림
(표준 위반이지만 더 나은 방법이 있을까?)
7. 재설정(RESET) 세그먼트
재설정은 참조 연결에 대해서 바르지 않은 세그먼트가 도착할때 발생함
- 참조 연결 (reference connection) : 4-tuple이 명시된 연결, 즉 FRC 793에서의 socket
- 4 tuple : souce/ Dst IP, src/Dst Port -> socket pair = reference connection
재설정 세그먼트가 사용되는 예 1: 존재하지 않는 포트에 대한 연결 요청 (닫힌 포트)
연결 요청이 목적지에 도청했지만, 목적지 포트 상에 listen 중인 프로세스가 없는 경우
예) 목적지에서 사용되지 않는 포트 번호를 지정하여 연결 시도
bsdi % telnet svr4 20000
Trying 140.252.13.34
telnet : Unable to connect remote host : Connection refused // ex. www.naver.com : 8080 -> url은 맞아도 port가 달라서 연결안됨
1 0.0 bsdi.1087 > svr4.20000 : S 297416193 : 297416193 (0) // 1087: 랜덤
win 4096 </mss 1024>
[tos 0x10]
2 0.003771(0.0038) svr4.20000 > bsdi.1087 : R 0 : 0 (0) // R: 종료 (올바른 요청이 아님)
ack 297416194 win 0
연결 중단 (Aborting a Connection)
정규해제(ordinary release): 상대편에 FIN 신호를 보내서 연결을 종료 (terminate)한 상황 / FIN은 큐에 대기한 데이터를 모두 전송한 후에야 전송되므로, 데이터에 대한 손실이 없음
중단해제(abortive release): FIN 대신에 재설정(RST)을 전송하여 연결을 중단 (abort)한 상황
연결 중단을 할 경우에 응용이 얻는 장점
대기 중인 (queued) 데이터를 바로 버리고 즉시 재설정 신호 (RST)를 전송해 연결을 재설정 가능
RST의 수신측 TCP는 응용에게 'RST 송신측이 연결을 중단했음'을 알릴 수 있음
- 따라서, API는 응용이 연결 중단을 할 수 있는 방법을 제공해야 함
(BSD는 SO_LINGER 옵션이 대표적인데, 여기서 linger는 중단 전에 기다릴 시간을 의미) -> SO_LINGER: 대기시간을 줄일수는 있음. 하지만 구지? 그래서 보통은 0이다.
bsdi % sock -L0 svr4 8888 //L0: LINGER=0: 기다리지 말고 즉시 보내라
hello, world
^D
svr4 % sock -s 8888
hello, world
read error : connection reset by peer
1 0.0 bsdi.1099 > svr4.8888 : S 671112193 : 671112193 (0) // 0: 상대적 시퀀스 넘버를 의미(ACK) / 1-3번 TCP 연결 확립
<mss 1024>
2 0.004975(0.0050) svr4.8888 > bsdi.1099 : S 322495489 : 322495489 (0) //SYN+ACK
ack 671112194 <mss 1024>
3 0.006656(0.0017) bsdi.1099 > svr4.8888 : . ack //ACK >> 3-way-handshake(맞나..?)
----------------------------------------------------------------------------------------------------------------------------------------
4 4.833024(4.8263) bsdi.1099 > svr4.8888 : P 1:14(13) ack 1 // 4-5번 데이터 전송, 13byte 전송
5 5.026224(0.1932) svr4.8888 > bsdi.1099 : .ack 14 // 14번까지는 잘 받음
6 9.527634(4.5014) bsdi.1099 > svr4.8888 : R 14 : 14 (0) ack 1 // R: ^D: 강제종료, 0: DATA 없음 FLAG만 전송, ACK: connetion reset by peer
절반 개방 연결

절반 개방 (half-open)
- half-close 개발자가 의도했지만 open은 아님
- 호스트 A가 호스트 B에게 세그먼트를 따로 보내지 않고 연결을 종료 또는 중단
(e.g., 호스트 A가 고장 또는 재부팅)
절반만 개방된 상태이더라도, B가 데이터 전송을 시도하지 않으면 B는 고장을 알 수 없음
- 때문에, 절반 개방된 연결로 B가 세그먼트를 보내는 경우, A의 TCP는 RST(재설정)로 응답해야 함
1 0.0 bsdi.1102 > srv4.discard : S 1591752193 : 1591752193 (0)
2 0.004811(0.0048) srv4. discard > bsdi.1102 : S 26368001 : 26368001 (0) // 1-3 연결 확립
ack 1591752194
3 0.006516(0.0017) bsdi.1102 > srv4.discard : .ack 1
------------------------------------------------------------------------------------------------------
4 5.167679(5.1612) bsdi.1102 > srv4.discard : p 1:11 (10) ack 1 // 4-5 hi there 데이터 전송
5 5.201662(0.0340) srv4.discard > bsdi.1102 : .ack 11
// srv4가 여기서 재부팅
6 194.909929 (189.7083) bsdi.1102 > srv4.discard : P 11:25 (14) ack 1 // 6 another line 데이터 전송
7 194.914957(0.0050) arp who-has bsdi tell srv4 // 7-8 arp 요구와 응답, ARP를 돌려서 bsdi가 누군지 srv4에게 알려줘
8 194.915678(0.0007) arp reply bsdi is-at 0:0:c0:6f:2d:40 // bsdi가 자신의 mac 알려줌
9 194.918225(0.0025) svr4.discard > bsdi.1102 : R 26368002 : 26368002 (0) // 9 재설정, reset 발생..
TIME_WAIT Assassination (TWA) [RFC1337] (2판) ->FIN,ACK 교환
아래와 같이 Client가 TIME_WAIT 상태에 있는데, Server가 오래전에 보낸 패킷이 늦게 도착하고 이를 응답하는 바람에 Server가 RST를 보내서 Client의 TIME_WAIT를 의도치않게 꺼버리는 문제
대부분의 구현은 TIME_WAIT 상태 동안 도착한 RST 세그먼트를 무시함

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


bsdi % sock v b8888 vangogh.cs.berkeley.edu 7777
Connected on 140.252.13.35.8888 to 128.32.130.2.7777
TCP_MAXSEG = 512
hello, world
and hi there
connection closed by peer
vangogh % sock v b7777 bsdi.tuc.nao.edu 8888
Connected on 128.32.130.2.7777 to 140.252.13.35.8888
TCP_MAXSEG = 512
hello, world
and hi there
^D
1 0.0 bsdi.8888 > vangogh.7777 : S 91904001 : 91904001 (0) win 4096 <mss 512>
2 0.213782(0.2138) vangogh.7777 > bsdi.8888 : S 1058199041 : 1058199041 (0)
3 0.215399(0.0016) bsdi.8888 > vangogh.7777 : S 91904001 : 91904001 (0) ack 1058199042 win 4096 <mss 512>
4 0.340405(0.1250) vangogh.7777 > bsdi.8888 : S 1058199041 : 1058199041 (0) ack 91904002 win 8192 <mss 512>
5 5.633142(5.2927) bsdi.8888 > vangogh.7777 : P 1:14(13) ack
6 6.10036 (0.4 672) vangogh.7777 > bsdi.8888 : .ack 14 win 8192
7 9.640214(3.5398) vangogh.7777 > bsdi.8888 : P 1:14(13) ack 14 win 8192
8 9.796417(0.1562) bsdi.8888 > vangogh.7777 : .ack 14 win 4096
9 13.060395(3.2640) vangogh.7777 > bsdi.8888 : F 1:14(0) ack 14 win 8192
10 13.061828(0.0014) bsdi.8888 > vangogh.7777 : .ack 15 win 4096
11 13.079769(0.0179) bsdi.8888 > vangogh.7777 : F 1:14(0) ack 15 win 4096
12 13.299940(0.2202) vangogh.7777 > bsdi.8888 : .ack 15 win 8192
동시에 bsdi의 8888포트와 vangogh의 7777포트를 동시 개방을 실행
1-4
5-6 : bsdi로부터 vangogh로 전송되는 입력 데이터와 확인응답
7-8 : vangogh로부터 bsdi로 전송되는 입력 데이터와 확인응답
9-10 : 일반적인 연결 종료
9. 동시 종료
양쪽 종단으로부터 능동적 폐쇄를 수행할 수 있음
동시 폐쇄는 일반적인 폐쇄와 같은 수의 세그먼트 교환

10. TCP 옵션
TCP 헤더에 옵션을 추가
RFC 793, 1323 은 추가적인 TCP 옵션을 정의
옵션의 유형은 kind의 값으로 구분
NOP(no operation) : 송신측이 필드를 4바이트의 배수가 되도록 채우기 위함
- 예 : <mss 512, nop, wscale 0, nop, nop, timestamp 146647 0>

11. TCP 서버 설계
TCP 서버는 병행성 (concurrent; 동시성)을 갖도록 설계함
서버는 새로운 연결 요청이 도착하면 서버는 그 연결을 받아들이고 새로운 클라이언트를 처리하기 위해 새로운 프로세스 또는 스레드를 가동함 -> fork(): 똑같은 프로세스 생성 기능
본 절에서는 병행성을 지원하는 TCP 서버의 자원 활용에 대해 논의함
TCP 서버 포트 번호
netstat 옵션
- a : 네트워크상의 모든 종단점을 표시
- n : DNS서버를 사용하여 IP주소를 dotted decimal로 출력하고 서비스이름을 숫자로 포트번호를 출력
- f inet : TCP와 UCP 종단점만 표시 (2판: 리눅스에서는 –t 옵션)
Sun % netstat -a -n -f inet
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (State)
tcp 0 0 *.23 *.* LISTEN
//Local Address : Local network interface card (LAN카드)
//*.* : 누구나 . 어떤 포트든
로컬주소 *.23는 임의의 로컬 인터페이스에서 받아들이는 의미
외부주소 *.*는 외부 IP주소와 포트를 알지 못하고 있으며 종단점은 연결의 도착을 기다림
Proto Recv-Q Send-Q Local Address Foreign Address (State)
tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED
tcp 0 0 *.23 *.* LISTEN
//LISTEN : 다른 연결요구를 받기위해서 계속 유지
LISTEN 상태는 병행서버가 나중에 연결요구를 받아들이기 위해 이용되는 종단점
Proto Recv-Q Send-Q Local Address Foreign Address (State)
tcp 0 0 140.252.1.29.23 140.252.1.32.34603 ESTABLISHED
tcp 0 0 140.252.13.33.23 140.252.13.65.1030 ESTABLISHED
tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED
tcp 0 0 *.23 *.* LISTEN
// 140.25.1.29.23으로만 신호 받기, 즉 수신 포트 한정
// 140.252.1.32.34603 : 신호를 보내는것은 자유
멀티홈드 호스트인 sun에는 slip 링크의 인터페이스(140.252.1.29)와 이더넷 (140.252.13.33)에 장착되어 있음
로컬 IP 주소의 제한
서버가 로컬 IP주소를 와일드 카드로 하지 않는 경우 지정된 로컬 IP주소 외에는 연결을 거부
Sun % sock -s 140.252.1.29 8888 140.252.1.29 //IP로 연결을 제한
Proto Recv-Q Send-Q Local Address Foreign Address (State)
tcp 0 0 140.252.1.29.8888 *.* LISTEN
// 140.252.13.33은 불가능하다. 포트를 8888로 제한해서?
외부 IP 주소의 제한
TCP 서버가 자신에 대해 확립할 수 있는 제한 형식
lport는 서버의 알려진 포트, localIP는 로컬 인터페이스의 IP의 주소

수신 연결 큐 (Incoming Connection Queue) (2판)
병행 서버는 각 클라이언트를 다루기 위해 새 프로세스를 만들 수 있지만, listen을 위한 서버는 accept 함수를 사용해 한 개의 연결 요청만을 처리할 수 있음
- 그렇다면, 여러 개의 연결 요청이 동시에 들어오면??
- 더군다나, 연결 설립이 되지 않는 연결 요청으로 공격받고 있다면?? (2판에서 추가로 다룸) -> ack가 오지 않는 공격
- 이런 문제를 TCP는 어떻게 다루는가? : queue 2개로 해결!!
이러한 연결들은 (1) SYN은 받았지만 아직 연결 설립이 되지 않은 연결, 또는 (2) 핸드셰이킹이 끝났지만 listen을 위한 서버가 아직 accept하지 못한 연결 중 하나임 -> (2) 서버 자체가 만들어 지지않음, 프로세스가 만들어지지않음, 대기중에 있을수 있음
- 운영체제에 포함된 TCP 구현은 각 상황을 처리하기 위한 연결 큐를 각각 가지고 있음 -> 해결방안
- 응용은 제한된 문맥에서 이 두 개의 큐의 크기를 조절할 수 있음
(BSD Sockets API는 전통적으로 두 큐의 합 크기를 설정하는 옵션을 제공했지만, 최신 Linux 커널은 해당 옵션을 사용하면 (2)번 큐의 크기를 정함) -> (2)번만 크기를 조정함
수신 연결 큐 (Incoming Connection Queue) (2판) >좀더 공부 필요
[리눅스에서 수신 연결 큐에 관한 규칙]
1. 시스템 파라미터 net.ipv4.tcp_max_syn_backlog (기본값 1000)이 운영체제에서 수용가능한 SYN 요청 수를 결정
- SYN_RCVD 상태의 연결 수가 이 값을 넘으면 새로운 연결 요청은 거절됨 -> 공격 SYN flooding (Dos attack)
2. 각 listening TCP socket은 앞 슬라이드 (2)번 연결에 대한 고정된 크기의 큐를 가지고 있으며, 큐의 크기를 backlog라고 부름
- backlog는 시스템 파라미터 net.core.somaxconn (기본값 128)을 넘을 수 없음 (코드에서 지정가능)
3. (2)번 연결에 대한 큐에 공간이 있으면, TCP는 SYN 요청에 대한 ACK를 송신해서 three-way handshake를 완료하려 함
4. (2)번 연결에 대한 큐에 공간이 없으면, Linux의 TCP 구현은 SYN에 대한 응답을 지연시키는 독특한 동작을 하는데, listening 서버가 accept을 해서 이 위기를 극복할 거라 생각한 설계임
- 하지만 시스템 파라미터 net.ipv4.tcp_abort_on_overflow가 설정되어 있으면, 지연시키지 않고 바로 RST 세그먼트를 보내 연결 중단: 강제
결국, BSD Sockets API에서, 응용이 연결 도착을 알 게 되었을 때에는 (즉, accept 함수가 연결 소켓을 리턴했을 때에는) 이미 TCP의 three-way 핸드셰이킹이 끝나있는 상태임에 주의할 것
- 한편, TCP 클라이언트의 connect는 서버로 SYN+ACK를 받으면 리턴되므로, 서버가 연결 소켓을 가지게 될 때에는 이미 클라이언트가 데이터를 보냈을 수 있음
출처 : Hoorin Park Assistant Professor, Department of Information Security, Seoul Women’s University
'공부' 카테고리의 다른 글
[윈도우 보안] Integrity Level (0) | 2023.07.20 |
---|---|
네트워크보안 v.05 _ DNS 공부 (0) | 2022.10.19 |
네트워크보안 v.03 _ TCP/IP Networks 공부 (TCP) (0) | 2022.10.11 |
네트워크보안 v.02 _ TCP/IP Networks 공부 (UDP/TCP) (0) | 2022.10.07 |
네트워크보안 v.01 _ TCP/IP Networks 공부(ARP) (1) | 2022.10.06 |