- 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


沒有留言:
張貼留言