ICMP(Ping)扫描

//--------------------------------------------------------------------//
//					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报文的类型
//类型八、代码0:回射请求。
//类型0、代码0:回射应答。
//类型十一、代码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\n", Result);
        return 0;
    }
    IcmpSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (IcmpSocket == INVALID_SOCKET)
    {
        printf("socket failed with error %d\n", WSAGetLastError());
        return 0;
    }
	//设置超时
    Result = setsockopt(IcmpSocket, SOL_SOCKET, SO_RCVTIMEO, (char*) &Timeout, sizeof(Timeout));
    if (Result == SOCKET_ERROR)
    {
        printf("setsockopt failed with error %d \n", 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 \n", 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 \n", WSAGetLastError());
            return 0;
        }
        else
        {
            printf("Host %s may be down.\n", DestIpAddr);
        }
    }
    if (Result < sizeof(Ip_Header) + sizeof(Icmp_Header))
    {
        printf("data error from %d\n", 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\n", icmp->ID);
            return 0;
        }
        else if ((icmp->Type == 0) && (icmp->ID == GetCurrentProcessId()))
        {
            printf("Host %s is up.\n", DestIpAddr);
        }
    }





	//收尾操做。。
    if (closesocket(IcmpSocket) == SOCKET_ERROR)
    {
        printf("closesocket failed with error %d\n", WSAGetLastError());
        return 0;
    }
    if (WSACleanup() == SOCKET_ERROR)
    {
        printf("WSACleanup failed with error %d\n", WSAGetLastError());
        return 0;
    }
    return 1;
}