Chapter 11. Raw 소켓
Ping 애플리케이션의 동작 원리를 이해하고 작성 방법을 익힌다. 학습 목표 Raw 소켓의 특징과 사용 방법을 익힌다. Ping 애플리케이션의 동작 원리를 이해하고 작성 방법을 익힌다. Traceroute 애플리케이션의 동작 원리를 이해하고 작성 방법을 익힌다. ICMP.DLL이 제공하는 함수 사용 방법을 익힌다.
TCP(또는 UDP) 소켓 vs. Raw 소켓 개요 (1/2) 데이터 애플리케이션 운영체제 프로토콜 헤더 데이터 애플리케이션
개요 (2/2) Raw 소켓의 특징 애플리케이션 수준에서 프로토콜 헤더를 직접 조작 기존의 TCP 또는 UDP 소켓을 사용하는 방식보다 세부적인 제어 가능 프로토콜 헤더의 구조와 동작 원리에 대한 이해를 필요로 하므로 프로그래밍이 상대적으로 어려움 해킹을 위해 악용할 가능성이 있음
Raw 소켓 생성 (1/2) Raw 소켓 생성 예 SOCKET sock = socket(AF_INET, SOCK_RAW, protocol); if(sock == INVALID_SOCKET) err_quit("socket()"); 운영체제가 생성할 헤더 IP (없음) protocol IPPROTO_ICMP IPPROTO_IGMP IPPROTO_TCP IPPROTO_UDP 사용자 정의 애플리케이션이 ICMP (IP+ICMP) IGMP (IP+IGMP) TCP (IP+TCP) UDP (IP+UDP) 사용자 정의 헤더 (IP+사용자 정의 헤더)
IP_HDRINCL 옵션 설정 Raw 소켓 생성 시 주의 사항 Raw 소켓 생성 (2/2) #include <ws2tcpip.h> ... BOOL optval = TRUE; if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval)) == SOCKET_ERROR) { err_quit("setsockopt()"); }
Destination IP Address Options(If any) + Padding Raw 소켓 입출력 (1/4) IPv4 패킷 구조 0 3 4 7 8 15 16 18 19 31 Version Hlen Type of Service Total Length Identification Flags Fragment Offset Time to Live Protocol Header Checksum 20 바이트 Source IP Address Destination IP Address Options(If any) + Padding 가변 길이 데이터 가변 길이
IPv4 패킷 정의 Raw 소켓 입출력 (2/4) typedef struct _IPHEADER { u_char ip_hl:4; // header length u_char ip_v:4; // version u_char ip_tos; // type of service short ip_len; // total length u_short ip_id; // identification short ip_off; // flags & fragment offset field u_char ip_ttl; // time to live u_char ip_p; // protocol u_short ip_cksum; // checksum IN_ADDR ip_src; // source address IN_ADDR ip_dst; // destination address } IPHEADER;
Raw 소켓 출력 Raw 소켓 입출력 (3/4) ① 일반적으로 sendto() 함수를 사용한다. ② IP_HDRINCL 옵션을 설정하지 않을 경우, socket() 함수의 세 번째 인자에 해당하는 프로토콜 헤더를 생성하고, 여기에 애플리케이션 데이터를 덧붙여 보내면 된다. 이때 IP 헤더는 운영체제가 자동으로 생성하여 덧붙인다. ③ IP_HDRINCL 옵션을 설정할 경우, IP 헤더와 socket() 함수의 세 번째 인자에 해당하는 프로토콜 헤더를 생성하고, 여기에 애플리케이션 데이터를 덧붙여 보내면 된다. 즉 애플리케이션이 IP 헤더를 포함한 패킷 전체를 생성하여 보내는 것이다. ④ IP_HDRINCL 옵션을 설정하더라도 IP 헤더의 Identification 부분은 0으로 채우면 운영체제가 자동으로 할당한다.
Raw 소켓 입력 Raw 소켓 입출력 (4/4) ① 일반적으로 recvfrom() 함수를 사용한다. ② Raw 소켓으로 읽은 데이터 제일 앞쪽에는 항상 IP 헤더가 포함된다. 이것은 송신자가 IP_HDRINCL 옵션을 사용했는지 여부와 관계없다. ③ 대부분의 ICMP 패킷과 모든 IGMP 패킷, 그리고 운영체제가 인식할 수 없는 IP 패킷은 Raw 소켓으로 읽을 수 있다. 그러나 TCP와 UDP 패킷은 Raw 소켓으로 읽을 수 없다. ④ 운영체제는 IP 패킷을 받으면, 프로토콜이 일치하는 모든 Raw 소켓에게 이 패킷을 전달한다. 여기서 프로토콜이 일치한다는 것은 IP 패킷의 Protocol 부분과 Raw 소켓 생성시 socket() 함수에 전달한 세 번째 인자가 일치한다는 뜻이다.
Ping (1/5) Ping 애플리케이션 인터넷에 연결된 호스트의 동작 여부를 확인 ICMP를 이용하여 구현
ICMP(Internet Control Message Protocol) Ping (2/5) ICMP(Internet Control Message Protocol) 인터넷에 연결된 호스트 간에 유용한 정보(오류 발생, 라우팅 정보, ...)를 알리는 용도로 사용 항상 IP 패킷에 포함된 형태로 전송되며, TCP/IP 프로토콜 동작에 필수적인 역할을 담당 IP 헤더 ICMP 메시지 20+ 바이트
Type과 Code에 따라 달라지는 부분 (가변 길이) Ping (3/5) ICMP 메시지 구조 ICMP 메시지 정의 Type Code Checksum Type과 Code에 따라 달라지는 부분 (가변 길이) 0 7 8 15 16 31 typedef struct _ICMPMESSAGE { u_char icmp_type; // type of message u_char icmp_code; // type sub code u_short icmp_cksum; // checksum ... } ICMPMESSAGE;
Ping 애플리케이션 동작 원리 에코 요청, 에코 응답 ICMP 메시지 Ping (4/5) ping A A 에코 요청 Type(0 또는 8) Code(0) Checksum 옵션 데이터 (가변 길이) 0 7 8 15 16 31 Identifier Sequence Number
에코 요청, 에코 응답 ICMP 메시지 정의 Ping (5/5) typedef struct _ICMPMESSAGE { u_char icmp_type; // type of message u_char icmp_code; // type sub code u_short icmp_cksum; // checksum u_short icmp_id; // identifier u_short icmp_seq; // sequence number ... // 옵션 데이터 } ICMPMESSAGE;
Traceroute 애플리케이션 특정 호스트까지 IP 패킷 전달 경로를 확인 ICMP를 이용하여 구현
Traceroute 동작 원리 Traceroute (2/3) tracert A 에코 요청(TTL=1) 라우터 1 시간 초과 라우터 2 시간 초과 tracert A 에코 요청(TTL=n) 라우터 1 라우터 n-1 A ... 에코 응답
IP_TTL 옵션 설정 Traceroute (3/3) #include <ws2tcpip.h> ... int optval = TTL값; if(setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&optval, sizeof(optval)) == SOCKET_ERROR) { err_quit("setsockopt()"); }
IcmpCreateFile() 함수 ICMP.DLL (1/5) HANDLE IcmpCreateFile(void) ; 성공: 핸들, 실패: INVALID_HANDLE_VALUE
IcmpSendEcho() 함수 ICMP.DLL (2/5) DWORD IcmpSendEcho ( HANDLE IcmpHandle, ULONG DestinationAddress, LPVOID RequestData, WORD RequestSize, PIP_OPTION_INFORMATION RequestOptions, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout ) ; 성공: ReplyBuffer에 저장된 ICMP_ECHO_REPLY 구조체 개수, 실패: 0
관련 구조체 ICMP.DLL (3/5) typedef struct { unsigned char Ttl; // Time To Live unsigned char Tos; // Type Of Service unsigned char Flags; // IP header flags unsigned char OptionsSize; // Size in bytes of options data unsigned char *OptionsData; // Pointer to options data } IP_OPTION_INFORMATION, *PIP_OPTION_INFORMATION; typedef struct { DWORD Address; // Replying address unsigned long Status; // Reply status unsigned long RoundTripTime; // RTT in milliseconds unsigned short DataSize; // Echo data size unsigned short Reserved; // Reserved for system use void *Data; // Pointer to the echo data IP_OPTION_INFORMATION Options; // Reply options } IP_ECHO_REPLY, *PIP_ECHO_REPLY;
IcmpCloseHandle() 함수 ICMP.DLL (4/5) BOOL IcmpCloseHandle ( HANDLE IcmpHandle ) ; 성공: TRUE, 실패: FALSE
DLL 조작 함수 ICMP.DLL (5/5) HMODULE LoadLibrary ( LPCTSTR lpFileName // DLL 파일 이름 ) ; 성공: 핸들, 실패: NULL FARPROC GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) ; 성공: 함수 또는 변수 주소, 실패: NULL