winsock으로 rawsocket 보내기
글쓴이: simybh / 작성시간: 일, 2008/08/10 - 3:02오후
안녕하십니까 전에 winsock으로 rawsocket을 사용하여 tcp syn플래그를 보내는 것에 대해 문의 했었는데요
우선 답변을 주셔서 감사합니다.
알려주신대로 사이트(http://www.codeproject.com/KB/IP/rawsocket.aspx)에서 소스를 다운받아서 컴파일해서
실행해 보니 패킷보낼때 raw소켓 생성시나 send시에 에러는 없는데 이상하게 와이어샤크에서는 잡히지 않네요
windows2000 server이고 vc++6을 사용했습니다.
udp, icmp는 rawsocket으로 잘 갑니다. 와이어샤크에서도 패킷이 뜨구요
따라서 환경이 rawsocket이 발송안되는건 아닌거 같은데 tcp로 보낼때만 와이어샤크에 패킷이 잡히지 않네요
rawsocket이 아닌 SOCK_STREAM으로는 tcp도 잘 갑니다.
아래는 소스입니다. 물론 위 codeproject에서 다운받은 소스이구요
소스변형은 없었구요, 도대체 뭣때문에 tcp패킷이 rawsocket일때 안나가는지,, 알려주세요 ㅜ.ㅜ
이거 한 3주 잡고 있습니다.
//raw tcp packet crafter #include "stdio.h" #include "winsock2.h" #include "ws2tcpip.h" //IP_HDRINCL is here #include "conio.h" #pragma comment(lib,"ws2_32.lib") //winsock 2.2 library typedef struct ip_hdr { unsigned char ip_header_len:4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also) unsigned char ip_version :4; // 4-bit IPv4 version unsigned char ip_tos; // IP type of service unsigned short ip_total_length; // Total length unsigned short ip_id; // Unique identifier unsigned char ip_frag_offset :5; // Fragment offset field unsigned char ip_more_fragment :1; unsigned char ip_dont_fragment :1; unsigned char ip_reserved_zero :1; unsigned char ip_frag_offset1; //fragment offset unsigned char ip_ttl; // Time to live unsigned char ip_protocol; // Protocol(TCP,UDP etc) unsigned short ip_checksum; // IP checksum unsigned int ip_srcaddr; // Source address unsigned int ip_destaddr; // Source address } IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR; // TCP header typedef struct tcp_header { unsigned short source_port; // source port unsigned short dest_port; // destination port unsigned int sequence; // sequence number - 32 bits unsigned int acknowledge; // acknowledgement number - 32 bits unsigned char ns :1; //Nonce Sum Flag Added in RFC 3540. unsigned char reserved_part1:3; //according to rfc unsigned char data_offset:4; /*The number of 32-bit words in the TCP header. This indicates where the data begins. The length of the TCP header is always a multiple of 32 bits.*/ unsigned char fin :1; //Finish Flag unsigned char syn :1; //Synchronise Flag unsigned char rst :1; //Reset Flag unsigned char psh :1; //Push Flag unsigned char ack :1; //Acknowledgement Flag unsigned char urg :1; //Urgent Flag unsigned char ecn :1; //ECN-Echo Flag unsigned char cwr :1; //Congestion Window Reduced Flag //////////////////////////////// unsigned short window; // window unsigned short checksum; // checksum unsigned short urgent_pointer; // urgent pointer } TCP_HDR , *PTCP_HDR , FAR * LPTCP_HDR , TCPHeader , TCP_HEADER; int main() { char host[100],buf[1000],*data=NULL,source_ip[20]; //buf is the complete packet SOCKET s; int k=1; IPV4_HDR *v4hdr=NULL; TCP_HDR *tcphdr=NULL; int payload=512 , optval; SOCKADDR_IN dest; hostent *server; //Initialise Winsock WSADATA wsock; printf("\nInitialising Winsock..."); if (WSAStartup(MAKEWORD(2,2),&wsock) != 0) { fprintf(stderr,"WSAStartup() failed"); exit(EXIT_FAILURE); } printf("Initialised successfully."); //////////////////////////////////////////////// //Create Raw TCP Packet printf("\nCreating Raw TCP Socket..."); if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==SOCKET_ERROR) { printf("Creation of raw socket failed."); return 0; } printf("Raw TCP Socket Created successfully."); //////////////////////////////////////////////// //Put Socket in RAW Mode. printf("\nSetting the socket in RAW mode..."); if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR) { printf("failed to set socket in raw mode."); return 0; } printf("Successful."); //////////////////////////////////////////////// //Target Hostname printf("\nEnter hostname : "); gets(host); printf("\nResolving Hostname..."); if((server=gethostbyname(host))==0) { printf("Unable to resolve."); return 0; } dest.sin_family = AF_INET; dest.sin_port = htons(50000); //your destination port memcpy(&dest.sin_addr.s_addr,server->h_addr,server->h_length); printf("Resolved."); ///////////////////////////////////////////////// printf("\nEnter Source IP : "); gets(source_ip); v4hdr = (IPV4_HDR *)buf; //lets point to the ip header portion v4hdr->ip_version=4; v4hdr->ip_header_len=5; v4hdr->ip_tos = 0; v4hdr->ip_total_length = htons ( sizeof(IPV4_HDR) + sizeof(TCP_HDR) + payload ); v4hdr->ip_id = htons(2); v4hdr->ip_frag_offset = 0; v4hdr->ip_frag_offset1 = 0; v4hdr->ip_reserved_zero = 0; v4hdr->ip_dont_fragment = 1; v4hdr->ip_more_fragment = 0; v4hdr->ip_ttl = 8; v4hdr->ip_protocol = IPPROTO_TCP; v4hdr->ip_srcaddr = inet_addr(source_ip); v4hdr->ip_destaddr = inet_addr(inet_ntoa(dest.sin_addr)); v4hdr->ip_checksum = 0; tcphdr = (TCP_HDR *)&buf[sizeof(IPV4_HDR)]; //get the pointer to the tcp header in the packet tcphdr->source_port = htons(1234); tcphdr->dest_port = htons(50000); tcphdr->cwr=0; tcphdr->ecn=1; tcphdr->urg=0; tcphdr->ack=0; tcphdr->psh=0; tcphdr->rst=1; tcphdr->syn=0; tcphdr->fin=0; tcphdr->ns=1; tcphdr->checksum = 0; // Initialize the TCP payload to some rubbish data = &buf[sizeof(IPV4_HDR) + sizeof(TCP_HDR)]; memset(data, '^', payload); printf("\nSending packet...\n"); while(!_kbhit()) { printf(" %d packets send\r",k++); if((sendto(s , buf , sizeof(IPV4_HDR)+sizeof(TCP_HDR) + payload, 0, (SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR) { printf("Error sending Packet : %d",WSAGetLastError()); break; } } return 0; }
Forums:
전에 어떤 분도
전에 어떤 분도 유사한 문제를 가지고 고민 하셔서 답변을 드린 기억이 나는데요,
제가 알기로 MS-Windows의 rawsocket은 connectionless datagram으로 처리 됩니다.
즉, user level application에 생성한 raw socket이 TCP일 경우 network driver 에서 제대로 처리되지 못할 가능성이 있다고 생각되네요... 테스트를 해 본 것은 아닙니다.
하지만, 예를들어 Transport layer 하단에 존재하는 network driver에서는 그 상위 레벨 스택에서 보내는 패킷 구조를 보고 "어라? 이건 ip 이하 레벨에 바인드 한건데 tcp라니? 나를 건너 뛰고 직접 세션 관리를 하겠다는 것인가?, 내가 뭘 어쩌면 되는 것인지 프로그램되어 있지 않네... 무섭다 그냥 drop시키자" 할 수도 있다는 것이죠..
테스트 해보지 않고 답변 드려 죄송합니다. (_ _)
그리고 이와는 별도로 패킷캡쳐 프로그램 구조상 패킷 캡쳐가 안되는 경우도 있습니다. Windows에는 Intercept 할 수 있는 layer 가 많이 있습니다. LSP 라는 dll 기반의 서비스 프로바이더, TPI 레벨 드라이버, IP 레벨 intermediate 드라이버, 그리고 minport driver, 또 제가 모르는 어떤 프레임워크가 있을지도 모릅니다.
아무튼 WinShark 가 사용하는 WinPcap의 경우 IP 레벨 intermediate 드라이버가 사용될 것인데, 이 intermediate 드라이버도 여러 순서에 의해 layering을 할 수 가 있습니다. 아마도 최신버전의 winpcap은 스택상의 상위 레벨에 들어가게 되어, 예를 들어 VPN 등의 경우 암호화 처리가 이미 되어 버린 상태의 결과 밖에 못보게 됩니다.
즉, 제대로 패킷이 전송된다 하더라도, rawsocket이 winpcap이 모니터 가능한 아래 레벨에 바인딩 되서 전송되는 것이라면 보지 못할 가능성도 충분하다는 것이죠.
제대로 확인 해 보시려면, dummy hub 에 다른 컴퓨터를 연결해서 그 다른 컴퓨터에서 패킷을 잡아보시면 되겠습니다.
저도 결과가 궁금하니 꼭 후기를 올려주시면 고맙겠습니다.......
-------------------------------------------------
$yes 4 8 15 16 23 42
-------------------------------------------------
$yes 4 8 15 16 23 42
답변감사합니다. 확인해 보니 와이어샤크 어뎁터를 잘못 지정해서;;
확인해 보니 어뎀터를 잘못지정해서 나타난 현상이었습니다. codeproject 사이트 소스는 정상적으로 syn 패킷을 전달 하더군요
근데 한가지,,
win2k에서는 되는데 xp에서는 안되던데 xp(sp2) 부터는 tcp data는 rawsock이 안된다고 msdn에 나와 있는데 혹시 xp에서도
rawsocket을 사용할수 있는 방법이 있는지요?
예로 레지스터리를 수정한다던가 하는 방법으로,,
앗 그것은 제가
앗 그것은 제가 경험해보지 못한 것이네요.
저도 인터넷을 찾아 보는 수 밖에 없을 것 같습니다. 혹시 나중에 알게 되면 댓글 드리겠습니다.
-------------------------------------------------
$yes 4 8 15 16 23 42
-------------------------------------------------
$yes 4 8 15 16 23 42
잠시 찾아보니
여러 솔루션이 있던것 같군요.
http://forums.techguy.org/networking/524127-solved-need-enable-raw-socket.html
이 외에도 다양한 방법이 있는것 같습니다. 한번 시간을 내보셔서 찾아보시면 더 좋을 듯 합니다.
어떤 프로그램을 배포하실 생각이 아니시라면 XP Home을 사용하시면 될 것 같네요.
이 SP2의 제약 사항에 대해 말들이 많았군요.
http://www.interact-sw.co.uk/iangblog/2004/08/12/norawsockets
http://silverstr.ufies.org/blog/archives/000666.html
MS Windows의 절대 다수 사용자층은 자신도 모르는 사이에 zombie가 될 수 있으니까요. 개발자들에게 욕을 먹더라도...사용자층이 많은 XP가 DDOS에 사용되는 (자의적이건 Zombie화 되건)것을 막기 위한 어쩔 수 없는 선택이었을지도 모르겠습니다.
-------------------------------------------------
$yes 4 8 15 16 23 42
-------------------------------------------------
$yes 4 8 15 16 23 42
댓글 달기