日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libpcap抓取数据包

發布時間:2025/3/21 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libpcap抓取数据包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

libpcap是數據包捕獲函數庫。該庫提供的C函數接口可用于需要捕獲經過網絡接口數據包的系統開發上。libpcap提供的接口函數主要實現和封裝了與數據包截獲有關的過程。這個庫為不同的平臺提供了一致的編程接口,在安裝了libpcap的平臺上,以libpcap為接口寫的程序,能夠自由的跨平臺使用。

linux下libpcap的安裝:sudo apt-get install libpcap-dev

linux下gcc編譯程序:gcc my_pcap.c -lpcap

執行程序的時候如果報錯:no suitable device found,以管理員權限運行程序即可,sudo ./my_pcap

?

libpcap的抓包框架:

頭文件:?#include?<pcap.h> 在/usr/local/include/pcap目錄下

1.查找網絡設備

char *pcap_lookupdev(char *errbuf)?

該函數用于返回可被pcap_open_live()或pcap_lookupnet()函數調用的網絡設備名(一個字符串指針)。如果函數出錯,則返回NULL,同時errbuf中存放相關的錯誤消息。

2.獲得指定網絡設備的網絡號和掩碼

int pcap_lookupnet(char *device, bpf_u_int32 *netp,?bpf_u_int32 *maskp, char *errbuf)?

netp參數和maskp參數都是bpf_u_int32指針。如果函數出錯,則返回-1,同時errbuf中存放相關的錯誤消息。

Bpf_u_int32:32位無符號數

Struct in_addr

{

?? unsigned long s_addr;

}

inet_ntoa();以a.b.c.d的形式顯示地址。

3.打開網絡設備?

?pcap_t *pcap_open_live(char *device,? int snaplen,??int promisc, int to_ms, char *ebuf)?

獲得用于捕獲網絡數據包的數據包捕獲描述字。device參數為指定打開的網絡設備名。snaplen參數定義捕獲數據的最大字節數,65535是最大值。promisc指定 是否將網絡接口置于混雜模式,設置為1表示混雜模式。to_ms參數指定超時時間(毫秒),設置為0表示超時時間無限大。ebuf參數則僅在pcap_open_live()函數出錯返回NULL時用于傳遞 錯誤消息。

typedef struct pcap pcap_t;

pcap結構在libpcap源碼的pcap-int.h定義,使用時一般都是使用其指針類型)。

4.打開已有的網絡數據包 //如果是抓取數據包,這個過程不需要

pcap_t *pcap_open_offline(char *fname, char *errbuf)

fname參數指定打開的文件名。該文件中的數據格式與tcpdump兼容。errbuf參數則僅在pcap_open_offline()函數出錯返回NULL時用于傳遞錯誤消息。

pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf)打開文件指針。

5.編譯和設置過濾條件

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

設置過濾條件,舉一些例子:

  • src host 192.168.1.1:只接收源ip地址是192.168.1.1的數據包
  • dst port 80:只接收tcp、udp的目的端口是80的數據包
  • not tcp:只接收不使用tcp協議的數據包
  • tcp[13] == 0x02 and (dst port 22 or dst port 23) :只接收 SYN 標志位置位且目標端口是 22 或 23 的數據包( tcp 首部開始的第 13 個字節)
  • icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo:只接收 icmp 的 ping 請求和 ping 響應的數據包
  • ehter dst 00:e0:09:c1:0e:82:只接收以太網 mac 地址是 00:e0:09:c1:0e:82 的數據包
  • ip[8] == 5:只接收 ip 的 ttl=5 的數據包(ip首部開始的第8個字節)

str參數指定的字符串編譯到過濾程序中。fp是一個bpf_program結構的指針,在pcap_compile()函數中被賦值。optimize參數控制結果代碼的優化。netmask參數指定本地網絡的網絡掩碼,當不知道的時候可以設為0。出錯時返回-1.

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

指定一個過濾程序。fp參數是bpf_program結構指針,通常取自pcap_compile()函數調用。出錯時返回-1。

6.抓取和讀取數據包

int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, ?u_char *user)?

捕獲并處理數據包。cnt參數指定函數返回前所處理數據包的最大值。cnt=-1表示在一個緩沖區中處理所有的數據包。callback參數指定一個帶有三個參數的回調函數,這三個參數為:一個從 pcap_dispatch()函數傳遞過來的u_char指針,一個pcap_pkthdr結構的指針,和指向caplen大小的數據包的u_char指針。

struct pcap_pkthdr {?

???? struct tim ts;?? // ts是一個結構struct timeval,它有兩個部分,第一部分是1900開始以來的秒數,第二部分是當前秒之后的毫秒數

???? bpf_u_int32 caplen;? ? //表示抓到的數據長度

???? bpf_u_int32 len;? ? //表示數據包的實際長度

};?

user參數是留給用戶使用的,當callback被調用的時候這個值會傳遞給callback的第一個參數(也叫user)。

成功 則返回讀到的數據包數。返回0沒有抓到數據包。出錯時則返回-1,此時可調用pcap_perror()或pcap_geterr()函數獲取錯誤消息。返回-2表示調用了pcap_breakloop().?

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

功能基本與pcap_dispatch()函數類似,只不過此函數在cnt個數據包被處理或出現錯誤時才返回,但讀取超時不會返回。

u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h) ?

讀取下一個數據包,類似于pcap_dispatch()中cnt參數設為1,返回指向讀到的數據包的指針,但是不返回這個包的pcap_pkthdr結構的參數。

7.關閉文件釋放資源

void pcap_close(pcap_t *p)

關閉P指針。

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pcap.h> 4 5 #define PCAP_DATABUF_MAX 65535 6 7 #define ETHERTYPE_IPV4 0x0800 8 #define ETHERTYPE_IPV6 0x86DD 9 10 typedef unsigned char u_int8; 11 typedef unsigned short u_int16; 12 typedef unsigned int u_int32; 13 typedef unsigned long u_int64; 14 15 /*MAC頭,總長度14字節 */ 16 typedef struct _eth_hdr{ 17 u_int8 dst_mac[6]; 18 u_int8 src_mac[6]; 19 u_int16 eth_type; 20 }eth_hdr; 21 eth_hdr *ethernet; 22 23 /*IP頭*/ 24 typedef struct _ip_hdr{ 25 u_int8 ver_hl; //版本和頭長 26 u_int8 serv_type; //服務類型 27 u_int16 pkt_len; //包總長 28 u_int16 re_mark; //重組標志 29 u_int16 flag_seg; //標志位和段偏移量 30 u_int8 surv_tm; //生存時間 31 u_int8 protocol; //協議碼(判斷傳輸層是哪一個協議) 32 u_int16 h_check; //頭檢驗和 33 u_int32 src_ip; //源ip 34 u_int32 dst_ip; //目的ip 35 u_int32 option; //可選選項 36 }ip_hdr; 37 ip_hdr *ip; 38 39 /*TCP頭,總長度20字節,不包括可選選項*/ 40 typedef struct _tcp_hdr{ 41 u_int16 sport; //源端口 42 u_int16 dport; //目的端口 43 u_int32 seq; //序列號 44 u_int32 ack; //確認序號 45 u_int8 head_len; //頭長度 46 u_int8 flags; //保留和標記位 47 u_int16 wind_size; //窗口大小 48 u_int16 check_sum; //校驗和 49 u_int16 urgent_p; //緊急指針 50 }tcp_hdr; 51 tcp_hdr *tcp; 52 53 /*UDP頭,總長度8個字節*/ 54 typedef struct _udp_hdr{ 55 u_int16 sport; //源端口 56 u_int16 dport; //目的端口 57 u_int16 pktlen; //UDP頭和數據的總長度 58 u_int16 check_sum; //校驗和 59 }udp_hdr; 60 udp_hdr *udp; 61 62 //ip整型轉換點分十進制 63 char *InttoIpv4str(u_int32 num){ 64 char* ipstr = (char*)calloc(128, sizeof(char*)); 65 66 if (ipstr) 67 sprintf(ipstr, "%d.%d.%d.%d", num >> 24 & 255, num >> 16 & 255, num >> 8 & 255, num & 255); 68 else 69 printf("failed to Allocate memory..."); 70 71 return ipstr; 72 } 73 74 void pcap_callback(u_char *useless,const struct pcap_pkthdr *pkthdr, const u_char *packet) 75 { 76 printf("data len:%u\n", pkthdr->caplen); //抓到時的數據長度 77 printf("packet size:%u\n", pkthdr->len); //數據包實際的長度 78 79 /*解析數據鏈路層 以太網頭*/ 80 ethernet = (struct _eth_hdr*)packet; 81 u_int64 src_mac = ntohs( ethernet->src_mac ); 82 u_int64 dst_mac = ntohs( ethernet->dst_mac ); 83 84 printf("src_mac:%lu\n",src_mac); 85 printf("dst_mac:%lu\n",dst_mac); 86 printf("eth_type:%u\n",ethernet->eth_type); 87 88 u_int32 eth_len = sizeof(struct _eth_hdr); //以太網頭的長度 89 u_int32 ip_len; //ip頭的長度 90 u_int32 tcp_len = sizeof(struct _tcp_hdr); //tcp頭的長度 91 u_int32 udp_len = sizeof(struct _udp_hdr); //udp頭的長度 92 93 /*解析網絡層 IP頭*/ 94 if(ntohs(ethernet->eth_type) == ETHERTYPE_IPV4){ //IPV4 95 printf("It's IPv4!\n"); 96 97 ip = (struct _ip_hdr*)(packet + eth_len); 98 ip_len = (ip->ver_hl & 0x0f)*4; //ip頭的長度 99 u_int32 saddr = (u_int32)ntohl(ip->src_ip); //網絡字節序轉換成主機字節序 100 u_int32 daddr = (u_int32)ntohl(ip->dst_ip); 101 102 printf("eth_len:%u ip_len:%u tcp_len:%u udp_len:%u\n", eth_len, ip_len, tcp_len, udp_len); 103 104 printf("src_ip:%s\n", InttoIpv4str(saddr)); //源IP地址 105 printf("dst_ip:%s\n", InttoIpv4str(daddr)); //目的IP地址 106 107 printf("ip->proto:%u\n", ip->protocol); //傳輸層用的哪一個協議 108 109 /*解析傳輸層 TCP、UDP、ICMP*/ 110 if(ip->protocol == 6){ //TCP 111 tcp = (struct _tcp_hdr*)(packet + eth_len + ip_len); 112 printf("tcp_sport = %u\n", tcp->sport); 113 printf("tcp_dport = %u\n", tcp->dport); 114 115 /**********(pcaket + eth_len + ip_len + tcp_len)就是TCP協議傳輸的正文數據了***********/ 116 117 }else if(ip->protocol == 17){ //UDP 118 udp = (struct _udp_hdr*)(packet + eth_len + ip_len); 119 printf("udp_sport = %u\n", udp->sport); 120 printf("udp_dport = %u\n", udp->dport); 121 122 /**********(pcaket + eth_len + ip_len + udp_len)就是UDP協議傳輸的正文數據了***********/ 123 124 }else if(ip->protocol == 1){ //ICMP 125 126 } 127 128 }else if(ntohs(ethernet->eth_type) == ETHERTYPE_IPV6){ //IPV6 129 printf("It's IPv6!\n"); 130 } 131 132 printf("============================================\n"); 133 } 134 135 int main() 136 { 137 char *dev; //設備名 138 char errbuf[PCAP_ERRBUF_SIZE] = {}; //PCAP_ERRBUF_SIZE在pcap.h中已經定義 139 bpf_u_int32 netp, maskp; //網絡號和掩碼 140 pcap_t *handler; //數據包捕獲描述字 141 struct bpf_program *fp; 142 char *filter_str = "port 9000"; //過濾條件 143 144 /*Find network devices*/ 145 if((dev = pcap_lookupdev(errbuf)) == NULL){ 146 printf("lookupdev failed:%s\n", errbuf); 147 exit(1); 148 }else{ 149 printf("Device:%s\n", dev); 150 } 151 152 /*Get the network number and mask of the network device*/ 153 if(pcap_lookupnet(dev, &netp, &maskp, errbuf) == -1){ 154 printf("%s\n", errbuf); 155 exit(1); 156 } 157 158 /*Open network device*/ 159 if((handler = pcap_open_live(dev, PCAP_DATABUF_MAX, 1, 0, errbuf)) == NULL){ 160 printf("%s\n", errbuf); 161 exit(1); 162 } 163 164 /*Compiling and setting filtering conditions*/ 165 if(pcap_compile(handler, fp, filter_str, 0, maskp) == -1){ 166 printf("pcap_compile error...\n"); 167 exit(1); 168 } 169 if(pcap_setfilter(handler, fp) == -1){ 170 printf("pcap_setfilter error...\n"); 171 exit(1); 172 } 173 174 /*Capturing and processing data packets*/ 175 if(pcap_loop(handler, -1, pcap_callback, NULL) == -1){ 176 printf("pcap_loop error...\n"); 177 pcap_close(handler); 178 } 179 180 return 0; 181 }

?

轉載于:https://www.cnblogs.com/itsad/p/7885113.html

總結

以上是生活随笔為你收集整理的libpcap抓取数据包的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。