네트워크 기초 - TCP/UDP
포스팅하는 순서를 꽤 신경을 많이 쓰고 있는편인데 어떤 주제를 다루려고 하면 이상하게 아.. 이거 전에 다른거 먼저 다뤄야 하겠구나.. 싶어서 자꾸 미뤄지네요.
배움에 중요도라는게 어디있겠냐마는 그래도 기초를 잘 다져야 나중에 고생이 덜하니 비중 있는 주제를 순서대로 다뤄야 한다는 생각이 자꾸 들어서 막상 다루고 싶은 SDN이나 Lab 내용들을 계속 미루게 되니 아쉽네요. 언제쯤 다룰 수 있을지 막막합니다. 그래도 열심히 써나가보겠습니다.
앞서 스위칭 편에서 간략하게 한번 다루었던 내용입니다.
REFERENCE 네트워크 기초 - 스위칭 (Switching)
전송계층 프로토콜로, 우리가 하는 인터넷은 거진 다 TCP/UDP 라고 보셔도 무방합니다. 당연히 IP와 함께 사용됩니다.
1. TCP (Transmission Control Protocol)
전송을 컨트롤하는 프로토콜이라는 뜻으로 인터넷에서 데이터를 메시지의 형식으로 주고받기 위해서 사용합니다.
스위칭에서도 말씀드렸다시피 TCP는 가상회선 패킷 교환 방식을 사용하는 연결형 서비스인데, 이번에는 연결을 맺기위한 과정에 대해 자세히 설명해 볼까 합니다.
가상회선 패킷 교환 방식의 특징으로는 주고받는 데이터의 순서를 표시하는 흐름제어, 또 그로인한 높은 데이터의 신뢰성 보장이 장점이 되겠습니다.
이러한 연결을 맺는 과정을 3-Way Handshaking, 연결을 해제하는 과정에서 4-Way Handshaking을 거치게 되는데 이 또한 말그대로 만나서 반갑다고 악수하는과정, 헤어지기 전 악수를 하는 과정이라고 생각하신다면 이해가 빠르실 듯 합니다.
TCP 헤더입니다. 이번에 눈여겨 보실 것은 포트주소, Sequence number, Acknowledgement number, 그리고 6개의 Flag 필드입니다.
1.1. 3-Way Handshaking
영어로 써 있으니 굉장히 복잡해 보일 수 있겠으나 사실 간단한 내용입니다. 처음 보는 사람을 만났을때 인사로 악수를 하면, 그 악수에는 대략적으로 이러한 의미들이 담겨있겠습니다.
이 과정이 인터넷에서도 똑같이 이루어 진다고 보시면 됩니다. 가상회선 방식에서 논리적 연결을 맺기 전에 상대방을 정확하게 확인하고 연결하기 위해 수행하는 과정입니다. 이 과정에서 3번의 패킷 교환후 연결을 수립하는데, 이것이 악수하는것 같다 하여 3 Way Handshake라는 이름을 갖게 됩니다.
1단계
우선, 연결을 맺기 위해서 서버는 연결을 위한 포트가 열려있어야 하겠습니다. 그리고 클라이언트는 서버에 SYN(Synchronize) 패킷, 동기화를 위한 시퀀스 번호를 전송하여 접속을 요청합니다. 이 시퀀스 번호는 무작위의 난수를 발생시켜 전송하게 됩니다. 이해를 돕기위해 SEQ 번호를 1이라고 가정하겠습니다.
2단계
서버측에서는 클라이언트로부터 SYN 패킷을 전송받게 되면 요청을 받은것을 확인했다는 ACK(Acknowledgment) 패킷과, 서버측에서도 연결을 맺기 위한 SYN 패킷을 같이 보내게 됩니다. 이 때, 확인을 위해 받았던 SYN 패킷의 SEQ 번호에 1을 더한 2를 ACK 패킷에 포함하고, SYN 패킷에는 또다른 난수를 발생시켜 보냅니다. 10이라고 가정해봅시다.
3단계
클라이언트 측에서는 ACK패킷을 받았고 SEQ 를 1로 보냈는데 +1하여 2를 담은 ACK가 왔으니, 성공적인 연결이 수립되었다는것을 알 수 있겠습니다. 그리고 서버측에서 보낸 SYN 패킷에 SEQ가 10이니, 자신도 +1 하여 11을 보내주어야겠죠. ACK 패킷에 SEQ 번호를 11로 설정하여 서버측으로 돌려보냅니다.
서버측에서는 자신이 보낸 요청(SEQ=10)에 대한 응답이 ACK(SEQ=11)로 돌아왔으니, 이 연결이 성공적으로 수립되었다는것을 알 수 있겠습니다. 이제 양측간 연결이 수립되었으니 서로 데이터를 주고받을 수 있습니다.
데이터 송수신
데이터를 주고받는것은 요청하고 받아오는것의 연속입니다. TCP에서는 이와 같은 방식으로 데이터를 송수신하며 데이터가 유실되거나 응답이 없을 경우에 재요청하고 받아오므로 신뢰성 있는 데이터를 보장한다는 것입니다.
패킷캡쳐
매번 말하지만 와이어샤크로 이 패킷들을 직접 확인하면 훨씬 이해가 빠릅니다. 헤더가 어쩌고 뭐가 어쩌고 설명을 해도 실제로 이런 데이터들을 주고받는다는 것을 눈으로 확인하는 것이 이해하기 더 좋습니다. 여건이 되신다면 따라해 보시면 좋겠습니다.
우선 와이어샤크를 키고, 캡쳐를 시작한 상태로 인터넷 주소창에 접속하고 싶은 사이트로 들어갑니다. 저는 daum.net 으로 접속했습니다.
페이지가 로딩이 완료되면 캡쳐를 중지하고 cmd 에서 nslookup [접속페이지 주소] 를 입력하여 ip 주소를 찾아봅시다.
대형 웹 페이지들은 접속자가 많아 로드밸런싱하기 때문에 여러 IP가 나옵니다. 하나씩 입력해보면 됩니다.
ip.addr==[IP주소] 형식으로 와이어샤크에서 검색합니다. 저는 4번째 주소네요. 그 다음 최상단을 확인해보면 뭔가 익숙한 패킷들이 보이기 시작합니다.
SYN, ACK? 이놈들이군요. 연관 패킷만 골라내기 위해 최상단 SYN 패킷을 우클릭하여 [Follow] → [TCP Stream] 을 클릭해주고 TCP 헤더를 펼쳐서 확인해보겠습니다.
좌측 SYN 패킷의 SEQ number : 97501486,
우측 ACK 패킷의 ACK number : 97501487,
우측 SYN 패킷의 SEQ number : 2079120530,
마지막 ACK 패킷의 ACK number : 2079120531.
+1 하여 주고받은것을 확인할 수 있습니다. 신기하죠?
1.2 4-Way Handshaking
3Way는 연결을 수립하기위해, 4Way는 연결을 끝내기 위해 사용됩니다. FIN(Finish) 패킷은 연결을 종료하기 위해 설정되는 플래그입니다.
4Way Handshake는 웹페이지 패킷 캡쳐로는 확인 불가능합니다. 웹 페이지는 접속자가 많은 관계로 서버쪽에서 보낼 데이터를 다 보낸 이후에는 강제로 연결을 끊어버리기 때문에 이러한 Handshake 과정을 거치지 않기 때문입니다.
패킷을 캡쳐해보고 싶으신 분들은 Telnet 과 같은 TCP 기반의 서비스를 사용하며 패킷을 캡쳐해보시면 이 4 Way Handshake 과정을 확인하실 수 있습니다.
하지만 기본적인 과정 자체는 3Way Handshake와 유사하므로, 4번의 패킷을 주고받는다는 것과, FIN 패킷에도 SEQ 번호가 포함되지만 SYN 처럼 SEQ번호가 없는 상태에서 만들어야 하는 것이 아니므로 주고받던 SEQ 번호를 그냥 사용한다는 것, ACK 패킷에 FIN SEQ번호에 +1 된다는것을 기억하시면 될 것 같습니다.
1.3 상태
3 Way Handshake와 4 Way Handshake는 패킷을 주고받음에 있어 다음과 같은 상태들을 각각 가지게 됩니다. 각 순서에 대한 상태요약은 아래 표를 참조하시면 됩니다.
상태 | 설명 |
CLOSED | 연결을 시도하지 않은 상태 |
LISTEN | 포트가 열린 상태로 연결을 대기하는 상태 |
SYN_SENT | SYN 요청을 한 상태 |
STN_RECEIVED | SYN 요청을 받고, 상대의 응답을 대기하는 상태 |
ESTABLISHED | 연결이 성립된 상태 |
FIN_WAIT | 연결 종료를 위해 FIN 패킷을 보내고 대기하는 상태 |
CLOSE_WAIT | FIN 패킷을 받고 연결 종료를 위해 ACK 패킷을 전송하고, 연결 종료를 위해 데이터를 처리하는 상태 |
LAST_ACK | 더이상 처리할 데이터가 없을때 연결 종료 요청에 합의한다는 의미로 FIN 패킷을 전송하고, 응답을 대기하는 상태 |
TIME_WAIT | 연결 종료를 위해 ACK 패킷을 보내고 실질적인 연결을 종료하는 상태 |
1.4 보안 취약점
이러한 Handshaking 과정들을 연결 수립, 종료마다 수행하기 때문에 속도가 비교적 느리다는 단점을 가지지만 굉장히 안정적인 시스템으로 보입니다. 하지만 보안 취약점 역시 존재합니다. 대표적으로 SYN Flooding 공격이 있는데 이 생소해 보이는 공격이 바로 DDoS(분산 서비스 거부) 공격의 일종 입니다.
연결을 맺을 때 서버는 클라이언트의 SYN을 받고 연결작업 수행을 위해 서버의 자원인 메모리를 할당합니다. 이 할당된 부분을 Queue 라고 하는데, 엄청나게 많은 수의 클라이언트가 SYN 요청을 보내고, 서버가 SYN, ACK를 보냈음에도 불구하고 다시 ACK를 보내지 않는다면 서버는 많은 수의 클라이언트들의 응답을 기다리며 메모리를 계속 할당한 상태로 있게 됩니다.
결국 메모리가 바닥나면 서버가 제 기능을 하지 못하게 되겠죠. 3 Way Handshake를 안 할 수도 없고, 공격을 당하고 있을수만도 없으니 아래와 같은 방어대책을 세우게 됩니다.
1. 백로그 큐 늘리기
메모리를 늘려서 수용 인원을 늘립니다. 비용이 많이 들고 무한정 확장시킬 수 없으니 근본적인 해결책은 아니겠습니다. 원래 예측되는 사용자 수를 충분히 수용하고도 남을 정도의 메모리를 확보하지만 보안공격은 일반적인 상황이 아니기에 완벽히 대처할 수 없습니다.
2. Anti-DDoS 사용
특정 IP에서 SYN 요청이 갑자기 수십개 수백개가 온다면 접속을 일정시간 차단시키는 방법입니다. 이를 임계치 기반 방어라 합니다.
3. SYN Cookie 사용
서버와 사용자간에 방화벽을 두고 방화벽이 정상적인 사용자인지 먼저 확인합니다. 방화벽과 먼저 3 Way Handshake를 해보고, 정상적이면 연결을 수립할 수 있게 트래픽을 서버로 넘겨주는겁니다. 결과적으로 방화벽과 한번, 서버와 한번 하여 Handshake를 두번 하게 되겠지만 일반적으로 사용자는 이 지연시간을 체감하기 힘듭니다.
4. SYN Proxy 사용
3과 비슷한 방식입니다. 굳이 체감은 못하지만 Handshake를 두번 하는게 굉장히 불편하죠. 방화벽과 Handshake를 성공적으로 수행하면 서버에서 굳이 한번 더 Handshake 할 필요가 없으니 방화벽이 서버에게 Handshake를 재현시켜주어서 한번의 Handshake로 연결을 수립할 수 있게 하는 방식입니다.
2. UDP (User Datagram Protocol)
UDP에 대한 내용이 기억나시나요? 데이터를 목적지만 맞으면 아무렇게나 뿌려서 최대한 빨리 보내는 방식이었습니다. 그래서 TCP 처럼 데이터가 정확하지 않고, 데이터 순서가 뒤섞일 수 있어서 순서를 짜맞추는 순서제어라는 기능이 필요해지고 주로 고용량 전송이나 연속성이 중요한 실시간 통신에 사용된다고 했었죠.
빨리 보내야 하는데 헤더가 TCP 처럼 복잡하면 그거 다 읽어봐야하니까 느려지겠죠. 그래서 최대한 간단한 형태의 헤더를 가집니다. 포트번호와 길이, 최소한의 오류 검출을 위한 체크섬 밖에 없죠. TCP 헤더와 비교해보겠습니다.
차이가 굉장히 심한걸 보실 수 있습니다. TCP에서 Handshake하고~ 어쩌고~ 하는 복잡한 과정또한 없습니다.
그냥 주고 받습니다. 연결 자체가 없고, 1:1, 1:N, N:M 등 여러 연결이 가능합니다. 너무나 간단한 프로토콜이죠. 그래서 설명할 내용도 딱히 없습니다. 이 TCP와 UDP를 잘 활용해서 용도에 맞게 사용하는것이 중요합니다.
3. 비교
두 프로토콜의 차이점만 한번 더 짚고 넘어가겠습니다. 워낙 상반되는 프로토콜이고 많이 사용되니 기억하기도 쉬울 것 같네요.