- 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






沒有留言:
張貼留言