简单的活动主机检测问题

来源:互联网 发布:天地诸神翅膀数据 编辑:程序博客网 时间:2024/06/07 09:57
#include<iostream>
#include<queue>
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"ipHlpApi.lib")
#pragma comment(lib,"wsock32.lib")


using namespace std;
char StartIp[20],EndIp[20];


//从命令行读取命令,加以分析
void AnalyCmd(int arg,char **str){
    if(arg != 2){
        cout<<"请输入正确的网段"<<endl;
        exit(0);
    }
    //用0来填充内存中的区域
    ZeroMemory(StartIp,20);
    ZeroMemory(EndIp,20);


    char ch = '-';
    //查找ch出现的位置,返回出现字符的相关指针
    char *pdest = strchr(str[1],ch);
    int index = pdest-str[1]+1;


    //提取相关IP地址
    strncpy(StartIp,str[1],index-1);
    strncpy(EndIp,str[1]+index,strlen(str[1]) - index);
}


//扫描目的主机是否存活,使用SendARP函数
/*
   SendARP(
    IPAddr DestIP,      IP地址的网络字节顺序
    IPAddr SrcIP,       填0
    PULONG pMacAddr,    MAc缓冲区指针
    PULONG PhyAddrLen   指向一个DWORD型数值为6的指针
    );


    返回值为访问结果
*/


int Arp_ScanHoststate(char *ip){
    IPAddr DestIp  = inet_addr(ip);//将ip地址转换为网络字节序


    ULONG pMacAddr[2];//将mac地址设为广播地址
    memset(pMacAddr,0xff,sizeof(pMacAddr));


    ULONG PhyAddrLen = 6;


    HRESULT result = SendARP(DestIp,0,pMacAddr,&PhyAddrLen);


    if(result == NO_ERROR){//正确返回


        char strMacAddr[100]={0};


        unsigned char* mac_addr = (unsigned char*)pMacAddr;//返回的远端主机的MAC地址是一个无符号的长整型数组


        sprintf(strMacAddr,"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);


        printf("主机%s 响应!  MAC地址:%s\n",ip, strMacAddr);


        return 1;


    }


    printf("主机%s 无响应!\n",ip);


    return 0;
}




//需要目的主机在80,端口进行监听才可以获得主机存活信息
int Tcp_ScanHoststate(char *ip){


    //初始化WSAStartup()函数
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data;


    if(WSAStartup(sockVersion, &data) != 0){
         return 0;
    }


    SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);//创建socket


    if(sock == INVALID_SOCKET){
        printf("socket error !");
        return 0;
    }


    //cout<<"++++++++++++++++++++++++++++++"<<endl;


    sockaddr_in sin;
    sin.sin_family = AF_INET ;
    sin.sin_port = htons(80);
    sin.sin_addr.S_un.S_addr = inet_addr(ip);


    if(connect(sock, (sockaddr *)&sin, sizeof(sin)) == 0){
     //
        printf("主机%s 响应! ,主机存活\n",ip);
        return 1;


    }else{
        printf("主机%s 无响应! ,主机不存活\n",ip);
    }


    return 0;
}




//定义ICMP首部
typedef struct icmp_hdr{
    unsigned char   icmp_type;   // 消息类型


    unsigned char   icmp_code;   // 代码


    unsigned short icmp_checksum; // 校验和


    unsigned short icmp_id;   // 用来惟一标识此请求的ID号,通常设置为进程ID


    unsigned short icmp_sequence; // 序列号


    unsigned long   icmp_timestamp; // 时间戳


} ICMP_HDR, *PICMP_HDR;


//校验和
USHORT checksum(USHORT* buff, int size)
{
    unsigned long cksum = 0;
    while(size>1)
    {
        cksum += *buff++;
        size -= sizeof(USHORT);
    }
    // 是奇数
    if(size)
    {
        cksum += *(UCHAR*)buff;
    }
    // 将32位的chsum高16位和低16位相加,然后取反
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);    // ???
    return (USHORT)(~cksum);
}




USHORT nSeq=0;//序列号
int Icmp_ScanHoststate(char *ip){


    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data;


    if(WSAStartup(sockVersion, &data) != 0){
        printf("WSAStartup error !");
        return 0;
    }


    SOCKET sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP );//创建socket


    if(sock == INVALID_SOCKET){
        printf("socket error !");
        return 0;
    }


    sockaddr_in sin;
    sin.sin_family = AF_INET ;
    sin.sin_port = htons(0);//ICMP为网络层协议,没有端口号
    sin.sin_addr.S_un.S_addr = inet_addr(ip);
    //创建ICMP数据报
    char buff[sizeof(ICMP_HDR)+32];
    ICMP_HDR * pIcmp=(ICMP_HDR *)buff;
    //初始化ICMP数据报
    pIcmp->icmp_type=8;
    pIcmp->icmp_code=0;
    pIcmp->icmp_id=(USHORT)::GetCurrentProcessId();
    pIcmp->icmp_checksum=0;
    pIcmp->icmp_sequence=0;
    memset(&buff[sizeof(ICMP_HDR)],'E',32);


    //填充ICMP包
    pIcmp->icmp_checksum=0;
    pIcmp->icmp_timestamp=::GetTickCount();
    pIcmp->icmp_sequence=nSeq++;
    pIcmp->icmp_checksum=checksum((USHORT *)buff,sizeof(ICMP_HDR)+32);


    //buff表示数据缓冲区的地址
    int nRet=sendto(sock,buff,sizeof(ICMP_HDR)+32,0,(SOCKADDR *)&sin,sizeof(sin));
   // int iRet = sendto(m_socket , (const char *) lpBuffer, dwSize, 0, (SOCKADDR *)&sin, sizeof(sin));


    if(nRet==SOCKET_ERROR){
        printf("sendto() failed:%d\n",::WSAGetLastError());
        return 0;
    }
//akrshm
    char revBuf[1024];
    sockaddr_in from;
    int nLen=sizeof(from);


    //设置为非阻塞模式
    int iMode = 1; //0:阻塞
    ioctlsocket(sock,FIONBIO, (u_long FAR*) &iMode);//非阻塞设置


    nRet=recvfrom(sock,revBuf,1024,0,(sockaddr *)&from,&nLen);


    if (nRet >-1){
            printf("%s 主机存活!\n",ip);
             WSACleanup();
            return 1;
    }else{
        printf("%s 主机没有存活!\n",ip);
         WSACleanup();
        return 0;
    }
     WSACleanup();


    return 0;


}






int main(int argc, char *argv[]){


    AnalyCmd(argc,argv);


    struct   in_addr  targetaddr; //目标机地址结构 \


    unsigned long ips=inet_addr(StartIp); //计算起始IP地址的网络字节
    unsigned long ipe=inet_addr(EndIp); //计算结束IP地址的网络字节


    ips=ntohl(ips);//计算起始IP地址的主机字节 转换为主机字节
    ipe=ntohl(ipe);//计算结束IP地址的主机字节




    DWORD dwStart = GetTickCount();//记录开始时间


    //开始循环探测主机
    for(unsigned long k=ips;k<=ipe;k++){
        targetaddr.S_un.S_addr=htonl(k);//转换为网络字节
        cout<<"------------------------------------------------"<<endl;
        Arp_ScanHoststate(inet_ntoa(targetaddr));//探测指定主机是否存活
        Tcp_ScanHoststate(inet_ntoa(targetaddr));
        Icmp_ScanHoststate(inet_ntoa(targetaddr));
    }
    printf("探测消耗时间:%d ms",GetTickCount()-dwStart);
    return 0;
}


//>demo.exe  192.168.23.1-192.168.23.5