1实验:ICMP协议的分析与实现[实验目的]分析ICMP报文,理解ICMP协议在Internet网中的具体应用及其实现原理,深入了解TCP/IP网络的容错控制;学会运用网络套接字Winsock开发网络通信程序。[实验内容]使用VisualStudioC++6.0和网络接口套接字Socket进行Windows环境下的网络编程,运用原始嵌套字RAW_SOCKET从IP层开始构造整个ICMP报文,通过ICMP协议所提供的回送请求(echorequest)和回送应答(echoreply)这两种报文实现检测目的站的可达性与状态。1.IP报头、ICMP报文的基本描述IP协议并不能保证绝对的可靠,所以就设计了ICMP协议,进行差错报告.ICMP消息使用IP头作为基本控制.IP头的格式如下:012301234567890123456789012345678901+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Version|IHL|TypeofService|TotalLength|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Identification|Flags|FragmentOffset|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|TimetoLive|Protocol|HeaderChecksum|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|SourceAddress|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|DestinationAddress|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Version=4IHLInternet头长TypeofService=0TotalLengthIP包的总长度Identification,Flags,FragmentOffset用于IP包分段TimetoLiveIP包的存活时长ProtocolICMP=1HeaderChecksum头校验和(检查整个IP报头)Addresses发送Echo消息的源地址是发送Echoreply消息的目的地址,相反,发送Echo消息的目的地址是发送Echoreply消息的源地址.2Echo或EchoReply消息格式如下:012301234567890123456789012345678901+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Type|Code|Checksum|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Identifier|SequenceNumber|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Data|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Typeecho消息的类型为8echoreply的消息类型为0.Code=0Checksum为从TYPE开始到IP包结束的校验和,也就是校验整个ICMP报文Identifier如果code=0,identifier用来匹配echo和echoreply消息SequenceNumber如果code=0,identifier用来匹配echo和echoreply消息功能描述:收到echo消息必须回应echoreply消息.identifier和sequencenumber可能被发送echo的主机用来匹配返回的echoreply消息.例如:identifier可能用于类似于TCP或UDP的port用来标示一个会话,而sequencenumber会在每次发送echo请求后递增.收到echo的主机或路由器返回同一个值与之匹配2数据结构(1)IP报头格式//定义IP首部typedefstruct_iphdr{unsignedcharh_lenver;//4位IP版本号+4位首部长度unsignedchartos;//8位服务类型TOSunsignedshorttotal_len;//16位IP包总长度(字节)unsignedshortident;//16位标识,用于辅助IP包的拆装,本实验不用,置零unsignedshortfrag_and_flags;//3位标志位+13位偏移位,也是用于IP包的拆装,本实验不用,置零unsignedcharttl;//8位IP包生存时间TTLunsignedcharproto;//8位协议(TCP,UDP或其他),本实验置ICMP,置为1unsignedshortchecksum;//16位IP首部校验和,最初置零,等所有包头都填写正确后,计算并替换.unsignedintsourceIP;//32位源IP地址unsignedintdestIP;//32位目的IP地址}IP_HEADER;(2)ICMP报头格式//定义ICMP首部3typedefstruct_icmphdr{unsignedchari_type;//8位类型,本实验用8:ECHO0:ECHOREPLYunsignedchari_code;//8位代码,本实验置零unsignedshorti_cksum;//16位校验和,从TYPE开始,直到最后一位用户数据,如果为字节数为奇数则补充一位unsignedshorti_id;//识别号(一般用进程号作为识别号),用于匹配ECHO和ECHOREPLY包unsignedshorti_seq;//报文序列号,用于标记ECHO报文顺序unsignedinttimestamp;//时间戳}ICMP_HEADER;3总体设计ICMP协议中的发送、接收ICMP回送请求报文,回送应答报文流程图。数据包太短?不是回送响?应?ID不符合?输出数据报中的IP地址填充ICMP数据报发送数据报接受数据报去掉IP报头,获取ICMP信息结束yyyNNN开始44.VC中网络套接字Winsock编程基础在VC中进行WINSOCK的API编程开发的时候,需要在项目中使用下面三个文件,否则会出现编译错误。1.WINSOCK.H:这是WINSOCKAPI的头文件,需要包含在项目中。2.WSOCK32.LIB:WINSOCKAPI连接库文件。在使用中,一定要把它作为项目的非缺省的连接库包含到项目文件中去。3.WINSOCK.DLL:WINSOCK的动态连接库,位于WINDOWS的安装目录下。几个基本的套接字:1、创建套接字——socket()功能:使用前创建一个新的套接字格式:SOCKETPASCALFARsocket(intaf,inttype,intprocotol);参数:af:通信发生的区域type:要建立的套接字类型procotol:使用的特定协议2、指定本地地址——bind()功能:将套接字地址与所创建的套接字号联系起来。格式:intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);参数:s:是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。其它:没有错误,bind()返回0,否则SOCKET_ERROR地址结构说明:structsockaddr_in{shortsin_family;//AF_INETu_shortsin_port;//16位端口号,网络字节顺序structin_addrsin_addr;//32位IP地址,网络字节顺序charsin_zero[8];//保留}3建立套接字连接——connect()和accept()功能:共同完成连接工作格式:intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*name,intFAR*addrlen);参数:同上4、监听连接——listen()功能:用于面向连接服务器,表明它愿意接收连接。格式:intPASCALFARlisten(SOCKETs,intbacklog);5、数据传输——send()与recv()5功能:数据的发送与接收格式:intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags);intPASCALFARrecv(SOCKETs,constcharFAR*buf,intlen,intflags);参数:buf:指向存有传输数据的缓冲区的指针。6、多路复用——select()功能:用来检测一个或多个套接字状态。格式:intPASCALFARselect(intnfds,fd_setFAR*readfds,fd_setFAR*writefds,fd_setFAR*exceptfds,conststructtimevalFAR*timeout);参数:readfds:指向要做读检测的指针writefds:指向要做写检测的指针exceptfds:指向要检测是否出错的指针timeout:最大等待时间7、关闭套接字——closesocket()功能:关闭套接字s格式:BOOLPASCALFARclosesocket(SOCKETs);5部分程序代码//初始化SOCKETWSADATAwsaData;iErrorCode=WSAStartup(MAKEWORD(2,2),&wsaData);CheckSockError(iErrorCode,WSAStartup);sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//原始套接字CheckSockError(sockRaw,socket);//设置超时时间timeout=time;iErrorCode=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));//设置接受延时CheckSockError(iErrorCode,SO_RCVTIMEO);timeout=time;iErrorCode=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));//设置发送延时CheckSockError(iErrorCode,SO_SNDTIMEO);6//获得目标主机IPmemset(&dest,0,sizeof(dest));//初始化dest结构dest.sin_family=AF_INET;//填充SOCKADDR_IN结构内容if((dest.sin_addr.s_addr=inet_addr(lpdest))==INADDR_NONE){if((hp=gethostbyname(lpdest))!=NULL)//目的主机名字不为空{memcpy(&(dest.sin_addr),hp-h_addr_list[0],hp-h_length);dest.sin_family=hp-h_addrtype;printf(dest.sin_addr=%s\n,inet_