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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tcpdump源码分析——抓包原理

發(fā)布時間:2024/1/23 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tcpdump源码分析——抓包原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本篇我們從總體看下tcpdump工具的抓包原理,通過學(xué)習(xí)了解并掌握其實現(xiàn)的機制,為后續(xù)進一步底層操作做準(zhǔn)備。

1.1.1.1??如何實現(xiàn)
先來看看包傳遞過來的流程,如下圖。包從網(wǎng)卡到內(nèi)存,到內(nèi)核態(tài),最后給用戶程序使用。我們知道tcpdump程序運行在用戶態(tài),那如何實現(xiàn)從內(nèi)核態(tài)的抓包呢?

這個就是通過libpcap庫來實現(xiàn)的,tcpdump調(diào)用libpcap的api函數(shù),由libpcap進入到內(nèi)核態(tài)到鏈路層來抓包,如下圖。圖中的BPF是過濾器,可以根據(jù)用戶設(shè)置用于數(shù)據(jù)包過濾減少應(yīng)用程序的數(shù)據(jù)包的包數(shù)和字節(jié)數(shù)從而提高性能。BufferQ是緩存供應(yīng)用程序讀取的數(shù)據(jù)包。我們可以說tcpdump底層原理其實就是libpcap的實現(xiàn)原理。

而libpcap在linux系統(tǒng)鏈路層中抓包是通過PF_PACKET套接字來實現(xiàn)的(不同的系統(tǒng)其實現(xiàn)機制是由差異的),該方法在創(chuàng)建的時候,可以指定第二參數(shù)為SOCK_DGRAM或者SOCK_RAW,影響是否扣除鏈路層的首部。

????????????libpcap在內(nèi)核收發(fā)包的接口處將skb_clone()拿走的包.

關(guān)于內(nèi)核中如何注冊網(wǎng)絡(luò)協(xié)議和鉤子函數(shù)的過程,此處先不展開,后續(xù)專門講解。我們接下去是看下libpcap的一些實現(xiàn)及其api.

1.1.1.2??libpcap
當(dāng)在系統(tǒng)中輸入tcpdump –version的時候,輸出的其實還有l(wèi)ibpcap,足見其在tcpdump中的地位。

????????????其實最早的編譯系統(tǒng)和過濾引擎是在tcpdump項目中的,后來為了編譯其他抓包的應(yīng)用,將其獨立出來。現(xiàn)在libpcap提供獨立于平臺的庫和API,來滿足執(zhí)行網(wǎng)絡(luò)嗅探。

tcpdump.c正式使用libpcap里的函數(shù)完成兩個最關(guān)鍵的動作:獲取捕獲報文的接口,和捕獲報文并將報文交給callback。

libpcap支持“伯克利包過濾(BPF)”語法。BPF能夠通過比較第2、3、4層協(xié)議中各個數(shù)據(jù)字段值的方法對流量進行過濾。Libpcap的使用邏輯如下圖:

如果愿意,大家也可以基于libpcap開發(fā)一個類似tcpdump的抓包工具。需要注意的是如果使用分組捕獲設(shè)備,只能在單個接口上接收到達(dá)的分組。

1.1.1.3??核心函數(shù)
我們先來看下libpcap中的一些核心函數(shù),根據(jù)函數(shù)的功能,可以分為如下幾類:

? ?(1)? 為讀包打開句柄

? ?(2)? 為抓包選擇鏈路層

? ?(3) 抓包函數(shù)

? ?(4) 過濾器

? ?(5) 選定抓包方向(進還是出)

? ?(6) 抓統(tǒng)計信息

? ?(7) 將包寫入文件打開句柄

? ?(8) 寫包

? ?(9) 注入包

? ?(10) 報告錯誤

? ?(11)? 獲取庫版本信息

官方的介紹查看http://www.tcpdump.org/manpages/pcap.3pcap.html

常用的一些函數(shù)如下:

pcap_lookupdev,如果分組捕獲設(shè)備未曾指定(-i命令行選項),該函數(shù)選擇一個設(shè)備。

pcap_open_offine打開一個保存的文件。

pcap_setfilter設(shè)置過濾器

pcap_open_live打開選擇的設(shè)備。

pcap_next接收一個包

pcap_dump將包寫入到pcap_dump_t結(jié)構(gòu)體

pcap_loopupnet返回分組捕獲設(shè)備的網(wǎng)絡(luò)地址和子網(wǎng)掩碼,然后在調(diào)用pcap_compile時必須指定這個子網(wǎng)掩碼。

pcap_compile把cmd字符數(shù)組中構(gòu)造的過濾器字符串編譯成一個過濾器程序,存放在fcode中。

pcap_setfilter把編譯出來的過濾器程序裝載到分組捕獲設(shè)備,同時引發(fā)用該過濾器選取的分組的捕獲。

pcap_datalink返回分組捕獲設(shè)備的數(shù)據(jù)鏈路類型。

等等,那么如何去使用libpcap庫呢,一起來看下。

1.1.1.4??使用準(zhǔn)備
先在系統(tǒng)中安裝pcap-dev包(apt-get install pcap-dev),然后創(chuàng)建一個test.c文件如下:

#include <stdio.h> #include <pcap.h>int main (int argc, char *argv[]) {char *dev, errbuf[PCAP_ERRBUF_SIZE];dev = pcap_lookupdev (errbuf);if (dev == NULL){fprintf (stderr, "Couldn't find default device: %s\n", errbuf);return (2);}printf ("Device: %s\n", dev);return (0); }

? ?然后編譯如下:

gcc test.c -lpcap -lpthread

?就可以執(zhí)行了,在系統(tǒng)中尋找一個可以抓包的接口。

?有了接口設(shè)備,可以繼續(xù)創(chuàng)建嗅探會話了,使用函數(shù)

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

其中snaplen是pcap抓包的字節(jié)數(shù),?promisc?是否啟用混雜模式(不是混雜模式的話就只抓給本機的包。),to_ms是否超時,ebuf存放錯誤信息。

??????創(chuàng)建了嗅探會話之后,就要一個過濾器。可以只提取我們想要的數(shù)據(jù)。過濾器在應(yīng)用之前必須要先編譯,調(diào)用函數(shù)如下:

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

第一個參數(shù)就是pcap_open_live返回的值,fp 存儲的過濾器的版本,optimize是表示是否需要優(yōu)化,最后netmask是過濾器使用的所在子網(wǎng)掩碼。

? ? ? 有了過濾器之后就是要使用編譯器,調(diào)用函數(shù):

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

??到此整個代碼流程參考如下代碼段:

#include <pcap.h>...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);net = 0;mask = 0;}handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);if (handle == NULL) {fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);return(2);}if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));return(2);}if (pcap_setfilter(handle, &fp) == -1) {fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));return(2);}

?

1.1.1.5??開始抓包

已經(jīng)準(zhǔn)備好監(jiān)聽抓包,并設(shè)置了過濾器,下面就是啟動抓包了。

抓包技術(shù)有兩種,一種是一次抓一個包;另一種是等待有n個包的時候在一起抓。

??????????? 先看抓一次抓一個包,使用函數(shù)如下:

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

?

? 第一個參數(shù)就是創(chuàng)建的會話句柄,第二個參數(shù)是存放包信息的。

??????????? 這個函數(shù)是比較少用的,現(xiàn)在大多數(shù)抓包工具都是使用第二種技術(shù)抓包的,其用到的函數(shù)就是:

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

?第一個參數(shù)是創(chuàng)建的會話句柄,第二個參數(shù)是數(shù)量(抓幾個包),就是這個參數(shù)制定抓多少包,抓完就結(jié)束了,第三個函數(shù)是抓到足夠數(shù)量后的回調(diào)函數(shù),每次抓到都會調(diào)用回調(diào)函數(shù),第四個參數(shù)經(jīng)常設(shè)置為NULL,在一些應(yīng)用中會有用。

????????????和pcap_loop函數(shù)類似的是pcap_dispatch,兩者用法基本一致,主要差異是pcap_dispatch只會執(zhí)行一次回調(diào)函數(shù),而pcap_loop會一直調(diào)用回調(diào)函數(shù)處理包。

????????????其回調(diào)函數(shù)的定義如下:

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

? ???是void型的,第一個參數(shù)args是pcap_loop函數(shù)的最后一個參數(shù),第二個參數(shù)是pcap的頭其包含了抓住的包的信息,第三個就是包本身了。

struct pcap_pkthdr {struct timeval ts; /* time stamp */bpf_u_int32 caplen; /* length of portion present */bpf_u_int32 len; /* length this packet (off wire) */ };

關(guān)于包本身其實是一個字符串指針,怎么去尋找我的ip頭,tcp頭,以及頭中的內(nèi)容呢?這就需要是使用C語言中異常強大的指針了,定義一個宏如下:

/* Ethernet addresses are 6 bytes */ #define ETHER_ADDR_LEN????? 6/* Ethernet header */struct sniff_ethernet {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 */};/* IP header */struct sniff_ip {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)/* TCP header */typedef u_int tcp_seq;struct sniff_tcp {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)u_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)u_short th_win;????????????? /* window */u_short th_sum;???????????? /* checksum */u_short th_urp;???????????? /* urgent pointer */ };/* ethernet headers are always exactly 14 bytes */ #define SIZE_ETHERNET 14const 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 */u_int size_ip;u_int size_tcp;

通過以上結(jié)構(gòu)體定義,可以從回調(diào)函數(shù)的包指針地址出發(fā),逐個找到鏈路幀頭、IP幀頭、TCP幀頭、數(shù)據(jù)負(fù)載了。

附上一個實例DEMO鏈接。實例DEMO

轉(zhuǎn)載地址:https://blog.csdn.net/notbaron/article/details/79735414

總結(jié)

以上是生活随笔為你收集整理的tcpdump源码分析——抓包原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 免费视频爱爱太爽 | 蜜桃传媒一区二区亚洲av | 免费成年人视频在线观看 | 国产高清视频 | 激情五月开心婷婷 | 黄色免费看片 | 国产一区资源 | 日本三不卡 | 国产亚洲精品精品国产亚洲综合 | 亚洲成人午夜在线 | 少妇搡bbbb搡bbb搡澳门 | 欧美 日韩 视频 | 天堂在线观看中文字幕 | 国产国产国产 | 成人黄色免费网 | 一本大道熟女人妻中文字幕在线 | 秋霞视频在线 | 久久涩视频 | 亚洲av永久无码精品一百度影院 | 久久久99精品国产一区二区三区 | 国产男男chinese网站 | 亚洲精品一区二区三区蜜桃久 | 欧美久久久久久久久久久久久久 | 亚州福利 | 快射视频网 | 精品国产一区在线 | 日批免费网站 | 蜜臀久久99精品久久久久宅男 | 韩国特级毛片 | 顶臀精品视频www | 91香蕉视频污污 | 国产原创在线播放 | 国产无遮挡a片又黄又爽 | 亚洲综合在线第一页 | 黑人100部av解禁片 | 波多野结衣办公室33分钟 | 久久精品第一页 | 国产成人精品国内自产拍免费看 | 91丝袜一区二区三区 | 一区二区三区免费观看视频 | 91超碰在线免费观看 | 激情五月激情综合 | 亚洲精品一区三区三区在线观看 | 成年人视频在线免费观看 | 日韩av在线看免费观看 | 女生的胸无遮挡 | av最新地址 | www.com久久| 久久精品国产成人av | 国产a视频 | 日韩午夜影院 | 动漫av在线 | 成人一二区 | 欧美做受高潮中文字幕 | 91免费国产视频 | 牛av| 中文在线字幕免费观看 | 成人av动漫在线观看 | 一区二区三区日韩精品 | 天天操操操操操 | 欧美福利影院 | 欧美激情国产精品 | 亚洲在线精品视频 | 小h片在线观看 | 伊人成综合 | 亚洲成熟少妇 | 无码精品a∨在线观看中文 福利片av | 不卡av免费| 亚洲激情六月 | 国产夫妻性爱视频 | 亚洲国产综合网 | www.国产一区二区三区 | 瑟瑟视频免费看 | 涩涩视频在线免费看 | 九九免费| 黄色一级毛片 | 国产精品久久国产 | 欧美激情一区二区三区p站 欧美mv日韩mv国产网站app | 成人激情视频在线播放 | 91免费观看视频在线 | 每日在线更新av | h网址在线观看 | 国产人妖在线观看 | 亚洲va视频 | 久久嗨| 大又大粗又爽又黄少妇毛片 | 日韩精品在线观看网站 | 亚洲欧美另类在线视频 | 国产三级av在线播放 | 亚洲视频一区二区三区在线观看 | 日韩一区二区免费看 | 午夜激情福利视频 | 国产亚韩 | 久久精品国产亚洲a | 一区二区三区视频播放 | 精品人妻一区二区色欲产成人 | 色七七桃花综合影院 | 成人手机av | 牛牛在线|