linux c libpcap统计流量,libpcap流量统计
最近老師讓寫一個(gè)流量監(jiān)控程序,用到了libpcap編程。雖然很簡單,但是前期也走了一些彎路。最初是直接從別人博客里面copy的代碼,然后運(yùn)行時(shí)就是結(jié)果就是不正確。本以為是系統(tǒng)問題,我又裝了個(gè)雙系統(tǒng)。。。
現(xiàn)在我把自己的代碼分享出來吧,這些是我自己運(yùn)行成功的,代碼很簡單,只是希望能給新人一些借鑒。
首先:我們先得到我們的設(shè)備名稱,因?yàn)橹笪覀冃枰鶕?jù)名稱指針來打開我們的設(shè)備,得到名稱指針的方式如下:
/*get our device name*/
char *dev,errbuf[PCAP_ERRBUF_SIZE];
dev = pcap_lookupdev(errbuf);
printf("Device: %s\n",dev); /*print our device name*/
如果我們實(shí)現(xiàn)已經(jīng)知道設(shè)備名稱了,就不用在通過這個(gè)方式得到了。
得到名稱之后,我們根據(jù)名稱指針打開我們的設(shè)備,這時(shí)候我們需要用到的函數(shù)是:
/*pcap_t *pcap_open_dev(char*device,int snaplen,int promisc,int to_ms,char*errbuf);*/
device是設(shè)備名稱,snaplen是pcap將捕獲的最大字節(jié)數(shù),promisc是混合模式,to_ms是讀取時(shí)的超時(shí)值,單位是毫秒,為0則一直嗅探直到錯(cuò)誤發(fā)生,errbuf是出錯(cuò)之后信息的儲存。
函數(shù)的返回值是一個(gè)句柄,在下面我們將會使用的到。
/*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);
}
打開設(shè)備之后,我們設(shè)置過濾條件,過濾掉我們不想要的包。設(shè)置過濾涉及到兩個(gè)函數(shù):
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的第一個(gè)參數(shù)就是剛剛我們打開設(shè)備的返回值,后面是我們存儲被編譯的過濾器版本的地址的引用。
str是我們的過濾條件。比如"tcp port 21"是指只抓取來自tcp協(xié)議,并且端口是21的包。optimize是一個(gè)定義表達(dá)式是否被優(yōu)化的整形量,netmask是表示網(wǎng)絡(luò)掩碼。
pcap_setfilter則是用的都是pcap_compile里面已經(jīng)出現(xiàn)過的函數(shù)。
好,現(xiàn)在我們開始設(shè)置過濾:
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);
接下來我們就開始循環(huán)捕獲了,在這里我用到的函數(shù)是pcap_loop,下面是它的函數(shù)原型:
int pcap_loop(pcap_t *p,int cnt,pcap_hander callback,u_char *user)
其中:pcap_t還是我們的句柄,cnt是表示我們想要捕獲多少個(gè)數(shù)據(jù)包,如果值為-1,則表示一直捕獲,直到出錯(cuò)位置。pcap_hander則是我們回調(diào)函數(shù)的名稱,user是我們想發(fā)送給回調(diào)函數(shù)的參數(shù),如果沒有,那么設(shè)置成NULL;
pthread_attr_init(&attr);
pthread_create(&tid,&attr,runner,NULL);//這兩句是創(chuàng)建線程用的,為了每秒都顯示流量情況。
pcap_loop(open_dev,-1,got_packet,NULL);
pcap_close(open_dev);
got_packet()是用戶自定義的函數(shù),可以根據(jù)自己的需要定義。下面是我定義的:
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協(xié)議
tcp_count += len2;
}else if(ip->proto == (u_char)17){ //17是代表使用的udp協(xié)議
udp_count += len2;
}
count +=len2; //count是為了統(tǒng)計(jì)總流量寫的,在函數(shù)外面聲明的,同理udp_count,tcp_count
}
Ethernet ,Ip_header是定義的結(jié)構(gòu)體,這是為了進(jìn)一步解析抓到的數(shù)據(jù)包用的。下面是結(jié)構(gòu)體原型。(其中有些是直接網(wǎng)上copy的)
/* *以太網(wǎng)幀的首部 */
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; // 服務(wù)類型(Type of service)
u_short tlen; // 總長(Total length)
u_short identification; // 標(biāo)識(Identification)
u_short flags_fo; // 標(biāo)志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)
u_char ttl; // 存活時(shí)間(Time to live)
u_char proto; // 協(xié)議(Protocol)
u_short crc; // 首部校驗(yàn)和(Header checksum)
int saddr; // 源地址(Source address)
int daddr; // 目的地址(Destination address)
}Ip_header;
當(dāng)然,如果你想解析到更多的數(shù)據(jù),那么你可能還需要另tcp_heaer,和udp_header。如下:
/* UDP 首部*/
typedef struct udp_header{
u_short sport; // 源端口(Source port)
u_short dport; // 目的端口(Destination port)
u_short len; // UDP數(shù)據(jù)包長度(Datagram length),the minimum is 8
u_short crc; // 校驗(yàn)和(Checksum)
}Udp_header;
/*TCP首部*/
typedef struct tcp_header{
u_short sport;//源端口
u_short dPort;//目的端口
unsigned int SequNum;//序號
unsigned int AckNum;//確認(rèn)號
u_short sHeaderLenAndFlag;//數(shù)據(jù)偏移+保留+URG+ACK+RST+SYN+FIN
u_short WinSize;//窗口大小
u_short CheckSum;//檢驗(yàn)和
u_short urgentPointer;//緊急指針
}Tcp_header;
這里面的代碼是流量監(jiān)控的大部分,完整的代碼附件可以在這里下載,不需要積分。
http://download.csdn.net/detail/qq_27856623/9713803
編譯的時(shí)候需要
gcc my.c -lpcap -lpthread
運(yùn)行的時(shí)候需要sudo ./a.out
總結(jié)
以上是生活随笔為你收集整理的linux c libpcap统计流量,libpcap流量统计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ffplay flv mp4 转_ffm
- 下一篇: Php+debugbar+api,rea