- Type:1 byte。
- Code:1 byte。
- Checksum:2 bytes。
- Data:這裡根據Type以及Code才能夠判斷該如何解析。
- 長度:4 ~ 65515 bytes。
ICMP基本表頭是4個byte,很多書上會寫8 bytes是錯誤的,那是echo request和echo reply的長度(ping)。接下來根據type及code列出幾種ICMP封包。
ICMP Echo Request and ICMP Echo Reply header
- Identification:2 bytes。
- Sequence Number:2 bytes。
- Data:0 ~ 65507 bytes。
- 長度:8 ~ 65515 bytes。
當Type等於0為echo reply,8是echo request,echo request和echo reply最少是8個byte。
data部分只是普通的message,ping指令會填入一些message當作data並發出echo request封包,正常情況目標會回覆一個echo reply封包且data內容必須要和原本request的message相同。
ICMP Time Exceeded and Destination Unreachable header
- Unused:4 bytes。
- The IP header plus the datagram data from the original "time exceeded" or "destination unreachable" packet:當發生
Time Exceeded
或Destination Unreachable
時,會把發生這兩事件的封包當成ICMP的payload傳回,variable bytes。
當Type等於3是destination unreachable,11是time exceeded,最少也是8個byte,其中destination unreachable的code除了4(Fragmentation Needed and Don't Fragment was Set)以外都使用這個表頭欄位。
封包在轉送過程中如果time to live(TTL)已達到0,會發出time exceeded封包到原本的source端;若沒辦法將封包送往下一個節點時(可能被防火牆擋下),則會發出destination unreachable封包到轉送(發送)該封包的主機或source端。
ICMP Destination Unreachable and Fragmentation Needed header
- Void:2 bytes。
- Next MTU:2 bytes。
- The IP header plus the datagram data from the original "destination unreachable" packet:當發生
Destination Unreachable
時,會把發生這事件的封包當成ICMP的payload傳回,variable bytes。
當type為3(Destination Unreachable)且Code為4(Fragmentation Needed and Don't Fragment was Set)時,使用這個表頭欄位。
封包如果IP表頭的Flags被設定don't fragment但因MTU大小無法轉送出去,則會發出destination unreachable然後code設定fragmentation needed到轉送(發送)該封包的主機或source端。
ICMP Redirect header
- Router IP Address:2 bytes。
- The IP header plus the first 8 bytes datagram data from the original need redirected packet:當router覺得有更好的路徑時(通常根據metric),會傳回建議重新轉向的封包IP表頭及其所帶的資料前8個byte,variable bytes。
當type為5(Redirect)時,使用這個表頭欄位。
封包在轉送過程中,router若發現有更好的路徑,則會發出redirect封包到轉送(發送)該封包的主機。
封包表頭部分include這些。
#ifndef __linux #include <net/if.h> #include <netinet/in.h> #include <net/if_dl.h> #include <net/ethernet.h> #else /* if BSD */ #define __FAVOR_BSD #include <linux/if_ether.h> #include <netpacket/packet.h> #include <linux/if_link.h> #include <netinet/ether.h> #endif /* if linux */ #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h>
解析封包表頭的函數參數修改成:直接給該層的表頭結構指標。
static void dump_ethernet(u_int32_t length, const u_char *content); static void dump_ip(struct ip *ip); static void dump_tcp(struct tcphdr *tcp); static void dump_tcp_mini(struct tcphdr *tcp); static void dump_udp(struct udphdr *udp); static void dump_icmp(struct icmp *icmp);
過濾器用"icmp"表示只抓icmp封包。
//compile filter if(-1 == pcap_compile(handle, &fcode, "icmp", 1, mask)) { fprintf(stderr, "pcap_compile(): %s\n", pcap_geterr(handle)); pcap_close(handle); exit(1); }//end if
因為解析函數都改了參數,所以傳入之前必須先算好開頭位置再傳。
case ETHERTYPE_IP: printf("IP\n"); dump_ip((struct ip *)(content + ETHER_HDR_LEN)); break;
函數
dump_ip()
部分。char *p = (char *)ip + (ip->ip_hl << 2); switch (protocol) { case IPPROTO_UDP: printf("Next is UDP\n"); break; case IPPROTO_TCP: printf("Next is TCP\n"); break; case IPPROTO_ICMP: printf("Next is ICMP\n"); dump_icmp((struct icmp *)p); break; default: printf("Next is %d\n", protocol); break; }//end switch
這邊
char *p = (char *)ip + (ip->ip_hl << 2);
,會將ip指標先轉成char *
是因為ip是struct ip *
指標,假如直接加上1的話,實際上指標會位移20個byte(sizeof(struct ip)),這樣會不正確,而轉成char *
加上1的話,只會位移1個byte(sizeof(char)),這邊一樣放上我之前在其他地方寫的。接著主要解析ICMP的函數。
//copy header u_char type = icmp->icmp_type; u_char code = icmp->icmp_code; u_char checksum = ntohs(icmp->icmp_cksum); static char *type_name[] = { "Echo Reply", /* Type 0 */ "Undefine", /* Type 1 */ "Undefine", /* Type 2 */ "Destination Unreachable", /* Type 3 */ "Source Quench", /* Type 4 */ "Redirect (change route)", /* Type 5 */ "Undefine", /* Type 6 */ "Undefine", /* Type 7 */ "Echo Request", /* Type 8 */ "Undefine", /* Type 9 */ "Undefine", /* Type 10 */ "Time Exceeded", /* Type 11 */ "Parameter Problem", /* Type 12 */ "Timestamp Request", /* Type 13 */ "Timestamp Reply", /* Type 14 */ "Information Request", /* Type 15 */ "Information Reply", /* Type 16 */ "Address Mask Request", /* Type 17 */ "Address Mask Reply", /* Type 18 */ "Unknown" /* Type 19 */ }; //icmp type #define ICMP_TYPE_MAX (sizeof type_name / sizeof type_name[0]) if (type < 0 || ICMP_TYPE_MAX <= type) type = ICMP_TYPE_MAX - 1;
結構
struct icmp
宣告:/* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ /* * Internal of an ICMP Router Advertisement */ struct icmp_ra_addr { u_int32_t ira_addr; u_int32_t ira_preference; }; /* * Structure of an icmp header. */ struct icmp { u_char icmp_type; /* type of message, see below */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ union { u_char ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { n_short icd_id; n_short icd_seq; } ih_idseq; int ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { n_short ipm_void; n_short ipm_nextmtu; } ih_pmtu; struct ih_rtradv { u_char irt_num_addrs; u_char irt_wpa; u_int16_t irt_lifetime; } ih_rtradv; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_void icmp_hun.ih_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime union { struct id_ts { n_time its_otime; n_time its_rtime; n_time its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; struct icmp_ra_addr id_radv; u_int32_t id_mask; char id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_radv icmp_dun.id_radv #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data };
接著先把固定表頭的部分和後面不同type、code的表頭畫出來。
printf("Protocol: ICMP (%s)\n", type_name[type]); printf("+------------+------------+-------------------------+\n"); printf("| Type: %3u| Code: %3u| Checksum: %5u|\n", type, code, checksum); printf("+------------+------------+-------------------------+\n"); if (type == ICMP_ECHOREPLY || type == ICMP_ECHO) { printf("| Identification: %5u| Sequence Number: %5u|\n", ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); printf("+-------------------------+-------------------------+\n"); }//end if else if (type == ICMP_UNREACH) { if (code == ICMP_UNREACH_NEEDFRAG) { printf("| void: %5u| Next MTU: %5u|\n", ntohs(icmp->icmp_pmvoid), ntohs(icmp->icmp_nextmtu)); printf("+-------------------------+-------------------------+\n"); }//end if else { printf("| Unused: %10lu|\n", (unsigned long) ntohl(icmp->icmp_void)); printf("+-------------------------+-------------------------+\n"); }//end else }//end if else if (type == ICMP_REDIRECT) { printf("| Router IP Address: %15s|\n", ip_ntoa(&(icmp->icmp_gwaddr))); printf("+---------------------------------------------------+\n"); }//end if else if (type == ICMP_TIMXCEED) { printf("| Unused: %10lu|\n", (unsigned long)ntohl(icmp->icmp_void)); printf("+---------------------------------------------------+\n"); }//end else
接著是payload部分。
//if the icmp packet carry ip header if (type == ICMP_UNREACH || type == ICMP_REDIRECT || type == ICMP_TIMXCEED) { struct ip *ip = (struct ip *)icmp->icmp_data; char *p = (char *)ip + (ip->ip_hl << 2); dump_ip(ip); switch (ip->ip_p) { case IPPROTO_TCP: if(type == ICMP_REDIRECT) { /** * RFC 792: Page 12 * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Gateway Internet Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Internet Header + 64 bits of Original Data Datagram | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * only 8 bytes */ dump_tcp_mini((struct tcphdr *)p); }//end if else { dump_tcp((struct tcphdr *)p); }//end else break; case IPPROTO_UDP: dump_udp((struct udphdr *)p); break; }//end switch }//end if
IP表頭的部分是固定有的,然後當type為redirect時候,只會帶回原封包前8個byte,如果直接呼叫函數
dump_tcp()
會解析整個tcp表頭,所以才另外寫一個只解析8個byte的函數dump_tcp_mini()
。static void dump_tcp_mini(struct tcphdr *tcp) { //copy header u_int16_t source_port = ntohs(tcp->th_sport); u_int16_t destination_port = ntohs(tcp->th_dport); u_int32_t sequence = ntohl(tcp->th_seq); //print printf("Protocol: TCP\n"); printf("+-------------------------+-------------------------+\n"); printf("| Source Port: %5u| Destination Port: %5u|\n", source_port, destination_port); printf("+-------------------------+-------------------------+\n"); printf("| Sequence Number: %10u|\n", sequence); printf("+---------------------------------------------------+\n"); }//end dump_tcp_mini
函數
dump_tcp_mini()
只解析tcp開頭8個byte。編譯:
libpcap % gcc -I/usr/local/opt/libpcap/include -Wall -std=gnu99 -L/usr/local/opt/libpcap/lib -lpcap dump-icmp.c -o dump-icmp
執行結果:
libpcap % ./dump-icmp Sniffing: en0 No. 1 Time: 01:03:46.353155 Length: 98 bytes Capture length: 98 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: f8:1a:67:53:f5:dc| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 84| +-----+------+------------+-------+-----------------+ | Identifier: 7944| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 1| Header Checksum: 55275| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.100| +---------------------------------------------------+ | Destination IP Address: 192.168.1.1| +---------------------------------------------------+ Protocol: ICMP (Echo Request) +------------+------------+-------------------------+ | Type: 8| Code: 0| Checksum: 254| +------------+------------+-------------------------+ | Identification: 11836| Sequence Number: 0| +-------------------------+-------------------------+ libpcap % ./dump-icmp Sniffing: en0 No. 1 Time: 01:03:46.354704 Length: 98 bytes Capture length: 98 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: f8:1a:67:53:f5:dc| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 84| +-----+------+------------+-------+-----------------+ | Identifier: 59097| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 1| Header Checksum: 4122| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.1| +---------------------------------------------------+ | Destination IP Address: 192.168.1.100| +---------------------------------------------------+ Protocol: ICMP (Echo Reply) +------------+------------+-------------------------+ | Type: 0| Code: 0| Checksum: 254| +------------+------------+-------------------------+ | Identification: 11836| Sequence Number: 0| +-------------------------+-------------------------+ libpcap % ./dump-icmp Sniffing: en0 No. 1 Time: 01:03:54.646161 Length: 94 bytes Capture length: 94 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: f8:1a:67:53:f5:dc| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: 11------| Total Length: 80| +-----+------+------------+-------+-----------------+ | Identifier: 59100| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 1| Header Checksum: 3931| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.1| +---------------------------------------------------+ | Destination IP Address: 192.168.1.100| +---------------------------------------------------+ Protocol: ICMP (Destination Unreachable) +------------+------------+-------------------------+ | Type: 3| Code: 3| Checksum: 228| +------------+------------+-------------------------+ | Unused: 0| +-------------------------+-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 52| +-----+------+------------+-------+-----------------+ | Identifier: 48211| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 1| Pro: 17| Header Checksum: 31152| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.100| +---------------------------------------------------+ | Destination IP Address: 192.168.1.1| +---------------------------------------------------+ Protocol: UDP +-------------------------+-------------------------+ | Source Port: 48210| Destination Port: 33435| +-------------------------+-------------------------+ | Length: 32| Checksum: 15626| +-------------------------+-------------------------+ libpcap % ./dump-icmp Sniffing: en0 No. 1 Time: 03:05:17.442507 Length: 106 bytes Capture length: 106 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: f8:1a:67:53:f5:dc| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: 11------| Total Length: 92| +-----+------+------------+-------+-----------------+ | Identifier: 23203| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 1| Header Checksum: 39816| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.1| +---------------------------------------------------+ | Destination IP Address: 192.168.1.100| +---------------------------------------------------+ Protocol: ICMP (Time Exceeded) +------------+------------+-------------------------+ | Type: 11| Code: 0| Checksum: 195| +------------+------------+-------------------------+ | Unused: 0| +---------------------------------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 64| +-----+------+------------+-------+-----------------+ | Identifier: 49525| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 1| Pro: 6| Header Checksum: 26546| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.100| +---------------------------------------------------+ | Destination IP Address: 120.125.86.7| +---------------------------------------------------+ Protocol: TCP +-------------------------+-------------------------+ | Source Port: 49523| Destination Port: 33436| +-------------------------+-------------------------+ | Sequence Number: 2191311219| +---------------------------------------------------+ | Acknowledgement Number: 0| +------+-------+----------+-------------------------+ | HL:20| RSV |F:------S-| Window Size: 0| +------+-------+----------+-------------------------+ | Checksum: 38681| Urgent Pointer: 0| +-------------------------+-------------------------+ libpcap % ./dump-icmp Sniffing: en0 No. 1 Time: 01:08:27.408177 Length: 70 bytes Capture length: 70 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: d8:bb:2c:cc:16:ab| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 56| +-----+------+------------+-------+-----------------+ | Identifier: 28275| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 1| Header Checksum: 34872| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.100| +---------------------------------------------------+ | Destination IP Address: 192.168.1.101| +---------------------------------------------------+ Protocol: ICMP (Redirect (change route)) +------------+------------+-------------------------+ | Type: 5| Code: 1| Checksum: 146| +------------+------------+-------------------------+ | Router IP Address: 192.168.1.1| +---------------------------------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 74| +-----+------+------------+-------+-----------------+ | Identifier: 27325| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 255| Pro: 17| Header Checksum: 52526| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.101| +---------------------------------------------------+ | Destination IP Address: 192.168.1.1| +---------------------------------------------------+ Protocol: UDP +-------------------------+-------------------------+ | Source Port: 63585| Destination Port: 53| +-------------------------+-------------------------+ | Length: 54| Checksum: 61429| +-------------------------+-------------------------+ libpcap % ./dump-icmp Sniffing: en0 No. 1 Time: 01:08:27.441180 Length: 70 bytes Capture length: 70 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: d8:bb:2c:cc:16:ab| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 56| +-----+------+------------+-------+-----------------+ | Identifier: 31285| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 1| Header Checksum: 31862| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.100| +---------------------------------------------------+ | Destination IP Address: 192.168.1.101| +---------------------------------------------------+ Protocol: ICMP (Redirect (change route)) +------------+------------+-------------------------+ | Type: 5| Code: 1| Checksum: 104| +------------+------------+-------------------------+ | Router IP Address: 192.168.1.1| +---------------------------------------------------+ Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 64| +-----+------+------------+-------+-----------------+ | Identifier: 18197| FF:-D-| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 6| Header Checksum: 25378| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.101| +---------------------------------------------------+ | Destination IP Address: 203.211.2.160| +---------------------------------------------------+ Protocol: TCP +-------------------------+-------------------------+ | Source Port: 52654| Destination Port: 80| +-------------------------+-------------------------+ | Sequence Number: 2376699460| +---------------------------------------------------+
Source code on Github
沒有留言:
張貼留言