本文以笔者对libpcap用户名另编译和执行过程为主线,在libpcap源代码中进行挖掘,旨在记录当下本人对源代码阅读的思路和阅读代码过程中的整理和参考文献汇总。
TCPDUMP是允许用于命令行操作的网络数据包嗅探工具,其工作流程主要有两个部分:用户字符串命令解析(compile)、以及解析后指令下发至设备进行运作。通过参考tcpdump-4.3.0中tcpdump.c文件,发现其对用户字符串命令的解析过程通过调用libpcap库中的pcap_compile()函数来实现,具体如下所示,于是转战libpcap寻找用户命令解析和执行的真正所在。
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
error("%s", pcap_geterr(pd));
一、有关用户字符串指令解析为BPF指令过程
(1)pcap_compile()
首先定位到tcpdump调用的pcap_compile()函数位置,处于gencode.c文件中,具体格式如下所示:
int
pcap_compile(pcap_t *p, struct bpf_program *program,
const char *buf, int optimize, bpf_u_int32 mask)
{
int result;
EnterCriticalSection(&g_PcapCompileCriticalSection);
result = pcap_compile_unsafe(p, program, buf, optimize, mask);
LeaveCriticalSection(&g_PcapCompileCriticalSection);
return result;
}
这里先对pcap_compile()函数做一个解释,pcap_compile函数返回int类型值,由tcpdump.c中对pcap_compile()使用的情况可知,其返回值目的在于辨识该函数对用户命令的编译是否正确执行。该函数有五个参数,pcap_t 类型指针p、bpf_program结构指针program、指向字符串的指针buf、整型optimize和无符号整型mask。
参数一:pcap_t(即pcap)是贯穿libpcap各个函数的libpcap自定义结构体类型,其定义存在于pcap-int.h中,本人对该结构体设计原因的理解是:该结构体囊括了用于包过滤过程中所需要使用的所有参数,于是其先用于接受用户的包过滤命令并以pcap规定格式进行保存,后用于向下BPF内核包过滤命令解释器(很多部分会翻译成BPF虚拟机,但本人认为解释器一说更为贴切和易于理解)传递参数和向网络接口设备进行配置。
struct pcap {
#ifdef WIN32
ADAPTER *adapter;
LPPACKET Packet;
int nonblock;
#else
int fd;
int selectable_fd;
int send_fd;
#endif /* WIN32 */
#ifdef HAVE_LIBDLPI
dlpi_handle_t dlpi_hd;
#endif
int snapshot; //用户期望捕获数据包的最大长度
int linktype; /* Network linktype */
int linktype_ext; /* Extended information stored in the linktype field of a file */
int tzoff; /* timezone offset */
int offset; /* offset for proper alignment */
int activated; /* true if the capture is really started */
int oldstyle; /* if we're opening with pcap_open_live() */
int break_loop; /* flag set to force break from packet-reading loop */
#ifdef PCAP_FDDIPAD
int fddipad;
#endif
#ifdef MSDOS
void (*wait_proc)(void); /* call proc while waiting */
#endif
struct pcap_sf sf;
struct pcap_md md;
struct pcap_opt opt;
/*
* Read buffer.
*/
int bufsize;
u_char *buffer;
u_char *bp;
int cc;
/*
* Place holder for pcap_next().
*/
u_char *pkt;
/* We're accepting only packets in this direction/these directions. */
pcap_direction_t direction;
/*
* Methods.『?』
*/
activate_op_t activate_op;
can_set_rfmon_op_t can_set_rfmon_op;
read_op_t read_op;
inject_op_t inject_op;
setfilter_op_t setfilter_op;
setdirection_op_t setdirection_op;
set_datalink_op_t set_datalink_op;
getnonblock_op_t getnonblock_op;
setnonblock_op_t setnonblock_op;
stats_op_t stats_op;
/*
* Routine to use as callback for pcap_next()/pcap_next_ex().
*/
pcap_handler oneshot_callback;
#ifdef WIN32
/*
* These are, at least currently, specific to the Win32 NPF
* driver.
*/
setbuff_op_t setbuff_op;
setmode_op_t setmode_op;
setmintocopy_op_t setmintocopy_op;
#endif
cleanup_op_t cleanup_op;
/*
* Placeholder for filter code if bpf not in kernel.
*/
struct bpf_program fcode;
char errbuf[PCAP_ERRBUF_SIZE + 1]; //函数调用出错信息缓存
int dlt_count;
u_int *dlt_list;
int tstamp_type_count;
u_int *tstamp_type_list;
struct pcap_pkthdr pcap_header; /* This is needed for