TCP,UDP完整数据包校验和通用计算

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;
/*Arp帧结构*/
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;
/*ARP包=DLC头+ARP帧*/
typedef struct {
Dlc_Header dlcheader;//DLC头
Arp_Frame arpframe;? //ARP帧
}ARP_Packet;
/*IP报头结构*/
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;
/*TCP报头结构*/
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;
/*UDP报头*/
typedef struct? {?
USHORT srcport;???? // 源端口
USHORT dstport;???? // 目的端口
USHORT total_len;?? // 包括UDP报头及UDP数据的长度(单位:字节)
USHORT chksum;????? // 校验和
}Udp_Header;
/*UDP伪首部-仅用于计算校验和*/
typedef struct tsd_hdr?
{?
ULONG? sourceip;??? //源IP地址
ULONG? destip;????? //目的IP地址
BYTE? mbz;?????????? //置空(0)
BYTE? ptcl;????????? //协议类型(IPPROTO_UDP)
USHORT udpl;???????? //UDP包总长度(单位:字节)?
}Udp_Psd_Header;
/*ICMP报头*/
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;
/*ICMP数据包*/
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()?

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值