linux c libpcap统计流量,libpcap流量统计

最近老师让写一个流量监控程序,用到了libpcap编程。虽然很简单,但是前期也走了一些弯路。最初是直接从别人博客里面copy的代码,然后运行时就是结果就是不正确。本以为是系统问题,我又装了个双系统。。。

现在我把自己的代码分享出来吧,这些是我自己运行成功的,代码很简单,只是希望能给新人一些借鉴。

首先:我们先得到我们的设备名称,因为之后我们需要根据名称指针来打开我们的设备,得到名称指针的方式如下:

/*get our device name*/

char *dev,errbuf[PCAP_ERRBUF_SIZE];

dev = pcap_lookupdev(errbuf);

printf("Device: %s\n",dev); /*print our device name*/

如果我们实现已经知道设备名称了,就不用在通过这个方式得到了。

得到名称之后,我们根据名称指针打开我们的设备,这时候我们需要用到的函数是:

/*pcap_t *pcap_open_dev(char*device,int snaplen,int promisc,int to_ms,char*errbuf);*/

device是设备名称,snaplen是pcap将捕获的最大字节数,promisc是混合模式,to_ms是读取时的超时值,单位是毫秒,为0则一直嗅探直到错误发生,errbuf是出错之后信息的储存。

函数的返回值是一个句柄,在下面我们将会使用的到。

/*open device and sniff

*pcap_t *pcap_open_dev(char*device,int snaplen,int promisc,int to_ms,char*errbuf);

*

*/

pcap_t * open_dev = pcap_open_live(dev,65535,1,0,errbuf);

if(!open_dev){

printf("open device failed: %s",errbuf);

}

打开设备之后,我们设置过滤条件,过滤掉我们不想要的包。设置过滤涉及到两个函数:

int pcap_compile(pcap_t *p,struct bpf_program *fp,char *str,int optimize,bpf_u_int32 netmask)

int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

pcap_compile的第一个参数就是刚刚我们打开设备的返回值,后面是我们存储被编译的过滤器版本的地址的引用。

str是我们的过滤条件。比如"tcp port 21"是指只抓取来自tcp协议,并且端口是21的包。optimize是一个定义表达式是否被优化的整形量,netmask是表示网络掩码。

pcap_setfilter则是用的都是pcap_compile里面已经出现过的函数。

好,现在我们开始设置过滤:

struct bpf_program filter;

char filter_exp[] = "port 80";/*filter expressiong*/

bpf_u_int32 mask; /*net mask*/

pcap_compile(open_dev,&filter,filter_exp,0,mask);

pcap_setfilter(open_dev,&filter);

接下来我们就开始循环捕获了,在这里我用到的函数是pcap_loop,下面是它的函数原型:

int pcap_loop(pcap_t *p,int cnt,pcap_hander callback,u_char *user)

其中:pcap_t还是我们的句柄,cnt是表示我们想要捕获多少个数据包,如果值为-1,则表示一直捕获,直到出错位置。pcap_hander则是我们回调函数的名称,user是我们想发送给回调函数的参数,如果没有,那么设置成NULL;

pthread_attr_init(&attr);

pthread_create(&tid,&attr,runner,NULL);//这两句是创建线程用的,为了每秒都显示流量情况。

pcap_loop(open_dev,-1,got_packet,NULL);

pcap_close(open_dev);

got_packet()是用户自定义的函数,可以根据自己的需要定义。下面是我定义的:

void got_packet(u_char *argv,const struct pcap_pkthdr *header,const u_char *packet){

int len2 = (int)header->caplen;

Ethernet *ethernet = (Ethernet *)(packet);

Ip_header *ip = (Ip_header *)(packet + sizeof(Ethernet));

if(ip->proto==(u_char)6){ //6是tcp协议

tcp_count += len2;

}else if(ip->proto == (u_char)17){ //17是代表使用的udp协议

udp_count += len2;

}

count +=len2; //count是为了统计总流量写的,在函数外面声明的,同理udp_count,tcp_count

}

Ethernet ,Ip_header是定义的结构体,这是为了进一步解析抓到的数据包用的。下面是结构体原型。(其中有些是直接网上copy的)

/* *以太网帧的首部 */

typedef struct ethernet{

u_char host1[6];

u_char host2[6];

u_short type;

}Ethernet;

/* IPv4 首部 */

typedef struct ip_header{

u_char ver_ihl; // 版本 (4 bits) + 首部长度 (4 bits)

u_char tos; // 服务类型(Type of service)

u_short tlen; // 总长(Total length)

u_short identification; // 标识(Identification)

u_short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)

u_char ttl; // 存活时间(Time to live)

u_char proto; // 协议(Protocol)

u_short crc; // 首部校验和(Header checksum)

int saddr; // 源地址(Source address)

int daddr; // 目的地址(Destination address)

}Ip_header;

当然,如果你想解析到更多的数据,那么你可能还需要另tcp_heaer,和udp_header。如下:

/* UDP 首部*/

typedef struct udp_header{

u_short sport; // 源端口(Source port)

u_short dport; // 目的端口(Destination port)

u_short len; // UDP数据包长度(Datagram length),the minimum is 8

u_short crc; // 校验和(Checksum)

}Udp_header;

/*TCP首部*/

typedef struct tcp_header{

u_short sport;//源端口

u_short dPort;//目的端口

unsigned int SequNum;//序号

unsigned int AckNum;//确认号

u_short sHeaderLenAndFlag;//数据偏移+保留+URG+ACK+RST+SYN+FIN

u_short WinSize;//窗口大小

u_short CheckSum;//检验和

u_short urgentPointer;//紧急指针

}Tcp_header;

这里面的代码是流量监控的大部分,完整的代码附件可以在这里下载,不需要积分。

http://download.youkuaiyun.com/detail/qq_27856623/9713803

编译的时候需要

gcc my.c -lpcap -lpthread

运行的时候需要sudo ./a.out

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值