⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 544.htm

📁 unix高级编程原吗
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>apue</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center">               ● UNIX网络编程                       (BM: clown)                </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p   align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="516.htm">上一层</a>][<a href="545.htm">下一篇</a>]
<hr><p align="left"><small>发信人: scz (小四), 信区: Security <br>

标  题: libpcap使用举例(1) <br>

发信站: 武汉白云黄鹤站 (Mon Jan 15 20:26:32 2001), 站内信件 <br>

作者:小四 < mailto: scz@nsfocus.com > <br>

主页:http://www.nsfocus.com <br>

日期:2000-12-14 20:10 <br>

我们曾经提供过<<libnet使用举例(1-12)>>,比较详细地介绍了报文发送编程。始终 <br>

没有介绍libpcap报文捕捉编程的原因很多,tcpdump、snort等著名软件包都是基于 <br>

libpcap,加上W.Richard.Stevens的<<Unix Network Programming Vol I>>第26章推 <br>

波助澜,实在觉得没有必要继续介绍libpcap编程。更真实的原因可能是BPF、DLPI、 <br>

SOCK_PACKET三种接口编程已经被演练得太多太滥。 <br>

今天讨论的不是效率,而是可能的移植性要求。没办法,第一次使用libpcap库,举 <br>

例能深入到什么地步,不知道。如果你也是 一次用这个库,跟我来,第N次使用? <br>

那还是忙你的去吧,别来看这篇无聊的灌水,:-P。我无聊是因为有程序要广泛可移 <br>

植,你无聊是为什么。 <br>

char * pcap_lookupdev ( char * errbuf ); <br>

该函数返回一个网络设备接口名,类似libnet_select_device(),对于Linux就是 <br>

"eth0"一类的名字。pcap_open_live()、pcap_lookupnet()等函数将用到这个网络设 <br>

备接口名。失败时返回NULL,errbuf包含了失败原因。errbuf一般定义如下: <br>

/usr/include/pcap.h <br>

#define PCAP_ERRBUF_SIZE 256 <br>

char errbuf[ PCAP_ERRBUF_SIZE ]; <br>

pcap_t * pcap_open_live ( char * devce, int snaplen, int promisc, <br>



                          int to_ms, char * errbuf ); <br>

该函数用于获取一个抽象的包捕捉句柄,后续很多libpcap函数将使用该句柄,类似 <br>

文件操作函数频繁使用文件句柄。device指定网络接口设备名,比如"eth0。snaplen <br>

指定单包最大捕捉字节数,为了保证包捕捉不至于太低效率,snaplen尽量适中,以 <br>

恰能获得所需协议层数据为准。promisc指定网络接口是否进入混杂模式,注意即使 <br>

该参数为false(0),网络接口仍然有可能因为其他原因处在混杂模式。to_ms指定毫 <br>

秒级读超时,man手册上并没有指明什么值意味着永不超时,测试下来的结论,0可能 <br>

代表永不超时。 <br>

{ <br>

2000-12-18 11:40 <br>

刚才用Source Insight跟踪源代码,确认0代表不设置超时机制,而且只有BPF、DLPI <br>

支持超时机制,SOCK_PACKET本身不支持超时机制,所以对于Linux平台,to_ms为多 <br>

少都无所谓 <br>

} <br>

如果调用失败返回NULL,errbuf包含失败原因。 <br>

-------------------------------------------------------------------------- <br>

/usr/include/pcap.h <br>

typedef struct pcap pcap_t; <br>

pcap-int.h里定义了struct pcap {} <br>

struct pcap <br>

{ <br>

    int               fd; <br>



    int                snapshot; <br>

    int                linktype; <br>

    int                tzoff;    /* timezone offset <br>

      */ <br>

    int                offset;   /* offset for proper alignment <br>

      */ <br>

    struct pcap_sf     sf; <br>

    struct pcap_md     md; <br>

    int                bufsize;  /* Read buffer <br>

      */ <br>

    u_char *           buffer; <br>

    u_char *           bp; <br>

    int                cc; <br>

    u_char *           pkt;      * Place holder for pcap_next() <br>

     */ <br>

    struct bpf_program fcode;    /* Placeholder for filter code if bpf not i <br>

n ke <br>

rnel. */ <br>

    char               errbuf[PCAP_ERRBUF_SIZE]; <br>

}; <br>

-------------------------------------------------------------------------- <br>

int pcap_lookupnet ( char * device, bpf_u_int32 * netp, <br>



                     bpf_u_int32 * maskp, char * errbuf ); <br>

该函数用于获取指定网络接口的IP地址、子网掩码。不要被netp的名字所迷惑,它对 <br>

应的就是IP地址,maskp对应子网掩码。 <br>

/usr/include/pcap.h <br>

typedef u_int bpf_u_int32; <br>

显然简单理解成32-bit即可。如果调用失败则返回-1,errbuf包含失败原因。 <br>

int pcap_compile ( pcap_t * p, struct bpf_program * fp, char * str, <br>

                   int optimize, bpf_u_int32 netmask ); <br>

该函数用于解析过滤规则串,填写bpf_program结构。str指向过滤规则串,格式参看 <br>

tcpdump的man手册,比如: <br>

tcpdump -x -vv -n -t ip proto \\tcp and dst 192.168.8.90 and tcp[13] \& 2 = <br>

2 <br>

这条过滤规则将捕捉所有携带SYN标志的到192.168.8.90腡CP报文。过滤规则串可以 <br>

是空串(""),表示抓取所有过路的报文。 <br>

optimize为1表示对过滤规则进行优化处理。netmask指定子网掩码,一般从 <br>

pcap_lookupnet()调用中获取。返回值小于零表示调用失败。 <br>

这个函数可能比较难于理解,涉及的概念源自BPF,Linux系统没有这种概念,但是 <br>

libpcap采用pcap_compile()和pcap_setfilter()结合的办法屏蔽了各种链路层支持 <br>

的不同,无论是SOCK_PACKET、DLPI。曾在华中Security版上写过一篇 <br>

<<内核包捕获过滤机制介绍>>,参看该文加强理解。 <br>

------------------------------------------------------------------------- <br>

# tcpdump -d ip proto \\tcp and dst 192.168.8.90 and tcp[13] \& 2 = 2 <br>



(000) ldh      [-4096] <br>

(001) jeq      #0x800           jt 2    jf 13 <br>

(002) ldb      [9] <br>

(003) jeq      #0x6             jt 4    jf 13 <br>

(004) ld       [16] <br>

(005) jeq      #0xc0a8085a      jt 6    jf 13 <br>

(006) ldh      [6] <br>

(007) jset     #0x1fff          jt 13   jf 8 <br>

(008) ldxb     4*([0]&0xf) <br>

(009) ldb      [x + 13] <br>

(010) and      #0x2 <br>

(011) jeq      #0x2             jt 12   jf 13 <br>

(012) ret      #65535 <br>

(013) ret      #0 <br>

# <br>

/usr/include/net/bpf.h <br>

/* Structure for BIOCSETF. */ <br>

struct bpf_program <br>

{ <br>

    u_int             bf_len; <br>

    struct bpf_insn * bf_insns; <br>

}; <br>

}; <br>

/* <br>

 * The instruction data structure. <br>

 */ <br>

struct bpf_insn <br>

{ <br>

    u_short   code; <br>

    u_char    jt; <br>

    u_char    jf; <br>

    bpf_int32 k; <br>

}; <br>

/* <br>

 * Macros for insn array initializers. <br>

 */ <br>

#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } <br>

#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } <br>

------------------------------------------------------------------------- <br>

int pcap_setfilter ( pcap_t * p, struct bpf_program * fp ); <br>

该函数用于设置pcap_compile()解析完毕的过滤规则,如果你足够聪明(愚公?),完 <br>

全可以自己提供过滤规则,无须pcap_compile()介入,就象你写 <br>

Password Sniffer For I386/FreeBSD时常做的那样。成功返回0,失败返回-1。 <br>

int pcap_dispatch ( pcap_t * p, int cnt, pcap_handler callback, u_char * use <br>

r ); <br>

r ); <br>

该函数用于捕捉报文、分发报文到预先指定好的处理函数(回调函数)。 <br>

pcap_dispatch()接收够cnt个报文便返回,如果cnt为-1 味着所有报文集中在一 <br>

  缓冲 <br>

区中。如果cnt为0,仅当发生错误、读取到EOF或者读超时到了(pcap_open_live <br>

中指定)才停止捕捉报文并返回。callback指定如下类型的回调函数,用于处理 <br>

pcap_dispatch()所捕获的报文: <br>

typedef void ( *pcap_handler ) ( u_char *, const struct pcap_pkthdr *, const <br>

 u_c <br>

har * ); <br>

pcap_dispatch()返回捕捉到的报文个数,如果在读取静态文件(以前包捕捉过程中存 <br>

储下来的)时碰到EOF则返回0。返回-1表示发生错误,此时可以用pcap_perror()、 <br>

pcap_geterr()显示错误信息。 <br>

下面来看看那个回调函数,总共有三个参数,第一个形参来自pcap_dispatch()的第 <br>

四个形参,一般我们自己的包捕捉程序不需要提供它,总是为NULL。第二个形参指向 <br>

pcap_pkthdr结构,该结构位于真正的物理帧前面,用于消除不同链路层支持的差异。 <br>

最后的形参指向所捕获报文的物理帧。 <br>

-------------------------------------------------------------------------- <br>

/usr/include/pcap.h <br>

/* <br>

 * Each packet in the dump file is prepended with this generic header. <br>

 * This gets around the problem of different header for different <br>

 * packet interfaces. <br>



 */ <br>

struct pcap_pkthdr <br>

{ <br>

    struct timeval ts;      /* time stamp                    */ <br>

    bpf_u_int32    caplen;  /* length of portion present     */ <br>

    bpf_u_int32    len;     /* length this packet (off wire) */ <br>

}; <br>

/usr/include/net/bpf.h <br>

/* <br>

 * Structure prepended to each packet. <br>

 */ <br>

struct bpf_hdr <br>

{ <br>

    struct timeval bh_tstamp;   /* time stamp                 */ <br>

    bpf_u_int32    bh_caplen;   /* length of captured portion */ <br>

    bpf_u_int32    bh_datalen;  /* oiginal length of packet  */ <br>

    u_short        bh_hdrlen;   /* length of bpf header (this struct <br>

                                   plus alignment padding)    */ <br>

}; <br>

/* <br>

 * Because the structure above is not a multiple of 4 bytes, some compilers <br>

 * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't wor <br>



k. <br>

 * Only the kernel needs to know about it; applications use bh_hdrlen. <br>

 */ <br>

#ifdef KERNEL <br>

#define SIZEOF_BPF_HDR 18 <br>

#endif <br>

-------------------------------------------------------------------------- <br>

void pcap_close ( pcap_t * p ); <br>

该函数用于关闭pcap_open_live()获取的包捕捉句柄,释放相关资源。 <br>

void pcap_perror ( pcap_t * p, char * prefix ); <br>

第一形参来自pcap_open_live(),第二行参的作用类似perror()的形参,指定错误信 <br>

息的前缀,与perror()一样,结尾自动输出一个换行。 <br>

pcap_perror( p, "pcap_compile" )的输出类似这个效果: <br>

pcap_compile: unknown ip proto ... <br>

pcap_perror并不自动exit(),与perror()一样,如果需要,应该显式调用ext()。 <br>

介绍到这里,已经可以写简单的sniffer。出于完整演示目的,提供这样一个sample <br>

code。请勿询问任何关于该代码的问题,烦了。 <br>

-------------------------------------------------------------------------- <br>

/* <br>

* File   : sniffer program for I386/Linux using libpcap <br>

* Version: 0.01 aleph <br>

* Author : Anonymous ( Don't ask anything about this program, please. ) <br>



* Complie: gcc -O3 -o pcap pcap_sniffer.c -lpcap `libnet-config --defines -- <br>

cfla <br>

gs` -Wall <br>

*        : strip pcap <br>

* Usage  : ./pcap -h <br>

* Date   : 2000-12-15 16:35 <br>

*/ <br>

/******************************************************************* <br>

*                                                                 * <br>

*                            Head File                           * <br>

*                                                                 * <br>

*******************************************************************/ <br>

#include <stdio.h> <br>

#include <stdlib.h> <br>

#include <string.h> <br>

#include <sys/types.h> <br>

#include <pcap.h> <br>

#include <libnet.h>  /* for LIBNET_TCP_H */ <br>

/******************************************************************* <br>

*                                                                 * <br>

*                            Macro                                * <br>

*                                                                * <br>



*******************************************************************/ <br>

#define SUCCESS  0 <br>

#define FAILURE -1 <br>

typedef void Sigfunc ( int );  /* for signal handlers */ <br>

/******************************************************************* <br>

*                                                                 * <br>

*                       Static Global Var                         * <br>

*                                                                 * <br>

*******************************************************************/ <br>

static pcap_t * pcap_fd = NULL;  /* 抽象的包捕捉句柄 */ <br>

/******************************************************************* <br>

*                                                                 * <br>

*                        Function Prototype                       * <br>

*                                                                 * <br>

*******************************************************************/ <br>

static void      Atexit        ( void ( *func ) ( void ) ); <br>

static void      bpf_dump      ( struct bpf_program * p, int option ); <br>

       char *    bpf_image     ( struct bpf_insn * p, int n ); <br>

static void      outputBinary  ( const u_char * byteArray, const size_t byte <br>

Arra <br>

yLen ); <br>

static void      pcap_callback ( u_char * none, const struct pcap_pkthdr * p <br>



cap_ <br>

head, const u_char * packet ); <br>

static pcap_t *  pcap_init     ( char * dev, char * filter, int snaplen, int <br>

 tim <br>

eout, int dumplevel ); <br>

static void      pcap_read     ( pcap_t * p ); <br>

static vod      sig_end       ( int signo ); <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -