http://hi.baidu.com/wyw5257/blog/item/9d1e1afaa0bde50da8d31110.html
From:http://blog.csdn.net/hzb1983/archive/2009/06/22/4288530.aspx
http://wenku.baidu.com/view/46c180c7aa00b52acfc7ca0b.html
下面這些TCP/IP數據包是我在進行Socket及Wipcap網絡編程過程中曾經用到過的數據包結構體, 這些東西平時看起來不起眼,真正用到的時候就會覺得非常有用......
/*物理幀頭結構*/typedef struct {
BYTE desmac[6]; //目的MAC地址
BYTE srcmac[6]; //源MAC地址
USHORT ethertype; //幀類型
}Dlc_Header;
/*IP報頭結構*/
typedef struct {
BYTE h_len_ver; //IP版本號(高4位)及以32比特爲單位的IP包頭部的長度(低四位)
BYTE tos; //服務類型TOS
USHORT total_len; //IP包總長度
USHORT ident; //標識
USHORT frag_and_flags; //標誌位
BYTE ttl; //生存時間
BYTE proto; //協議
USHORT checksum; //IP首部校驗和
BYTE sourceip[4]; //源IP地址(32位)
//或者UINT sourceip;
BYTE destip[4]; //目的IP地址(32位)
//或者 UINT destip;
}Ip_Header;
/*TCP報頭*/
typedef struct {
USHORT srcport; // 源端口
USHORT dstport; // 目的端口
UINT seqnum; // 順序號
UINT acknum; //期待獲得對方的TCP包編號
BYTE h_len; // 以32比特爲單位的TCP報頭長度
BYTE flags; // 標誌(URG、ACK等)
USHORT indow; // 窗口大小
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頭的長度(單位:字節)
}PSD_HEADER;
/*UDP報頭*/
typedef struct {
USHORT srcport; // 源端口
USHORT dstport; // 目的端口
USHORT total_len; // 包括UDP報頭及UDP數據的長度(單位:字節)
USHORT chksum; // 校驗和
}Udp_Header;
//UDP僞首部-僅用於計算校驗和
typedef struct tsd_hdr
{
BYTE sourceip[4]; //源IP地址
BYTE destip[4]; //目的IP地址
BYTE mbz;//置空(0)
BYTE ptcl; //協議類型(IPPROTO_UDP)
USHORT udpl;//UDP包總長度(不包括僞首部的長度 單位:字節)
}PSD_HEADER;
/*ICMP報頭*/
typedef struct {
BYTE i_type; //類型 發出的ICMP爲8(ICMP_ECHO_REQUEST),接受到的ICMP爲0
BYTE i_code; //代碼
USHORT i_cksum; //ICMP包校驗和
USHORT i_id; //識別號(一般用進程號作爲標識號)
USHORT i_seq; //報文序列號(一般設置爲0)
ULONG timestamp;//時間戳
}Icmp_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地址
BYTE Send_Prot_Addr[4];//源IP地址
BYTE Targ_HW_Addr[6];//目的MAC地址
BYTE Targ_Prot_Addr[4];//目的IP地址
BYTE Padding[18];//填充數據
}Arp_Frame;
/*DNS數據報頭*/
typedef struct {
USHORT id; //標識,通過它客戶端可以將DNS的請求與應答相匹配;
USHORT flags; //標誌:(查詢)0x0100 (應答)0x8180 這些數字都是主機序
USHORT questions; //問題數目
USHORT answers; //資源記錄數目
USHORT author; //授權資源記錄數目
USHORT addition; //額外資源記錄數目
}DNS_HEADER;
//這是DNS包的公共部分,即查詢包及應答包都含有這部分,由於查詢問題(Domain)大小無法確定,因此這裏不好將其及其以後的數據寫入結構體中
From:http://tech.sina.com.cn/s/2006-11-10/1455153882.shtml
大多數程序員所接觸到的套接字(Socket)爲兩類:
(1)流式套接字(SOCK_STREAM):一種面向連接的Socket,針對於面向連接的TCP服務應用;
(2)數據報式套接字(SOCK_DGRAM):一種無連接的Socket,對應於無連接的UDP服務應用。
從用戶的角度來看,SOCK_STREAM、SOCK_DGRAM這兩類套接字似乎的確涵蓋了TCP/IP應用的全部,因爲基於TCP/IP的應用,從協議棧的層次上講,在傳輸層的確只可能建立於TCP或UDP協議之上(圖1),而SOCK_STREAM、SOCK_DGRAM又分別對應於TCP和
UDP,所以幾乎所有的應用都可以用這兩類套接字實現。
圖1 TCP/IP協議棧 |
但是,當我們面對如下問題時,SOCK_STREAM、SOCK_DGRAM將顯得這樣無助:
(1) 怎樣發送一個自定義的IP包?
(2) 怎樣發送一個ICMP協議包?
(3) 怎樣使本機進入雜糅模式,從而能夠進行網絡sniffer?
(4) 怎樣分析所有經過網絡的包,而不管這樣包是否是發給自己的?
(5) 怎樣僞裝本地的IP地址?
這使得我們必須面對另外一個深刻的主題――原始套接字(Raw Socket)。Raw Socket廣泛應用於高級網絡編程,也是一種廣泛的黑客手段。著名的網絡sniffer、拒絕服務攻擊(DOS)、IP欺騙等都可以以Raw Socket實現。
Raw Socket與標準套接字(SOCK_STREAM、SOCK_DGRAM)的區別在於前者直接置"根"於操作系統網絡核心(Network Core),而SOCK_STREAM、SOCK_DGRAM則"懸浮"於TCP和UDP協議的外圍,如圖2所示:
圖2 Raw Socket與標準Socket |
當我們使用Raw Socket的時候,可以完全自定義IP包,一切形式的包都可以"製造"出來。因此,本文事先必須對TCP/IP所涉及IP包結構進行必要的交待。
目前,IPv4的報頭結構爲:
版本號(4) | 包頭長(4) | 服務類型(8) |
數據包長度(16)
|
標識(16)
|
偏移量(16)
|
||
生存時間(8)
|
傳輸協議(8)
|
校驗和(16)
|
|
源地址(32)
|
|||
目的地址(32)
|
|||
選項(8)
|
.........
|
填充
|
對其進行數據結構封裝:
typedef struct _iphdr //定義IP報頭 { unsigned char h_lenver; //4位首部長度+4位IP版本號 unsigned char tos; //8位服務類型TOS unsigned short total_len; //16位總長度(字節) unsigned short ident; //16位標識 unsigned short frag_and_flags; //3位標誌位 unsigned char ttl; //8位生存時間 TTL unsigned char proto; //8位協議 (TCP, UDP 或其他) unsigned short checksum; //16位IP首部校驗和 unsigned int sourceIP; //32位源IP地址 unsigned int destIP; //32位目的IP地址 } IP_HEADER; |
或者將上述定義中的第一字節按位拆分:
typedef struct _iphdr //定義IP報頭 { unsigned char h_len : 4; //4位首部長度 unsigned char ver : 4; //4位IP版本號 unsigned char tos; unsigned short total_len; unsigned short ident; unsigned short frag_and_flags; unsigned char ttl; unsigned char proto; unsigned short checksum; unsigned int sourceIP; unsigned int destIP; } IP_HEADER; |
更加嚴格地講,上述定義中h_len、ver字段的內存存放順序還與具體CPU的Endian有關,因此,更加嚴格的IP_HEADER可定義爲:
typedef struct _iphdr //定義IP報頭 { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned char h_len : 4; //4位首部長度 unsigned char ver : 4; //4位IP版本號 #elif defined (__BIG_ENDIAN_BITFIELD) unsigned char ver : 4; //4位IP版本號 unsigned char h_len : 4; //4位首部長度 #endif unsigned char tos; unsigned short total_len; unsigned short ident; unsigned short frag_and_flags; unsigned char ttl; unsigned char proto; unsigned short checksum; unsigned int sourceIP; unsigned int destIP; } IP_HEADER; |
TCP報頭結構爲:
源端口(16)
|
目的端口(16)
|
||
序列號(32)
|
|||
確認號(32)
|
|||
TCP偏移量(4)
|
保留(6)
|
標誌(6)
|
窗口(16)
|
校驗和(16)
|
緊急(16)
|
||
選項(0或32)
|
|||
數據(可變)
|
對應數據結構:
typedef struct psd_hdr //定義TCP僞報頭 { unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz; char ptcl; //協議類型 unsigned short tcpl; //TCP長度 }PSD_HEADER; typedef struct _tcphdr //定義TCP報頭 { unsigned short th_sport; //16位源端口 unsigned short th_dport; //16位目的端口 unsigned int th_seq; //32位序列號 unsigned int th_ack; //32位確認號 unsigned char th_lenres; //4位首部長度/4位保留字 unsigned char th_flag; //6位標誌位 unsigned short th_win; //16位窗口大小 unsigned short th_sum; //16位校驗和 unsigned short th_urp; //16位緊急數據偏移量 } TCP_HEADER; |
同樣地,TCP頭的定義也可以將位域拆分:
typedef struct _tcphdr { unsigned short th_sport; unsigned short th_dport; unsigned int th_seq; unsigned int th_ack; /*little-endian*/ unsigned short tcp_res1: 4, tcp_hlen: 4, tcp_fin: 1, tcp_syn: 1, tcp_rst: 1, tcp_psh: 1, tcp_ack: 1, tcp_urg: 1, tcp_res2: 2; unsigned short th_win; unsigned short th_sum; unsigned short th_urp; } TCP_HEADER; |
UDP報頭爲:
源端口(16)
|
目的端口(16)
|
報文長(16)
|
校驗和(16)
|
對應的數據結構爲:
typedef struct _udphdr //定義UDP報頭 { unsigned short uh_sport;//16位源端口 unsigned short uh_dport;//16位目的端口 unsigned short uh_len;//16位長度 unsigned short uh_sum;//16位校驗和 } UDP_HEADER; |
ICMP協議是網絡層中一個非常重要的協議,其全稱爲Internet Control Message Protocol(因特網控制報文協議),ICMP協議彌補了IP的缺限,它使用IP協議進行信息傳遞,向數據包中的源端節點提供發生在網絡層的錯誤信息反饋。ICMP報頭爲:
類型(8)
|
代碼(8)
|
校驗和(16)
|
消息內容 |
常用的回送與或回送響應ICMP消息對應數據結構爲:
typedef struct _icmphdr //定義ICMP報頭(回送與或回送響應) { unsigned char i_type;//8位類型 unsigned char i_code; //8位代碼 unsigned short i_cksum; //16位校驗和 unsigned short i_id; //識別號(一般用進程號作爲識別號) unsigned short i_seq; //報文序列號 unsigned int timestamp;//時間戳 } ICMP_HEADER; |
常用的ICMP報文包括ECHO-REQUEST(響應請求消息)、ECHO-REPLY(響應應答消息)、Destination Unreachable(目標不可到達消息)、Time Exceeded(超時消息)、Parameter Problems(參數錯誤消息)、Source Quenchs(源抑制消息)、Redirects(重定向消息)、Timestamps(時間戳消息)、Timestamp Replies(時間戳響應消息)、Address Masks(地址掩碼請求消息)、Address Mask Replies(地址掩碼響應消息)等,是Internet上十分重要的消息。後面章節中所涉及到的ping命令、ICMP拒絕服務攻擊、路由欺騙都與 ICMP協議息息相關。
另外,本系列文章中的部分源代碼參考了一些優秀程序員的開源項目,由於篇幅的關係我們不能一一列舉,在此一併表示感謝。