利用原始套接字可以访问位于基层的传输协议。原始套接字向程序员提供了读写IP/ICMP/IGMP以及构造特殊的IP报文的功能:
- SOCKET s;
- s=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
- //或者
- WSASocket(AF_INET,SOCK_RAW,IPPROTO_TCMP,NULL,0,WSA_FLAG_OVERLAPPED);
一般情况下,原始套接字不调用bind和connect函数。
Ping程序:
- #include<stdio.h>
- #include<winsock2.h>
- #include<ws2tcpip.h>
- #include<process.h>
- #pragma comment(lib,"ws2_32.lib")
- typedef struct iphdr
- {
- unsigned char ver_hlen;//4位IPv4版本的4位头长度(用32位字表示)
- unsigned char tos;//服务的IP类型
- unsigned short total_len;//总长
- unsigned short ident;//唯一标识符
- unsigned short frag_and_flags;//片段偏移字段
- unsigned char ttl;//生存时间
- unsigned char proto;//协议
- unsigned short checksum;//IP校验和
- unsigned int sourceIP;//源地址
- unsigned int destIP;//目的地址
- }IPHeader;
- typedef struct icmphdr
- {
- unsigned char type;
- unsigned char code;
- unsigned short cksum;
- unsigned short id;
- unsigned short seq;
- }ICMPHeader;
- #define ICMP_ECHO_REPLY 0
- #define ICMP_ECHO_REQUEST 8
- #define PACKAGE_SIZE sizeof(IPHeader)+sizeof(ICMPHeader)
- #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
- #define xfree(p) HeapFree(GetProcessHeap(),0,(p))
- void usage();
- void HandleError(char *);
- void FillPackage(char *, unsigned long, u_short);
- USHORT CheckSum(USHORT*, int);
- int main(int argc,char *argv[])
- {
- unsigned long dstIP;
- BOOL bBroadcast = FALSE;
- if(argc==2)
- {
- dstIP=inet_addr(argv[1]);
- if(dstIP==INADDR_NONE)
- {
- usage();
- return -1;
- }
- }
- else if(argc==3)
- {
- if(strcmp(argv[1],"-b")!=0)
- {
- usage();
- return -1;
- }
- }
- else
- {
- usage();
- return -1;
- }
- int pid = _getpid();
- WSAData wsaData;
- WSAStartup(/*MAKEWORD(2,2)*/WINSOCK_VERSION, &wsaData);
- SOCKET sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
- if(INVALID_SOCKET==sock)
- {
- HandleError("socket");
- WSACleanup();
- return -1;
- }
- BOOL on = TRUE;
- if(SOCKET_ERROR==setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&on,sizeof(on)))
- {
- HandleError("setsockopt");
- WSACleanup();
- return -1;
- }
- SOCKADDR_IN to,from;
- memset(&to,0,sizeof(to));
- to.sin_family=AF_INET;
- to.sin_addr.s_addr=dstIP;
- int len = sizeof(to);
- char *buf = (char*)xmalloc(PACKAGE_SIZE);
- struct timeval tv;
- fd_set readSet;
- BOOL bError = FALSE;
- for(int i=0;i<30&&!bError;i++)
- {
- printf("ping %s...%d\n",inet_ntoa(to.sin_addr),i+1);
- FillPackage(buf,dstIP,(u_short)pid);
- if(SOCKET_ERROR==sendto(sock,buf,PACKAGE_SIZE,0,(SOCKADDR*)&to,len))
- {
- HandleError("sendto");
- break;
- }
- while(TRUE)
- {
- tv.tv_sec=3;
- tv.tv_usec=0;
- FD_ZERO(&readSet);
- FD_SET(sock,&readSet);
- int res=select(sock+1,&readSet,NULL,NULL,&tv);
- if(SOCKET_ERROR==res)
- {
- HandleError("select");
- bError = TRUE;
- break;
- }
- if(0==res)
- {
- //printf("Error:%d\n",WSAGetLastError());
- if(!bBroadcast)
- printf("time out!\n");
- break;
- }
- if(FD_ISSET(sock,&readSet))
- {
- memset(buf,0,PACKAGE_SIZE);
- memset(&from,0,sizeof(from));
- len=sizeof(from);
- if(SOCKET_ERROR==recvfrom(sock,buf,PACKAGE_SIZE,0,(SOCKADDR*)&from,&len))
- {
- HandleError("recvfrom");
- bError=TRUE;
- break;
- }
- IPHeader *pIPHdr = (IPHeader*)buf;
- ICMPHeader *pICMPHdr = (ICMPHeader*)(buf+sizeof(IPHeader));
- if(pICMPHdr->id==htons((u_short)pid)
- &&pICMPHdr->seq==htons((u_short)pid)
- &&pICMPHdr->type==ICMP_ECHO_REPLY)
- {
- printf("Echo Reply From %s.\n",inet_ntoa(from.sin_addr));
- if(!bBroadcast)
- break;
- }
- }
- }
- }
- xfree(buf);
- closesocket(sock);
- WSACleanup();
- system("pause");
- return 0;
- }
- void FillPackage(char * pData, unsigned long dstIP, u_short id)
- {
- memset(pData,0,PACKAGE_SIZE);
- IPHeader *pIPHeader = (IPHeader*)pData;
- int nVersion = 4;
- int nHeadSize = sizeof(IPHeader)/4;
- unsigned long srcIP = inet_addr("192.168.1.222");//183.211.29.69
- unsigned long destIp = dstIP;
- pIPHeader->ver_hlen=(nVersion<<4)|nHeadSize;
- pIPHeader->tos=0;
- pIPHeader->total_len=htons(PACKAGE_SIZE);
- pIPHeader->ident=htons(1234);
- pIPHeader->frag_and_flags=0;
- pIPHeader->ttl=255;
- pIPHeader->proto=IPPROTO_ICMP;
- pIPHeader->checksum=0;
- pIPHeader->sourceIP=srcIP;
- pIPHeader->destIP=destIp;
- pIPHeader->checksum = CheckSum((USHORT*)pData,sizeof(IPHeader));
- ICMPHeader* pICMPHeader = (ICMPHeader*)(pData+sizeof(IPHeader));
- pICMPHeader->type=ICMP_ECHO_REQUEST;
- pICMPHeader->code=0;
- pICMPHeader->cksum=0;
- pICMPHeader->id=htons(id);
- pICMPHeader->seq=htons(id);
- pICMPHeader->cksum=CheckSum((USHORT*)((char*)pData+sizeof(IPHeader)),sizeof(ICMPHeader));
- }
- USHORT CheckSum(USHORT* pUShort, int size)
- {
- unsigned long cksum = 0;
- while(size>1)
- {
- cksum += *pUShort++;
- size -= sizeof(USHORT);
- }
- if(size)
- {
- cksum += *(UCHAR*)pUShort;
- }
- cksum = (cksum>>16) + (cksum& 0xffff);
- cksum += (cksum>>16);
- return (USHORT)(~cksum);
- }
- void usage()
- {
- printf("usage:ping [-b] hostIP\n");
- printf("notes:如果ping广播地址必须加上-b,否则无法得到完整输出.\n");
- }
- void HandleError(char *cfun)
- {
- int errCode = WSAGetLastError();
- char info[65] = {0};
- _snprintf(info,64,"%s: %d\n",cfun, errCode);
- printf(info);
- }