//--------------------------------------------------------------------// // ICMP(Ping)扫描 // // Rrouned // //--------------------------------------------------------------------// #include "stdio.h" #include "Winsock2.h" #pragma comment( lib, "ws2_32.lib" ) ; typedef struct IpHeader { unsigned char Version_HLen; unsigned char TOS; unsigned short Length; unsigned short Ident; unsigned short Flags_Offset; unsigned char TTL; unsigned char Protocol; unsigned short Checksum; unsigned int SourceAddr; unsigned int DestinationAddr; } Ip_Header; //类型和代码一起决定了ICMP报文的类型 //类型8、代码0:回射请求。 //类型0、代码0:回射应答。 //类型11、代码0:超时。 //ICMP回射请求和应答报文,标识本ICMP进程 typedef struct IcmpHeader { BYTE Type; //类型 BYTE Code; //代码 USHORT Checksum;//校验和 USHORT ID; USHORT Sequence; } Icmp_Header; USHORT checksum(USHORT *buff, int size) { unsigned long cksum = 0; while (size > 1) { cksum += *buff++; size -= sizeof(USHORT); } if (size) { cksum += *(UCHAR*)(buff); } cksum = (cksum >> 16) + (cksum &0xffff); cksum += (cksum >> 16); return (USHORT)(~cksum); } int main(int argc, char *argv[]) { WSADATA wsaData; sockaddr_in DestAddr; Ip_Header *ip; Icmp_Header *icmp; Icmp_Header *SendIcmp; int Timeout = 100; char DestIpAddr[100] = "192.168.1.10"; char IcmpBuffer[8] = ""; SOCKET IcmpSocket; char RecvBuffer[1024]; sockaddr_in addr; int Len = sizeof(addr); int Result; if ((Result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { printf("WSAStartup failed with error %d ", Result); return 0; } IcmpSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (IcmpSocket == INVALID_SOCKET) { printf("socket failed with error %d ", WSAGetLastError()); return 0; } //设置超时 Result = setsockopt(IcmpSocket, SOL_SOCKET, SO_RCVTIMEO, (char*) &Timeout, sizeof(Timeout)); if (Result == SOCKET_ERROR) { printf("setsockopt failed with error %d ", WSAGetLastError()); return 0; } //构造数据包 memset(&DestAddr, 0, sizeof(DestAddr)); DestAddr.sin_addr.s_addr = inet_addr(DestIpAddr); DestAddr.sin_port = htons(0); DestAddr.sin_family = AF_INET; SendIcmp = (Icmp_Header*)IcmpBuffer; SendIcmp->Type = 8; SendIcmp->Code = 0; SendIcmp->ID = (USHORT)GetCurrentProcessId(); SendIcmp->Sequence = htons(1); SendIcmp->Checksum = 0; SendIcmp->Checksum = checksum((USHORT*)IcmpBuffer, sizeof(IcmpBuffer)); Result = sendto(IcmpSocket, IcmpBuffer, sizeof(IcmpBuffer), 0, (SOCKADDR*) &DestAddr, sizeof(DestAddr)); if (Result == SOCKET_ERROR) { printf("sendto failed with error %d ", WSAGetLastError()); return 0; } //recvform是阻塞的,一直等到数据的到达 //设置了超时之后如果在超时前没有数据到达就返回 Result = recvfrom(IcmpSocket, RecvBuffer, 1024, 0, (sockaddr*) &addr, &Len); if (Result == SOCKET_ERROR) { if (WSAGetLastError() != WSAETIMEDOUT) { printf("recvfrom failed with error %d ", WSAGetLastError()); return 0; } else { printf("Host %s may be down. ", DestIpAddr); } } if (Result < sizeof(Ip_Header) + sizeof(Icmp_Header)) { printf("data error from %d ", inet_ntoa(addr.sin_addr)); } ip = (Ip_Header*)RecvBuffer; //检查返回的数据包 //IP的目标地址,协议类型 if ((ip->SourceAddr == inet_addr(DestIpAddr)) && (ip->Protocol == IPPROTO_ICMP)) { icmp = (Icmp_Header*)(RecvBuffer + sizeof(Ip_Header)); //ICMP类型 if (icmp->Type != 0) { printf("type error %d ", icmp->Type); return 0; } //ICMP的进程ID if (icmp->ID != GetCurrentProcessId()) { printf("id error %d ", icmp->ID); return 0; } else if ((icmp->Type == 0) && (icmp->ID == GetCurrentProcessId())) { printf("Host %s is up. ", DestIpAddr); } } //收尾操作。。 if (closesocket(IcmpSocket) == SOCKET_ERROR) { printf("closesocket failed with error %d ", WSAGetLastError()); return 0; } if (WSACleanup() == SOCKET_ERROR) { printf("WSACleanup failed with error %d ", WSAGetLastError()); return 0; } return 1; }