引用pcap.h,确认是否能正常用libpcap开发 int main(int argc, char *argv[])
printf("Device: %s\n", dev);
int main(int argc, char *argv[])
char *dev, errbuf[PCAP_ERRBUF_SIZE];
dev =
pcap_lookupdev(errbuf);
fprintf(stderr, "%s\n", errbuf);
printf("Device: %s\n", dev);
打开设备,返回一个pcap_t类型的“handle”。调用这个函数叫做“开启一个嗅探会话(sniffing session)” pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
device:pcap_lookupdev返回的设备名,类似ethx的字符串
errbuf[PCAP_ERRBUF_SIZE];
char* dev =
pcap_lookupdev(errbuf);
pcap_t* handle =
pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
pcap_t *p, 由pcap_open_live返回的“handle”
struct bpf_program *fp, 存放编译好的过滤器的数据结构
char *str, 过滤器表达式,如“port 23”
int optimize, 表达式是否需要被“优化”, 取值0或1
bpf_u_int32 netmask 有pcap_lookupnet函数获取的netmask
int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
pcap_t *handle; /* Session handle */
char dev[] = "rl0"; /* Device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
struct bpf_program fp; /* The compiled filter expression */
char filter_exp[] = "port 23"; /* The filter expression */
bpf_u_int32 mask; /* The netmask of our sniffing device */
bpf_u_int32 net; /* The IP of our sniffing device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Can't get netmask for device %s\n", dev);
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
if (
pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
if (
pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
struct pcap_pkthdr header; /* The header that pcap gives us */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
packet =
pcap_next(handle, &header);
调用上面的pcap_next函数可以得到header和packet 但是pcap_next只能抓一个包,libpcap提供了循环抓包的函数 pcap_t *p, //由pcap_open_live返回的“handle”
pcap_handler callback, //抓到包后的回调函数
u_char *user // 这个参数是用户自定义的,libpcap会自动将这个值传给回调函数
u_char *args, // 这个就是pcap_loop的最后一个参数u_char *user
const struct pcap_pkthdr *header,
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
packet是一个u_char*,执行一块数据,这块数据可以被转换为下面几个结构体 const struct sniff_ethernet /* The ethernet header */
const struct sniff_ip /* The IP header */
const struct sniff_tcp /* The TCP header */
const char *payload; /* Packet payload */
这些数据结构介绍如下packet其实就是包头的二进制内容,因此结构体需要按包头的格式编排各变量的大小和顺序,然后强制类型转换即可。 下面的结构体来自tcpdump官网的文章。 /* Ethernet addresses are 6 bytes */
u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
将u_char *packet转换成这些结构体的方法: const struct sniff_ethernet *ethernet; /* The ethernet header */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const char *payload; /* Packet payload */
ethernet = (struct sniff_ethernet*)(packet); // 先是链路层的头 ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); // 链路层头的后面是变长的ip包头 size_ip = IP_HL(ip)*4; // IP_HL这个宏的作用是去ip头第一个字节的后4位,这4位表示IP头的长度,单位是4byte printf(" * Invalid IP header length: %u bytes\n", size_ip);
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip); // 再后面是tcp包头 size_tcp = TH_OFF(tcp)*4;
printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp); Variable | Location (in bytes) |
sniff_ethernet | X |
sniff_ip | X + SIZE_ETHERNET |
sniff_tcp | X + SIZE_ETHERNET + {IP header length} |
payload | X + SIZE_ETHERNET + {IP header length} + {TCP header length} |
[root@localhost cc]# cat cap.c
char errbuf[PCAP_ERRBUF_SIZE];
int addr_ntoa(int i_addr, char* str_addr)
char* tmp = inet_ntoa(addr);
int errstr(int ret, char* str)
if(str != NULL) fprintf(stderr, "%s\n", str);
void got_packet(u_char* args, const struct pcap_pkthdr* header, const u_char* packet)
const struct sniff_ethernet *ethernet;
const struct sniff_ip *ip;
const struct sniff_tcp *tcp;
ethernet = (struct sniff_ethernet*)(packet);
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
if((size_ip = IP_HL(ip)*4) < 20) return;
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
if((size_tcp = TH_OFF(tcp)*4) < 20) return;
addr_ntoa(ip->ip_src.s_addr, ip_src);
addr_ntoa(ip->ip_dst.s_addr, ip_dst);
printf("%s:%d>> %s:%d\n", ip_src, ntohs(tcp->th_sport), ip_dst, ntohs(tcp->th_dport));
struct ether_header *eptr = (struct ether_header *) packet;
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
struct tm* local = localtime(&(header->ts));
printf("time: %d:%d:%d\n",local->tm_hour,local->tm_min,local->tm_sec);
printf("package length: %d\n", header->len);
printf("TTL: %d\n", ip->ip_ttl);
if ((dev = pcap_lookupdev(errbuf)) == NULL) err(-1);
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) err(-1);
addr_ntoa(mask, strmask);
printf("\nMonitoring: %s/%s/%s\n\n", dev, strnet, strmask);
if((handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf)) == NULL) err(-1);
if((pcap_loop(handle, 10, got_packet, "test1")) < 0) err(-1);
头文件里的结构体来自tcpdump官网的文章,其实就是按照包头的格式设置变量大小和顺序。 [root@localhost cc]# cat cap.h
#include <netinet/if_ether.h>
#include <net/ethernet.h>
/* Ethernet addresses are 6 bytes */
//#define ETHER_ADDR_LEN 6
u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
[root@localhost cc]# ./cap
Monitoring: enp0s8/192.168.1.0/255.255.255.0
192.168.1.66:22>> 192.168.1.1:52672
src MAC: [ 8:0:27:80:ff:b0]
dest MAC: [ a:0:27:0:0:0]
192.168.1.1:52672>> 192.168.1.66:22
dest MAC: [ 8:0:27:80:ff:b0]
192.168.1.66:22>> 192.168.1.1:52672
src MAC: [ 8:0:27:80:ff:b0]
dest MAC: [ a:0:27:0:0:0]
192.168.1.66:22>> 192.168.1.1:52672
src MAC: [ 8:0:27:80:ff:b0]
dest MAC: [ a:0:27:0:0:0]
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26239116/viewspace-2058238/,如需转载,请注明出处,否则将追究法律责任。