利用原始套接字可以访问位于基层的传输协议。原始套接字向程序员提供了读写IP/ICMP/IGMP以及构造特殊的IP报文的功能:

  1. SOCKET s; 
  2. s=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); 
  3. //或者 
  4. WSASocket(AF_INET,SOCK_RAW,IPPROTO_TCMP,NULL,0,WSA_FLAG_OVERLAPPED); 

一般情况下,原始套接字不调用bind和connect函数。

 

Ping程序:

  1. #include<stdio.h> 
  2. #include<winsock2.h> 
  3. #include<ws2tcpip.h> 
  4. #include<process.h> 
  5. #pragma comment(lib,"ws2_32.lib") 
  6.  
  7. typedef struct iphdr 
  8.     unsigned char ver_hlen;//4位IPv4版本的4位头长度(用32位字表示) 
  9.     unsigned char tos;//服务的IP类型 
  10.     unsigned short total_len;//总长 
  11.     unsigned short ident;//唯一标识符 
  12.     unsigned short frag_and_flags;//片段偏移字段 
  13.     unsigned char ttl;//生存时间 
  14.     unsigned char proto;//协议 
  15.     unsigned short checksum;//IP校验和 
  16.     unsigned int sourceIP;//源地址 
  17.     unsigned int destIP;//目的地址 
  18.  
  19. }IPHeader; 
  20.  
  21. typedef struct icmphdr 
  22.     unsigned char type; 
  23.     unsigned char code; 
  24.     unsigned short cksum; 
  25.     unsigned short id; 
  26.     unsigned short seq; 
  27. }ICMPHeader; 
  28.  
  29. #define ICMP_ECHO_REPLY    0 
  30. #define ICMP_ECHO_REQUEST  8 
  31.  
  32. #define PACKAGE_SIZE sizeof(IPHeader)+sizeof(ICMPHeader) 
  33.  
  34. #define xmalloc(s)  HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) 
  35. #define xfree(p)    HeapFree(GetProcessHeap(),0,(p)) 
  36.  
  37. void usage(); 
  38. void HandleError(char *); 
  39. void FillPackage(char *, unsigned long, u_short); 
  40. USHORT CheckSum(USHORT*, int); 
  41.  
  42. int main(int argc,char *argv[]) 
  43.     unsigned long dstIP; 
  44.     BOOL bBroadcast = FALSE; 
  45.     if(argc==2) 
  46.     { 
  47.         dstIP=inet_addr(argv[1]); 
  48.         if(dstIP==INADDR_NONE) 
  49.         { 
  50.             usage(); 
  51.             return -1; 
  52.         } 
  53.     } 
  54.     else if(argc==3) 
  55.     { 
  56.         if(strcmp(argv[1],"-b")!=0) 
  57.         { 
  58.             usage(); 
  59.             return -1; 
  60.         } 
  61.     } 
  62.     else 
  63.     { 
  64.         usage(); 
  65.         return -1; 
  66.     } 
  67.  
  68.     int pid = _getpid(); 
  69.  
  70.     WSAData wsaData; 
  71.     WSAStartup(/*MAKEWORD(2,2)*/WINSOCK_VERSION, &wsaData); 
  72.     SOCKET sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); 
  73.     if(INVALID_SOCKET==sock) 
  74.     { 
  75.         HandleError("socket"); 
  76.         WSACleanup(); 
  77.         return -1; 
  78.     } 
  79.  
  80.     BOOL on = TRUE; 
  81.     if(SOCKET_ERROR==setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&on,sizeof(on))) 
  82.     { 
  83.         HandleError("setsockopt"); 
  84.         WSACleanup(); 
  85.         return -1; 
  86.     } 
  87.  
  88.     SOCKADDR_IN to,from; 
  89.     memset(&to,0,sizeof(to)); 
  90.     to.sin_family=AF_INET; 
  91.     to.sin_addr.s_addr=dstIP; 
  92.     int len = sizeof(to); 
  93.  
  94.     char *buf = (char*)xmalloc(PACKAGE_SIZE); 
  95.     struct timeval tv; 
  96.     fd_set readSet; 
  97.  
  98.     BOOL bError = FALSE; 
  99.     for(int i=0;i<30&&!bError;i++) 
  100.     { 
  101.         printf("ping %s...%d\n",inet_ntoa(to.sin_addr),i+1); 
  102.         FillPackage(buf,dstIP,(u_short)pid); 
  103.         if(SOCKET_ERROR==sendto(sock,buf,PACKAGE_SIZE,0,(SOCKADDR*)&to,len)) 
  104.         { 
  105.             HandleError("sendto"); 
  106.             break
  107.         } 
  108.         while(TRUE) 
  109.         { 
  110.             tv.tv_sec=3; 
  111.             tv.tv_usec=0; 
  112.             FD_ZERO(&readSet); 
  113.             FD_SET(sock,&readSet); 
  114.  
  115.             int res=select(sock+1,&readSet,NULL,NULL,&tv); 
  116.             if(SOCKET_ERROR==res) 
  117.             { 
  118.                 HandleError("select"); 
  119.                 bError = TRUE; 
  120.                 break
  121.             } 
  122.             if(0==res) 
  123.             { 
  124.                 //printf("Error:%d\n",WSAGetLastError()); 
  125.                 if(!bBroadcast) 
  126.                     printf("time out!\n"); 
  127.                 break
  128.             } 
  129.             if(FD_ISSET(sock,&readSet)) 
  130.             { 
  131.                 memset(buf,0,PACKAGE_SIZE); 
  132.                 memset(&from,0,sizeof(from)); 
  133.                 len=sizeof(from); 
  134.                 if(SOCKET_ERROR==recvfrom(sock,buf,PACKAGE_SIZE,0,(SOCKADDR*)&from,&len)) 
  135.                 { 
  136.                     HandleError("recvfrom"); 
  137.                     bError=TRUE; 
  138.                     break
  139.                 } 
  140.                 IPHeader *pIPHdr = (IPHeader*)buf; 
  141.                 ICMPHeader *pICMPHdr = (ICMPHeader*)(buf+sizeof(IPHeader)); 
  142.                 if(pICMPHdr->id==htons((u_short)pid) 
  143.                     &&pICMPHdr->seq==htons((u_short)pid) 
  144.                     &&pICMPHdr->type==ICMP_ECHO_REPLY) 
  145.                 { 
  146.                     printf("Echo Reply From %s.\n",inet_ntoa(from.sin_addr)); 
  147.                     if(!bBroadcast) 
  148.                         break
  149.                 } 
  150.             } 
  151.         } 
  152.     } 
  153.     xfree(buf); 
  154.     closesocket(sock); 
  155.     WSACleanup(); 
  156.  
  157.     system("pause"); 
  158.     return 0; 
  159.  
  160. void FillPackage(char * pData, unsigned long dstIP, u_short id) 
  161.     memset(pData,0,PACKAGE_SIZE); 
  162.     IPHeader *pIPHeader = (IPHeader*)pData; 
  163.     int nVersion = 4; 
  164.     int nHeadSize = sizeof(IPHeader)/4; 
  165.     unsigned long srcIP = inet_addr("192.168.1.222");//183.211.29.69 
  166.     unsigned long destIp = dstIP; 
  167.      
  168.     pIPHeader->ver_hlen=(nVersion<<4)|nHeadSize; 
  169.     pIPHeader->tos=0; 
  170.     pIPHeader->total_len=htons(PACKAGE_SIZE); 
  171.     pIPHeader->ident=htons(1234); 
  172.     pIPHeader->frag_and_flags=0; 
  173.     pIPHeader->ttl=255; 
  174.     pIPHeader->proto=IPPROTO_ICMP; 
  175.     pIPHeader->checksum=0; 
  176.     pIPHeader->sourceIP=srcIP; 
  177.     pIPHeader->destIP=destIp; 
  178.  
  179.     pIPHeader->checksum = CheckSum((USHORT*)pData,sizeof(IPHeader)); 
  180.  
  181.     ICMPHeader* pICMPHeader = (ICMPHeader*)(pData+sizeof(IPHeader)); 
  182.     pICMPHeader->type=ICMP_ECHO_REQUEST; 
  183.     pICMPHeader->code=0; 
  184.     pICMPHeader->cksum=0; 
  185.     pICMPHeader->id=htons(id); 
  186.     pICMPHeader->seq=htons(id); 
  187.     pICMPHeader->cksum=CheckSum((USHORT*)((char*)pData+sizeof(IPHeader)),sizeof(ICMPHeader)); 
  188.  
  189. USHORT CheckSum(USHORT* pUShort, int size) 
  190.     unsigned long cksum = 0; 
  191.  
  192.     while(size>1) 
  193.     { 
  194.         cksum += *pUShort++; 
  195.         size -= sizeof(USHORT); 
  196.     } 
  197.     if(size) 
  198.     { 
  199.         cksum += *(UCHAR*)pUShort; 
  200.     } 
  201.     cksum = (cksum>>16) + (cksum& 0xffff); 
  202.     cksum += (cksum>>16); 
  203.  
  204.     return (USHORT)(~cksum); 
  205.  
  206. void usage() 
  207.     printf("usage:ping [-b] hostIP\n"); 
  208.     printf("notes:如果ping广播地址必须加上-b,否则无法得到完整输出.\n"); 
  209.  
  210. void HandleError(char *cfun) 
  211.     int errCode = WSAGetLastError(); 
  212.     char info[65] = {0}; 
  213.     _snprintf(info,64,"%s:  %d\n",cfun, errCode); 
  214.     printf(info);