ronnie
4.2.2 初始化ICMP首部
void InitIcmpHeader(ICMP_HDR* icmp_hdr) { char buff[sizeof(ICMP_HDR) + 32]; //ICMP报文类型,类型为8,代码为0 icmp_hdr->icmp_type = ICMP_ECHO_REQUEST_TYPE; // 请求回显 icmp_hdr->icmp_code = ICMP_ECHO_REQUEST_CODE; icmp_hdr->icmp_id = (USHORT)GetCurrentProcessId(); icmp_hdr->icmp_checksum = 0; icmp_hdr->icmp_sequence = 0; icmp_hdr->icmp_timestamp= GetTickCount(); //往ICMP头部填充信息 memset(&buff[sizeof(ICMP_HDR)], 'E', 32); }
函数为ICMP报文首部中各个字段赋值,达到初始化的目的。其中比较重要的语句有
icmp_hdr->icmp_type = ICMP_ECHO_REQUEST_TYPE; // 请求回显 icmp_hdr->icmp_code = ICMP_ECHO_REQUEST_CODE;
这样赋值后,就把ICMP报文设置成ICMP询问报文,回送请求和回答。
4.2.3地址解析
void Resolove(char hostname[]) { if(isdigit(hostname[0])) //判断主机名是否为数字 { //printf(\执行inet_addr()...\\n\ dest.sin_addr.s_addr = inet_addr(hostname); //将主机地址写入s_addr //printf(\ } else if( (host=gethostbyname(hostname)) != 0)//判断所给主机名是否与host中的一致 { //printf(\执行gethostbyname()...\\n\ strncpy((char *)&dest.sin_addr , (char *)host->h_addr_list[0] , sizeof dest.sin_addr);
//printf(\完成。\\n\ } else { printf(\解析主机失败。\\n\ exit(EXIT_FAILURE); }
16
ronnie
}
根据用户输入地址字符串转化成相应的地址字段,写入dest.sin_addr中。如果用户输入的点分十进制。则就会调用相应的inet_addr()函数,否则调用gethostbyname(),在写入地址字段。 4.2.4 计算检验和
unsigned short checksum(unsigned short *buffer, int size) { unsigned long cksum=0; while (size > 1) { cksum += *buffer++; size -= sizeof(USHORT); } if (size) { cksum += *(UCHAR*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); }
根据TCP/IP协议,IP数据报在传输过程前必须计算检验和,对收到的数据也要计算检验和。该函数实现了首部的检验和计算。 4.2.5 网段扫描 主要语句如下:
for(i = startport ; i<= endport ; i++) { sock = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP); //创建一个Socket if(sock==INVALID_SOCKET) { printf(\ exit(EXIT_FAILURE); } //主机字节序转换为网络字节序
17
ronnie
}
dest.sin_port = htons(i);
//用此Socket连接目的主机,核心代码
status = connect(sock , (struct sockaddr *)&dest , sizeof dest);
if(status == SOCKET_ERROR) //连接失败 { switch(WSAGetLastError()) { case 10060: printf(\ break; case 10061: printf(\ break; default: printf(\ break; } //fflush(stdout); }
else //连接成功 { printf(\ //关闭收发服务 if( shutdown( sock ,SD_BOTH ) == SOCKET_ERROR ) { printf(\ exit(EXIT_FAILURE); } }
closesocket(sock); //关闭Socket,回收资源 //WSACleanup();
利用一个for(;;)循环,对确定的起始和终止IP地址的内的所有可能存在的主机发送,请求回显的ICMP报文,并对返回的ICMP报文进行分析,提取出type和code字段,根据ICMP报文格式所定义的数值,对各个主机判断,并打印信息。 4.2.6 端口扫描
18
ronnie
for(i = startport ; i<= endport ; i++) { sock = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP); //创建一个Socket if(sock==INVALID_SOCKET) { printf(\ exit(EXIT_FAILURE); } //主机字节序转换为网络字节序 dest.sin_port = htons(i); //用此Socket连接目的主机,核心代码 status = connect(sock , (struct sockaddr *)&dest , sizeof dest); if(status == SOCKET_ERROR) //连接失败 { switch(WSAGetLastError()) { case 10060: printf(\ break; case 10061: printf(\ break; default: printf(\ break; } //fflush(stdout); } else //连接成功 { printf(\ //关闭收发服务 if( shutdown( sock ,SD_BOTH ) == SOCKET_ERROR ) { printf(\ exit(EXIT_FAILURE); } } closesocket(sock); //关闭Socket,回收资源 //WSACleanup(); }
19
ronnie
函数同样利用一个for(;;)循环对给定的主机的端口区间扫描。调用WSAGetLastError()库函数判断端口是否连接,根据相应的ERROR CODE判断端口的具体情况。以下是主要的ERROR CODE:
WSAETIMEDOUT 10060
Connection timed out.
A connection attempt failed because the connected party did not properly respond after a period of time, or the established connection failed because the connected host has failed to respond.
WSAECONNREFUSED 10061
Connection refused.
No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running.
WSAELOOP 10062
Cannot translate name. Cannot translate a name.
摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
五、总结与体会
5.1 程序调试与运行 程序主界面
20