- Source Port:2 bytes。
- Destination Port:2 bytes。
- Sequence Number:4 bytes。
- Acknowledgement Number:4 bytes。
- Header Length:4 bits。
- Reserved:4 bits。
- Flags:8 bits。
- Window Size:2 bytes。
- Checksum:2 bytes。
- Urgent Pointer:2 bytes。
- TCP Option + Padding:0 ~ 40 bytes。
- 長度:20 ~ 60 bytes。
Flags由左到右分別為:CWR、ECE、URG、ACK、PUSH、RST、SYN以及FIN,共8個bit。
- Source Port:2 bytes。
- Destination Port:2 bytes。
- Length:2 bytes。
- Checksum:2 bytes。
- 長度:8 bytes。
先include的header。
#include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h>
打開預設的device,過濾器是"tcp or udp"表示只抓tcp和udp,然後只抓一個封包。
char errbuf[PCAP_ERRBUF_SIZE]; char *device = NULL; //get default interface name device = pcap_lookupdev(errbuf); if(!device) { fprintf(stderr, "pcap_lookupdev(): %s\n", errbuf); exit(1); }//end if printf("Sniffing: %s\n", device); pcap_t *handle = pcap_open_live(device, 65535, 1, 1, errbuf); if(!handle) { fprintf(stderr, "pcap_open_live(): %s\n", errbuf); exit(1); }//end if //generate bpf filter bpf_u_int32 net, mask; struct bpf_program fcode; //get network and mask if(-1 == pcap_lookupnet(device, &net, &mask, errbuf)) { fprintf(stderr, "pcap_lookupnet(): %s\n", errbuf); mask = PCAP_NETMASK_UNKNOWN; }//end if //compile filter if(-1 == pcap_compile(handle, &fcode, "tcp or udp", 1, mask)) { fprintf(stderr, "pcap_compile(): %s\n", pcap_geterr(handle)); pcap_close(handle); exit(1); }//end if //set filter if(-1 == pcap_setfilter(handle, &fcode)) { fprintf(stderr, "pcap_pcap_setfilter(): %s\n", pcap_geterr(handle)); pcap_freecode(&fcode); pcap_close(handle); exit(1); }//end if //free bpf code pcap_freecode(&fcode); //start capture pcap_loop(handle, 1, pcap_callback, NULL);
switch (protocol) { case IPPROTO_UDP: printf("Next is UDP\n"); dump_udp(length, content); break; case IPPROTO_TCP: printf("Next is TCP\n"); dump_tcp(length, content); break; case IPPROTO_ICMP: printf("Next is ICMP\n"); break; default: printf("Next is %d\n", protocol); break; }//end switch
解析ip層的時候,當下一層協定是17(或marcos
IPPROTO_UDP
)呼叫函數dump_udp()
解析udp;當下一層是6(或marcos IPPROTO_TCP
)呼叫函數dump_tcp()
解析tcp。
先來看udp部分。
static void dump_udp(u_int32_t length, const u_char *content) { struct ip *ip = (struct ip *)(content + ETHER_HDR_LEN); struct udphdr *udp = (struct udphdr *)(content + ETHER_HDR_LEN + (ip->ip_hl << 2)); u_int16_t source_port = ntohs(udp->uh_sport); u_int16_t destination_port = ntohs(udp->uh_dport); u_int16_t len = ntohs(udp->uh_ulen); u_int16_t checksum = ntohs(udp->uh_sum); printf("Protocol: UDP\n"); printf("+-------------------------+-------------------------+\n"); printf("| Source Port: %5u| Destination Port: %5u|\n", source_port, destination_port); printf("+-------------------------+-------------------------+\n"); printf("| Length: %5u| Checksum: %5u|\n", len, checksum); printf("+-------------------------+-------------------------+\n"); }//end dump_udp
udp比較簡單,udp開始位置就是略過ethernet和ip層;ip層的表頭長度是結構
struct ip
成員ip_hl的4倍。結構
struct udphdr
宣告:/* * Udp protocol header. * Per RFC 768, September, 1981. */ struct udphdr { u_short uh_sport; /* source port */ u_short uh_dport; /* destination port */ u_short uh_ulen; /* udp length */ u_short uh_sum; /* udp checksum */ };
接著來看tcp部分。
static void dump_tcp(u_int32_t length, const u_char *content) { struct ip *ip = (struct ip *)(content + ETHER_HDR_LEN); struct tcphdr *tcp = (struct tcphdr *)(content + ETHER_HDR_LEN + (ip->ip_hl << 2)); //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); u_int32_t ack = ntohl(tcp->th_ack); u_int8_t header_len = tcp->th_off << 2; u_int8_t flags = tcp->th_flags; u_int16_t window = ntohs(tcp->th_win); u_int16_t checksum = ntohs(tcp->th_sum); u_int16_t urgent = ntohs(tcp->th_urp);
tcp層的表頭長度是結構
struct tcphdr
成員th_off的4倍。結構
struct tcphdr
宣告:/* * TCP header. * Per RFC 793, September, 1981. */ struct tcphdr { unsigned short th_sport; /* source port */ unsigned short th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ #if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN unsigned int th_x2:4, /* (unused) */ th_off:4; /* data offset */ #endif #if __DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN unsigned int th_off:4, /* data offset */ th_x2:4; /* (unused) */ #endif unsigned char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) unsigned short th_win; /* window */ unsigned short th_sum; /* checksum */ unsigned short th_urp; /* urgent pointer */ };
接著就把tcp表頭列印出來。
//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"); printf("| Acknowledgement Number: %10u|\n", ack); printf("+------+-------+----------+-------------------------+\n"); printf("| HL:%2u| RSV |F:%8s| Window Size: %5u|\n", header_len, tcp_ftoa(flags), window); printf("+------+-------+----------+-------------------------+\n"); printf("| Checksum: %5u| Urgent Pointer: %5u|\n", checksum, urgent); printf("+-------------------------+-------------------------+\n");
函數
tcp_ftoa()
是將tcp的flags轉成字串。做法跟函數
ip_ftoa()
一樣。static const char *tcp_ftoa(u_int8_t flag) { static int f[] = {'W', 'E', 'U', 'A', 'P', 'R', 'S', 'F'}; #define TCP_FLG_MAX (sizeof f / sizeof f[0]) static char str[TCP_FLG_MAX + 1]; u_int32_t mask = 1 << 7; int i; for (i = 0; i < TCP_FLG_MAX; i++) { if(mask & flag) str[i] = f[i]; else str[i] = '-'; mask >>= 1; }//end for str[i] = '\0'; return str; }//end tcp_ftoa
編譯:
libpcap % gcc -I/usr/local/opt/libpcap/include -Wall -std=gnu99 -L/usr/local/opt/libpcap/lib -lpcap dump-tcp-and-udp.c -o dump-tcp-and-udp
執行結果(Mac OS X):
libpcap % ./dump-tcp-and-udp Sniffing: en0 No. 1 Time: 14:10:14.698494 Length: 54 bytes Capture length: 54 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: d8:fe:e3:a4:d3:78| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Next protocol is IP Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 40| +-----+------+------------+-------+-----------------+ | Identifier: 65227| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 6| Header Checksum: 0xbcb5| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.50| +---------------------------------------------------+ | Destination IP Address: 64.233.188.139| +---------------------------------------------------+ Next is TCP Protocol: TCP +-------------------------+-------------------------+ | Source Port: 51736| Destination Port: 443| +-------------------------+-------------------------+ | Sequence Number: 3339194354| +---------------------------------------------------+ | Acknowledgement Number: 1712036847| +------+-------+----------+-------------------------+ | HL:20| RSV |F:---A----| Window Size: 4096| +------+-------+----------+-------------------------+ | Checksum: 15292| Urgent Pointer: 0| +-------------------------+-------------------------+
執行結果(CentOS):
[root@tutu libpcap]# ./dump-tcp-and-udp Sniffing: eth0 No. 1 Time: 14:11:11.535115 Length: 74 bytes Capture length: 74 bytes Ethernet Frame: +-------------------------+-------------------------+-------------------------+ | Destination MAC Address: d8:fe:e3:a4:d3:78| +-------------------------+-------------------------+-------------------------+ | Source MAC Address: 6c:40:08:bc:ae:98| +-------------------------+-------------------------+-------------------------+ | Ethernet Type: 0x0800| +-------------------------+ Next protocol is IP Protocol: IP +-----+------+------------+-------------------------+ | IV:4| HL:20| T: --------| Total Length: 60| +-----+------+------------+-------+-----------------+ | Identifier: 1292| FF:---| FO: 0| +------------+------------+-------+-----------------+ | TTL: 64| Pro: 17| Header Checksum: 0xf221| +------------+------------+-------------------------+ | Source IP Address: 192.168.1.50| +---------------------------------------------------+ | Destination IP Address: 192.168.1.1| +---------------------------------------------------+ Next is UDP Protocol: UDP +-------------------------+-------------------------+ | Source Port: 62017| Destination Port: 53| +-------------------------+-------------------------+ | Length: 40| Checksum: 23279| +-------------------------+-------------------------+
Source code on Github
沒有留言:
張貼留言