使用libpcap和tcpdump抓包

參考

tcpdump & libpcap官網
使用PCAP獲取數據包納秒(ns)級精度的時間戳(timestamp)
tcpdump/libpcap中捕獲數據包的時間戳
基於libpcap多網卡抓包編程心得
在LINUX系統下使用libpcap,一些流程
Python-對Pcap文件進行處理,獲取指定TCP流
PCAP文件格式分析(做抓包軟件之必備)

pcap文件格式

Pcap文件頭24B各字段說明:

  • Magic:4B:0x1A 2B 3C 4D:用來標示文件的開始
  • Major:2B,0x02 00:當前文件主要的版本號
  • Minor:2B,0x04 00當前文件次要的版本號
  • ThisZone:4B當地的標準時間;全零
  • SigFigs:4B時間戳的精度;全零
  • SnapLen:4B最大的存儲長度
  • LinkType:4B鏈路類型

常用類型:

  • 0 BSD loopback devices, except for later OpenBSD
  • 1 Ethernet, and Linux loopback devices
  • 6 802.5 Token Ring
  • 7 ARCnet
  • 8 SLIP
  • 9 PPP
  • 10 FDDI
  • 100 LLC/SNAP-encapsulated ATM
  • 101 “raw IP”, with no link
  • 102 BSD/OS SLIP
  • 103 BSD/OS PPP
  • 104 Cisco HDLC
  • 105 802.11
  • 108 later OpenBSD loopback devices (with the AF_value in network byte order)
  • 113 special Linux “cooked” capture
  • 114 LocalTalk

Packet 包頭和Packet數據組成

字段說明:
Timestamp:時間戳高位,精確到seconds
Timestamp:時間戳低位,精確到microseconds
Caplen:當前數據區的長度,即抓取到的數據幀長度,由此可以得到下一個數據幀的位置。
Len:離線數據長度:網絡中實際數據幀的長度,一般不大於caplen,多數情況下和Caplen數值相等。
Packet 數據:即 Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的後面,就是當前PCAP文件中存放的下一個Packet數據包,PCAP文件裏面並沒有規定捕獲的Packet數據包之間有什麼間隔字符串,下一組數據在文件中的起始位置,我們需要靠第一個Packet包確定。

使用

先編譯libpcap,這裏交叉編譯,用於arm平臺,

./configure --host=arm-xilinx-linux-gnueabi --prefix=$cur_path/zynq-$PETALINUX_VER

同樣方法,交叉編譯tcpdump,可以自動發現libpcap,採用靜態編譯的庫,可直接拷貝到板卡運行,

...
checking for local pcap library... ../libpcap-1.9.0/libpcap.a
checking for pcap-config... ../libpcap-1.9.0/pcap-config
...

包格式

pcap文件的包格式,caplen爲捕獲到長度,len爲數據包原始長度,也就是說caplen可能比len小,struct timeval在這裏長度爲64字節。

/*
 * Generic per-packet information, as supplied by libpcap.
 *
 * The time stamp can and should be a "struct timeval", regardless of
 * whether your system supports 32-bit tv_sec in "struct timeval",
 * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit
 * and 64-bit applications.  The on-disk format of savefiles uses 32-bit
 * tv_sec (and tv_usec); this structure is irrelevant to that.  32-bit
 * and 64-bit versions of libpcap, even if they're on the same platform,
 * should supply the appropriate version of "struct timeval", even if
 * that's not what the underlying packet capture mechanism supplies.
 */
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) */
};

libpcap-1.9.0tcpdump-4.9.2支持設置時間精度爲毫秒或者納秒,左邊毫秒,右邊納秒,
181
代碼,

// libpcap-1.9.0\pcap\pcap.h line404
/*
 * Time stamp resolution types.
 * Not all systems and interfaces will necessarily support all of these
 * resolutions when doing live captures; all of them can be requested
 * when reading a savefile.
 */
#define PCAP_TSTAMP_PRECISION_MICRO	0	/* use timestamps with microsecond precision, default */
#define PCAP_TSTAMP_PRECISION_NANO	1	/* use timestamps with nanosecond precision */

// tcpdump-4.9.2\tcpdump.c line945
static pcap_t *
open_interface(const char *device, netdissect_options *ndo, char *ebuf)
{
...
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
	status = pcap_set_tstamp_precision(pc, ndo->ndo_tstamp_precision);
	if (status != 0)
		error("%s: Can't set %ssecond time stamp precision: %s",
			device,
			tstamp_precision_to_string(ndo->ndo_tstamp_precision),
			pcap_statustostr(status));
#endif
...
}
// tcpdump-4.9.2\tcpdump.c line1495 main
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
		case OPTION_TSTAMP_PRECISION:
			ndo->ndo_tstamp_precision = tstamp_precision_from_string(optarg);
			if (ndo->ndo_tstamp_precision < 0)
				error("unsupported time stamp precision");
			break;
#endif

遍歷網卡

代碼,

	char errbuf[PCAP_ERRBUF_SIZE];//存放錯誤信息的緩衝
	pcap_if_t *it;
	int r;
	
	r=pcap_findalldevs(&it,errbuf);
 	if(r < 0) {
	  printf("err:%s\n",errbuf);
	  return r;
	}
	
	while(it) {
	  printf(":%s\n",it->name);
	  it=it->next;
	}

	pcap_freealldevs(it);

其中pcap_if_tname成員用於pcap_open_live函數,

/*
 * Item in a list of interfaces.
 */
struct pcap_if {
	struct pcap_if *next;
	char *name;		/* name to hand to "pcap_open_live()" */
	char *description;	/* textual description of interface, or NULL */
	struct pcap_addr *addresses;
	bpf_u_int32 flags;	/* PCAP_IF_ interface flags */
};

過濾

只抓數據部分:src host 192.168.6.6 and src port 8080 and tcp[tcpflags] & (tcp-push) != 0

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

字符串str是過濾參數,program參數是一個指向bpf_program結構體的指針,optimize參數用於控制是否採用最優化的結果,netmask用於指定IPv4的網絡子網掩碼,這個參數僅僅在檢查過濾程序中的IPv4廣播地址時纔會使用。

struct bpf_program filter;
pcap_compile(fip->nic, &filter, fip->filter, 1, 0);
pcap_setfilter(fip->nic, &filter);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章