ICMP,IP,UDP,TCP报头部分都有checksum(检验和)字段。ICMP和IP报头校验和的计算都很简单,使用RFC1071中给出的方法即可完成(如下)。 //计算校验和 USHORT checksum(USHORT *buffer,int size) { unsigned long cksum=0; while(size>1) { cksum+=*buffer++; size-=sizeof(USHORT); } if(size) { cksum+=*(UCHAR *)buffer; } //将32位数转换成16 while (cksum>>16) cksum=(cksum>>16)+(cksum & 0xffff); return (USHORT) (~cksum); }
UDP/TCP报头中的校验和的计算比较复杂的,要用到 UDP/TCP伪首部:先要填充伪首部各个字段,然后再将UDP/TCP报头以后(包括报头)的数据附加到伪首部的后面,再对位首部使用上述校验和计算,所得到的值才是UDP/TCP报头部分的校验和。 位首部可以用如下的结构体表示: typedef struct{ ULONG sourceip; //源IP地址 ULONG destip; //目的IP地址 BYTE mbz; //置空(0) BYTE ptcl; //协议类型 USHORT plen; //TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度 单位:字节) }Psd_Header; 这个过程是一个很繁琐的过程,计算过几次后再也忍受不了做这样重复的工作,于是写了一个通用的计算函数。这个函数使用起来我感觉非常方便:先封装好你的数据包(完整的,包括以太头),然后将数据包的首地址作为参数,调用该函数即可。函数将帮你完成IP报头以及UDP/TCP报头部分校验和的计算。 //------------------------------------------------------------------------- // PacketCheckSum // 计算数据包的校验和 // 参数:packet-待处理数据(将封装好的数据包的指针) //------------------------------------------------------------------------- void PacketCheckSum(unsigned char packet[]) { Dlc_Header *pdlc_header=NULL; //以太头指针 Ip_Header *pip_header=NULL; //IP头指针 unsigned short attachsize=0; //传输层协议头以及附加数据的总长度 pdlc_header=(Dlc_Header *)packet; //判断ethertype,如果不是IP包则不予处理 if(ntohs(pdlc_header->ethertype)!=0x0800) return; pip_header=(Ip_Header *)(packet+14); //TCP包 if(0x06==pip_header->proto) { Tcp_Header *ptcp_header=NULL; //TCP头指针 Tcp_Psd_Header *ptcp_psd_header=NULL; ptcp_header=(Tcp_Header *)(packet+14+((pip_header->ver_len)&15)*4); attachsize=ntohs(pip_header->total_len)-((pip_header->ver_len)&15)*4; ptcp_psd_header=(Tcp_Psd_Header *)malloc(attachsize+sizeof(Tcp_Psd_Header)); if(!ptcp_psd_header) return; memset(ptcp_psd_header,0,attachsize+sizeof(Tcp_Psd_Header)); //填充伪TCP头 ptcp_psd_header->destip=pip_header->destIP; ptcp_psd_header->sourceip=pip_header->sourceIP; ptcp_psd_header->mbz=0; ptcp_psd_header->ptcl=0x06; ptcp_psd_header->tcpl=htons(attachsize); //计算TCP校验和 ptcp_header->chksum=0; memcpy((unsigned char *)ptcp_psd_header+sizeof(Tcp_Psd_Header), (unsigned char *)ptcp_header,attachsize); ptcp_header->chksum=checksum((unsigned short *)ptcp_psd_header, attachsize+sizeof(Tcp_Psd_Header)); //计算ip头的校验和 pip_header->checksum=0; pip_header->checksum=checksum((unsigned short *)pip_header,20); return; } //UDP包 if(0x11==pip_header->proto) { Udp_Header *pudp_header=NULL; //UDP头指针 Udp_Psd_Header *pudp_psd_header=NULL; pudp_header=(Udp_Header *)(packet+14+((pip_header->ver_len)&15)*4); attachsize=ntohs(pip_header->total_len)-((pip_header->ver_len)&15)*4; pudp_psd_header=(Udp_Psd_Header *)malloc(attachsize+sizeof(Udp_Psd_Header)); if(!pudp_psd_header) return; memset(pudp_psd_header,0,attachsize+sizeof(Udp_Psd_Header)); //填充伪UDP头 pudp_psd_header->destip=pip_header->destIP; pudp_psd_header->sourceip=pip_header->sourceIP; pudp_psd_header->mbz=0; pudp_psd_header->ptcl=0x11; pudp_psd_header->udpl=htons(attachsize); //计算UDP校验和 pudp_header->chksum=0; memcpy((unsigned char *)pudp_psd_header+sizeof(Udp_Psd_Header), (unsigned char *)pudp_header,attachsize); pudp_header->chksum=checksum((unsigned short *)pudp_psd_header, attachsize+sizeof(Udp_Psd_Header)); //计算ip头的校验和 pip_header->checksum=0; pip_header->checksum=checksum((unsigned short *)pip_header,20); return; } return; } 需要几个头文件,以及库: #include <winsock2.h> #include <windows.h> #include "packet.h" #pragma comment(lib,"ws2_32.lib") 最后附上我使用的数据包的结构体(比较多): //数据包结构体 #pragma pack(1)
typedef struct { BYTE desmac[6]; //目的MAC地址 BYTE srcmac[6]; //源MAC地址 USHORT ethertype; //帧类型 }Dlc_Header; typedef struct { USHORT hw_type; //硬件类型Ethernet:0x1 USHORT prot_type; //上层协议类型IP:0x0800 BYTE hw_addr_len; //硬件地址长度:6 BYTE prot_addr_len; //协议地址(IP地址)的长度:4 USHORT flag; //1表示请求,2表示应答 BYTE send_hw_addr[6]; //源MAC地址 UINT send_prot_addr; //源IP地址 BYTE targ_hw_addr[6]; //目的MAC地址 UINT targ_prot_addr; //目的IP地址 BYTE padding[18]; //填充数据 }Arp_Frame;
typedef struct { Dlc_Header dlcheader;//DLC头 Arp_Frame arpframe; //ARP帧 }ARP_Packet;
typedef struct { BYTE ver_len; //IP包头部长度,单位:4字节 BYTE tos; //服务类型TOS USHORT total_len; //IP包总长度 USHORT ident; //标识 USHORT frag_and_flags; //标志位 BYTE ttl; //生存时间 BYTE proto; //协议 USHORT checksum; //IP首部校验和 UINT sourceIP; //源IP地址(32位) UINT destIP; //目的IP地址(32位) }Ip_Header;
typedef struct { USHORT srcport; // 源端口 USHORT dstport; // 目的端口 UINT seqnum; // 顺序号 UINT acknum; // 确认号 BYTE dataoff; // TCP头长 BYTE flags; // 标志(URG、ACK等) USHORT window; // 窗口大小 USHORT chksum; // 校验和 USHORT urgptr; // 紧急指针 }Tcp_Header;
//TCP伪首部 用于进行TCP校验和的计算,保证TCP效验的有效性 typedef struct{ ULONG sourceip; //源IP地址 ULONG destip; //目的IP地址 BYTE mbz; //置空(0) BYTE ptcl; //协议类型(IPPROTO_TCP) USHORT tcpl; //TCP包的总长度(单位:字节) }Tcp_Psd_Header; typedef struct { USHORT srcport; // 源端口 USHORT dstport; // 目的端口 USHORT total_len; // 包括UDP报头及UDP数据的长度(单位:字节) USHORT chksum; // 校验和 }Udp_Header;
typedef struct tsd_hdr { ULONG sourceip; //源IP地址 ULONG destip; //目的IP地址 BYTE mbz; //置空(0) BYTE ptcl; //协议类型(IPPROTO_UDP) USHORT udpl; //UDP包总长度(单位:字节) }Udp_Psd_Header;
typedef struct{ BYTE i_type; //类型 类型是关键:0->回送应答(Ping应答) 8->回送请求(Ping请求) BYTE i_code; //代码 这个与类型有关 当类型为0或8时这里都是0 USHORT i_cksum; //ICMP包校验和 USHORT i_id; //识别号(一般用进程ID作为标识号) USHORT i_seq; //报文序列号(一般设置为0) //UINT timestamp; //时间戳 BYTE padding[32];//填充数据 }Icmp_Header;
typedef struct { Dlc_Header dlc_header; //以太帧 Ip_Header ip_header; //IP头 Icmp_Header icmp_header;//ICMP帧 }Icmp_Packet;
typedef struct { unsigned char flag; //攻击数据包类型1-arp,2-tcp,3-udp unsigned int srcip; //攻击者IP unsigned char code[33]; //攻击特征码 }Attack_Infor; #pragma pack()
|