[經驗]TCP,UDP完整資料包校驗和通用計算 - 日誌 - redice - 我的空間
導讀:
ICMP,IP,UDP,TCP報頭部分都有checksum(檢驗和)欄位。ICMP和IP報頭校驗和的計算都很簡單,使用RFC1071中給出的方法即可完成(如下)。
本文轉自
http://hi.bccn.net/space-112902-do-blog-id-12121.html
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);
}
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;
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; //傳輸層協議頭以及附加資料的總長度
// 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;
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);
//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));
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);
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;
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));
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;
}
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
#include
#include "packet.h"
#pragma comment(lib,"ws2_32.lib")
#include
#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;
#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;
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;
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;
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;
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{
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;
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;
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{
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()
typedef struct
{
unsigned char flag; //攻擊資料包型別1-arp,2-tcp,3-udp
unsigned int srcip; //攻擊者IP
unsigned char code[33]; //攻擊特徵碼
}Attack_Infor;
#pragma pack()
本文轉自
http://hi.bccn.net/space-112902-do-blog-id-12121.html
相關文章
- 日誌和告警資料探勘經驗談
- 【測試】echo傳送和接收TCP/UDP資料包|shell 傳送TCP/UDP資料包TCPUDP
- 網路資料包效驗和(checksum)的計算
- TCP的校驗和與編號TCP
- IP資料包的校驗和演算法_儒雅演算法
- 行式填報 資料校驗 --- 小計校驗
- 計算歸檔日誌所需要的磁碟空間
- 資料校驗
- TimesTen計算和配置TimesTen的ttmesg日誌儲存空間
- [na]二層+tcp/udp資料包格式TCPUDP
- 計算校驗和工具:Checksum Thing MacMac
- MySQL手動資料校驗+雲資料庫資料校驗MySql資料庫
- IP和TCP抓包分析實驗TCP
- 身份證校驗碼的計算方法
- easypoi資料校驗
- tcp 偽頭部 結構 格式 校驗和TCP
- db2修改資料庫的日誌空間DB2資料庫
- DW中的資料校驗
- ORACLE應用經驗(5)-表空間Oracle
- ORACLE資料校驗文件Oracle
- rpm包的校驗和檔案讀取
- 計算機網路 之 TCP和UDP的埠號解析計算機網路TCPUDP
- SOCKET通訊中TCP、UDP資料包大小的確定TCPUDP
- 對oracle資料表空間的計算Oracle
- [資料校驗/資料質量] 資料校驗框架(Java):hibernate-validation框架Java
- 前端資料校驗後,後端介面是否需要再次校驗?前端後端
- 身份證號碼校驗位的計算方式
- ORACLE應用經驗(5)-表空間(轉)Oracle
- TCP 和 UDPTCPUDP
- TCP和UDPTCPUDP
- 資料庫設計經驗談資料庫
- Binding(四):資料校驗
- struts2資料校驗
- 使用 voluptuous 校驗資料
- Python 日誌庫 logging 的理解和實踐經驗Python
- UDP分片和丟包與TCP效果對比UDPTCP
- 資料清洗經驗
- 經驗分享:MySQL日誌維護策略總結MySql