使用套接字实现ICMP协议

来源:互联网 发布:js给json对象添加属性 编辑:程序博客网 时间:2024/05/29 10:55

//ip协议 结构头部定义


#pragma once#include "stdafx.h"#ifdef  USING_IP_HEADERtypedef struct   _ipheader{  #if LITTLE_ENDIAN  unsigned char ihl:4;     //首部长度  unsigned char version:4; //版本   #else  unsigned char version:4 ;//版本  unsigned char ihl:4 ;    //首部长度  #endif  unsigned char tos;       //服务类型  unsigned short tot_len;  //总长度  unsigned short id;       //标志  unsigned short frag_off; //分片偏移  unsigned char ttl;       //生存时间  unsigned char protocol;  //协议  unsigned short chk_sum;  //检验和  //struct in_addr src_addr;  //源IP地址   /*unsigned int srcaddr;/*减少导入库,需要在引用的地方 转换为in_addr*/  //struct in_addr dest_addr;  //目的IP地址   /*unsigned int destaddr;/*减少导入库,需要在引用的地方 转换为in_addr*/    unsigned long src_addr;    unsigned long dest_addr;}IP_HEADER,*PIP_HEADER;#endif //USING_IP_HEADER#ifdef USING_IP_ICMP_HEADER//ICMP 结构头typedef struct _icmp_header{/*类型*/unsigned char icmp_type;/*代码*/unsigned char icmp_code;/*校检和*/unsigned short icmp_checksum;/*标识符,一般以进程号作为标识*/unsigned short icmp_id;/*序列号*/unsigned short icmp_seq;    /*时间戳*/unsigned long  icmp_timestamp;}ICMP_HEADER,*PICMP_HEADER;

//ICMP 协议函数定义 头文件

 //解析ICMP协议包数据  BOOL __stdcall Nw_ParseIcmp4PacketData(  /*ICMP协议数据包*/  __in void* pIcmpData,  /*pIcmpData的长度,长度必须匹配pIcmpData,否则导致内存访问越界*/  __in size_t IcmpDataLen,  /*ip结构*/  /*#ifdef USING_IP_HEADER  __out_opt IP_HEADER* pIpHdr,#else*/  __out_opt void** ppIpHdr,//#endif  /*icmp结构*//*#ifdef USING_IP_ICMP_HEADER  __out_opt ICMP_HEADER* pIcmpHdr,#else*/  __out_opt void** ppIcmphdr,//#endif  /*包含的数据*/  __out_opt void** ppData,  /*pData的数据长度*/  __out_opt size_t* pDataReturnLen  );//目标地址是否可使用ICMP协议到达并返回,是ping程序的简易版  //一个调用作为一个调用例程,可结合多线程使用 作为网络扫描,基于主机地址而非端口  //也可用用于使用ICMP发送数据  //可用这个函数获取本机 宽带通信的IP(用于外网通信的,不是局域网),在网络不好的情况下无法得到正确的数据,根据返回值判断,最好是多调用几次,直到返回值为0表示调用正确  /*成功返回0*/  int __stdcall Nw_Icmp4InvokeRoutine(  /*目标地址*/  __in char*  phostname,  /*指示icmp请求允许的等待时间,为-1表示无限时间等待,函数不返回,除非目标回显请求*/  __in int itimeout,  /*指定发送到icmp类型,如为0 表示以请求回显的方式 同ping一样*/  __in unsigned short icmptype,  /*为TRUE,用户必须在psendbuffer构造ICMP结构头,为FALSE,则由函数自己构造,标识符为线程ID*/  __in BOOL bBuildIcmpPacket,  /*通过icmp携带的数据,可为NULL;是否构造ICMP结构头,根据bBuildIcmpPacket参数指定。携带数据的长度加上ip协议结构头的和不能超过0xFFFF,超出部分被截断*/  __in void* psendbuffer,  /*psendbuffer的字节长度*/  __in size_t bufferlen ,  /*接受的数据缓存区,可为NULL;数据结构: ip协议结构头+icmp结构+数据,用户亲自处理*/  __out_opt void* precvbuffer,  /*指定precvbuffer的字节长度*/  __in size_t recvbufferlen,  /*precvbuffer实际接受的字节长度*/  __out_opt size_t* preturnrecvbufferlen  );


//源文件,代码实现


//解析ICMP协议包数据BOOL __stdcall Nw_ParseIcmp4PacketData(/*ICMP协议数据包*/__in void* pIcmpData, /*pIcmpData的长度,长度必须匹配pIcmpData,否则导致内存访问越界*/ __in size_t IcmpDataLen, /*ip结构*/ __out_opt void** ppIpHdr, /*icmp结构*/  __out_opt void** ppIcmpHdr, /*包含的数据*/  __out_opt void** ppData, /*pData的数据长度*/  __out_opt size_t* pDataReturnLen  ){if(! pIcmpData || !IcmpDataLen) return FALSE;DWORD dwroffset=sizeof(IP_HEADER);if(dwroffset>IcmpDataLen) return FALSE;if(ppIpHdr) *ppIpHdr=(PIP_HEADER)pIcmpData;dwroffset+=sizeof(ICMP_HEADER);if(dwroffset>IcmpDataLen) return FALSE;if(ppIcmpHdr)*ppIcmpHdr=(PICMP_HEADER)((DWORD)pIcmpData+sizeof(IP_HEADER));if(ppData) *ppData=(void*)((DWORD)pIcmpData+sizeof(IP_HEADER)+sizeof(ICMP_HEADER));if(pDataReturnLen) *pDataReturnLen=IcmpDataLen-dwroffset;return TRUE;}int __stdcall Nw_Icmp4InvokeRoutine( /*目标地址*/ __in char*  phostname, /*指示icmp请求允许的等待时间,为-1表示无限时间等待,函数不返回,除非目标回显请求*/ __in int itimeout, /*指定发送到icmp类型,如为0 表示以请求回显的方式 同ping一样*/ __in unsigned short icmptype, /*为TRUE,用户必须在psendbuffer构造ICMP结构头,为FALSE,则由函数自己构造,标识符为线程ID*/ __in BOOL bBuildIcmpPacket, /*通过icmp携带的数据,可为NULL;是否构造ICMP结构头,根据bBuildIcmpPacket参数指定。携带数据的长度加上ip协议结构头的和不能超过0xFFFF,超出部分被截断*/ __in void* psendbuffer, /*psendbuffer的字节长度*/ __in size_t bufferlen , /*接受的数据缓存区,可为NULL;数据结构: ip协议结构头+icmp结构+数据,用户亲自处理*/ __out_opt void* precvbuffer, /*指定precvbuffer的字节长度*/ __in size_t recvbufferlen, /*precvbuffer实际接受的字节长度*/ __out_opt size_t* preturnrecvbufferlen ) { int ierr=0; struct hostent* phost=gethostbyname(phostname); struct sockaddr_in dest_addr,src_addr; SOCKET sk_Icmp; PICMP_HEADER picmppacket=NULL;//to delete if it could int src_addr_len=sizeof(src_addr); if(!phost) { unsigned long _laddr =inet_addr(phostname); if(_laddr==INADDR_NONE) return WSAGetLastError(); dest_addr.sin_addr.s_addr=_laddr; dest_addr.sin_family=AF_INET; }else{ CopyMemory(&dest_addr.sin_addr.s_addr,phost->h_addr,phost->h_length); dest_addr.sin_family=phost->h_addrtype; } /*创建套接字*/ sk_Icmp=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED); if(sk_Icmp==INVALID_SOCKET) return INVALID_SOCKET; //设置超时 int ito= setsockopt(sk_Icmp,SOL_SOCKET,SO_RCVTIMEO,(char*)&itimeout,sizeof(int)); if(ito==SOCKET_ERROR) { closesocket(sk_Icmp); return SOCKET_ERROR; } ito= setsockopt(sk_Icmp,SOL_SOCKET,SO_SNDTIMEO,(char*)&itimeout,sizeof(int)); if(ito==SOCKET_ERROR) { closesocket(sk_Icmp); return SOCKET_ERROR; } //发送 if(psendbuffer==NULL/*用户指定发送包为NULL*/){ picmppacket = (PICMP_HEADER)HeapAlloc(GetProcessHeap(),8, sizeof(ICMP_HEADER)); if(picmppacket==NULL){ closesocket(sk_Icmp); return -2;//内存原因 } picmppacket->icmp_checksum=0; picmppacket->icmp_code=0; picmppacket->icmp_id=GetCurrentThreadId(); picmppacket->icmp_seq=1; picmppacket->icmp_timestamp=GetTickCount(); picmppacket->icmp_type=8; picmppacket->icmp_checksum=Icmp_CheckSum((USHORT*)picmppacket,sizeof(ICMP_HEADER)); ierr=sendto(sk_Icmp,(char*)picmppacket,sizeof(ICMP_HEADER),0,(struct sockaddr*)&dest_addr,sizeof(dest_addr)); if(ierr==SOCKET_ERROR){ ierr=WSAGetLastError(); closesocket(sk_Icmp); HeapFree(GetProcessHeap(),0,picmppacket); return ierr; } }/*NULL*/ else{ if(bBuildIcmpPacket/*用户亲自处理ICMP包*/){ ierr=sendto(sk_Icmp,(char*)psendbuffer,bufferlen/*大于65535会产生 IP碎片,这里不处理*/,0,(struct sockaddr*)&dest_addr,sizeof(dest_addr)); if(ierr==SOCKET_ERROR){ ierr=WSAGetLastError(); closesocket(sk_Icmp); return ierr; } }else/*函数构造ICMP结构*/{ size_t l=bufferlen+sizeof(ICMP_HEADER); picmppacket = (PICMP_HEADER) HeapAlloc(GetProcessHeap(),8,l); if(!picmppacket) { closesocket(sk_Icmp); return -2; } picmppacket->icmp_checksum=0; picmppacket->icmp_code=0; picmppacket->icmp_id=GetCurrentThreadId(); picmppacket->icmp_seq=1; picmppacket->icmp_timestamp=GetTickCount(); picmppacket->icmp_type=8; CopyMemory((LPVOID)((DWORD)picmppacket+sizeof(ICMP_HEADER)),psendbuffer,bufferlen); picmppacket->icmp_checksum=Icmp_CheckSum((USHORT*)picmppacket,l); ierr=sendto(sk_Icmp,(char*)picmppacket,l,0,(struct sockaddr*)&dest_addr,sizeof(dest_addr)); if(ierr==SOCKET_ERROR){ ierr=WSAGetLastError(); closesocket(sk_Icmp); HeapFree(GetProcessHeap(),0,picmppacket); return ierr; } } } //接收数据,注意,如果要做类似于ping的程序需要接收数据以判断目标是否可到达 if(precvbuffer){ ierr=recvfrom(sk_Icmp,(char*)precvbuffer,recvbufferlen,0,(struct sockaddr*)&src_addr,&src_addr_len); if(ierr==SOCKET_ERROR){ closesocket(sk_Icmp); if(picmppacket) HeapFree(GetProcessHeap(),0,picmppacket); return ierr; } if(preturnrecvbufferlen) *preturnrecvbufferlen=ierr; } closesocket(sk_Icmp); if(picmppacket) HeapFree(GetProcessHeap(),0,picmppacket); return 0; }



原创粉丝点击