邪恶八进制信息安全团队技术讨论组's Archiver

冰血封情 2005-5-4 14:23

[转载]函数库 libpcap(+SCO) 的安装及使用

  文章作者:bobdai <[email]bobdai@sohu.com[/email]>

写在前面

   我最近修改了 libpcap 函数库,使之能够支持 SCO OpenServer ,现将其文档放在主页上供大家参考,请多指教!

一、安装前的准备(仅SCO系统需要此步骤)
   首先应准备一个支持混杂模式(Promiscuous Mode)的网卡,如 3C509。按正常步骤安装到系统中,然后按下列步骤做:1)、在/etc/default/boot文件中,将“ksl.disable”加在“DEFBOOTSTR”串后;2)、在/var/opt/K/SCO/lli/5.0.4d/llimdi文件中,删除或注释与相关网卡有关的相应行;3)、将/etc/rc2.d/S85tcp改名为/etc/rc2.d/S83tcp;4)、重新引导系统。



二、安装 libpcap
1、解压、解包 libpcap+sco.tar.Z,进入 libpcap+sco 目录;
2、进入 install-bpf 目录,输入 ./installbpf 安装BPF内核过滤器;(仅SCO系统需要此步骤)
3、返回 libpcap+sco 目录,输入 ./configure 生成 Makefile;(仅SCO系统需要此步骤)
4、输入 make 编译
5、输入 make install将生成的库安装到系统默认目录中。此目录为 /usr/lib ,如果需要修改,可以修改文件 Makefile 的 prefix。
6、输入 make install-incl ,将头文件安装至系统默认目录,/usr/include,修改同上。
7、安装完毕,如果以上任意一步出错,libpcap 将无法正常使用。



三、libpcap 的使用
1、头文件:#include <pcap.h>
2、编译选项: cc .. -lpcap –lsocket ..
3、主要数据结构及函数

pcap_t

这个结构是我们使用 libpcap 库的核心数据结构,在程序的开始,调用 pcap_open_live() 将返回一个指向这个结构的指针,以后几乎调用库里的每一个函数都需要这个结构作为参数。我们编程时需要涉及到的成员有:int fd; 打开设备的描述符;u_char *buffer; 是指向所捕获到数据的缓冲区指针。

struct pcap_stat

包含两个可用成员:u_int ps_recv, u_int ps_drop 。调用函数 pcap_stats() 可以返回一个该结构。两个成员分别为内核过滤器收到的包和丢弃的包。

struct bpf_hdr

内核过滤器每输出一个包,将在输出的数据前加了20字节的数据,这就是 struct bpf_hdr 。这个结构包含了三个可用成员:struct timeval bh_tstamp,接收此包的时间戳;u_long bh_caplen,返回数据长度;u_long bh_datalen,实际包长度。

struct bpf_program

此结构如果使用 tcpdump 表达式,则不用关心其内部结构。但如果要使用 BPF 程序,就需要知道其成员:struct bpf_insn *bf_insns,指向BPF指令所在空间;u_int bf_len,BPF程序长度。

pcap_t *pcap_open_live()

功能:打开监听设备

输入:第一个参数为 char *,指定要打开设备的名称。在SCO下这一参数设置为 NULL ,SCO的这个函数能自动寻找可用设备。在别的系统下,必须调用函数 char *pcap_lookupdev( char *errbuf );这个函数返回可用设备名,将其在传给 pcap_open_live 即可。第二个参数为 int,指定从每个包返回数据的长度,例如,如果指定1000,那么长度小于1000的包将返回其实际长度的全部数据;如果包长度大于1000,则返回包的前1000字节。第三个参数为混杂标志,如果设定为1,将把网卡设置为混杂模式,监听全网段。第四个参数为以毫秒计超时时限。第五个参数为出错消息字符串指针。

输出:指向结构 pcap_t 的指针

char *pcap_lookupdev()

功能:获取可用监听设备。

输入:出错消息可用监听设备。

输出:可用监听设备字符串指针。

说明:由于SCO和其他系统在监听机制上的差异,SCO下这个函数返回的设备仅用于获取子网掩码所用,并非我们真正要使用的设备。

int *pcap_lookupnet()

功能:获取网络相关参数

输入:第一个参数为指向监听设备的字符串。第二、三个参数为指向bpf_u_int32 的指针,分别为网络地址 localnet 和 子网掩码 netmask。第四个参数为出错消息字符串指针。

输出:返回-1表示出错。

int pcap_compile()

功能:编译 tcpdump 表达式为BPF程序。

输入:第一个参数为指向 pcap_t 的指针。第二个参数为指向结构 struct bpf_program 的指针,用于存放编译后的BPF程序。第三个参数为 tcpdump 表达式字符串指针。第四个参数为优化编译标志。第五个参数为 bpf_u_int32 类型的子网掩码,要获得子网掩码,可调用 pcap_lookupnet 函数。、

输出:返回-1表示出错。

int pcap_setfilter()

功能:设置BPF内核过滤器。

输入:第一个参数为指向 pcap_t 的指针。第二个参数为指向结构 struct bpf_program 的指针,一般为 pcap_compile 编译后的结果,也可以手编BPF代码,详情参见 << BPF 程序的编写 >>。

输出:返回-1表示出错。

const u_char *pcap_next()

功能:获取下一个包。

输入:第一个参数为指向 pcap_t 的指针。第二个参数为指向结构 struct pcap_pkthdr 的指针,与 struct bpf_hdr 几乎完全一样。例程序里我没有用他。返回的数据都放在 pcap_t 的 buffer 中。

int pcap_stats()

功能:获取BPF内核过滤器的状态。

输入:第一个参数为指向 pcap_t 的指针。第二个参数为指向结构struct pcap_stat 的指针,返回的状态数据将存放在这个结构里。

int pcap_geterr()

功能:获取上一条出错消息

输入:一个指向 pcap_t 的指针。

输出:出错消息字符串指针。


4、基本运行模式

打开设备

在SCO下直接使用pcap_open_live(),在其他系统下先调用 pcap_lookupdev(),获取可用设备,再调用 pcap_open_live()。在SCO下,如果想取得子网掩码,供 pcap_compile 使用,也需要调用pcap_lookupdev(),再调用 pcap_lookupnet()。

设置过滤规则

给定 tcpdump 表达式字符串,调用 pcap_compile() 编译他,再调用 pcap_setfilter() 设置BPF内核过滤器。关于 tcpdump 表达式字符串的编写方法,请参看附录B。

获取数据

不断调用 pcap_next() 函数即可一个一个的获取过滤器输出的包。

状态及出错消息

pcap_stats() 可获取过滤器当前状态,pcap_geterr() 可获取上一次的出错消息。


5、一个例子

libpcap+sco.tar.Z 解开后,主目录下会有一个 pcap0.c 文件,是使用 libpcap 库的例程序,读一读这些源码对理解、使用会很有帮助。附录A里有这个程序的全部源码,并加入了一些中文注释。



四、兼容性
1、SCO系统下的打开设备方式与别的系统不完全相同。别的系统,也就是库的原来设计者设计的打开过程是:调用 pcap_lookupdev() 获得可用监听设备 char *dev,然后将其作为参数传递给 pcap_open_live() 打开设备。而在SCO下不用先调用 pcap_lookupdev() ,直接传递 NULL 的 char *dev 给pcap_open_live() 即可。

2、原来的库支持脱机方式监听网络( pcap_open_offline() ),即支持将截获的数据先存入磁盘文件,再使用这些磁盘文件进行脱机监听。我对这一机制没有更深的研究,也没有测试过,建议不使用。




附录A 例程序 pcap0.c
/*
* A sample program using libpcap for SCO
*
* Author bobdai, May 2000
*/

/* cc a.c -lpcap -lsocket */

#include   <stdio.h>
#include   <string.h>
#include   <pcap.h>

main()
{
   int    i;
   char   exp[8192], errbuf[PCAP_ERRBUF_SIZE];   
   pcap_t   *p;
   char   *dev;

   struct   pcap_pkthdr  h;
   struct   pcap_stat    ps;
   struct   bpf_program  bp;
   struct   bpf_hdr      *bh;

   bpf_u_int32 localnet, netmask;

   if( (p=pcap_open_live(NULL, 1000, 1, 1000, errbuf)) == NULL )
   {
      printf( "pcap_open_live: %s\n", errbuf );
      exit(0);
   }
  
   if( (dev=pcap_lookupdev(errbuf)) == NULL)
      printf( "%s\n", errbuf );
   if( pcap_lookupnet(dev, &localnet, &netmask, errbuf) <0 )
      printf( "%s\n", errbuf );
   printf( "localnet=%.8x netmask=%.8x\n", localnet, netmask );

   /* set BPF filter */

/* 下面这句 tcpdump 过滤规则表达式的含义是:接收源IP地址为 192.168.0.1 且设置了 SYN 标志的 TCP 分节。从 TCP 头部开始处偏移为13字节的值为2,即SYN 标志。tcpdump 过滤表达式的写法见附录B。
*/

strcpy( exp, "src host 192.168.0.1 and tcp[13:1] & 2 != 0" );
   if( pcap_compile(p, &bp, exp, 1, netmask ) <0 )
      printf( "%s\n", pcap_geterr(p) ), exit(0);
   if( pcap_setfilter(p, &bp) <0 )
      printf( "%s\n", pcap_geterr(p) ), exit(0);

   for(;;){                  /* Begin ... @!@ */

   pcap_next( p, &h );           /* Get next packet */
   bh = ( struct bpf_hdr *)p->buffer;   /* The first 20 bytes is the bpf_hdr */
   pcap_stats( p, &ps );           /* Get stats of BPF module */
   printf( "caplen=%d datalen=%d recv=%d drop=%d\n",
        bh->bh_caplen, bh->bh_datalen,
        ps.ps_recv, ps.ps_drop );

   for( i=0; i<(int)bh->bh_caplen; i++ )  /* Display the data */
   {
     /* Real data is begin at buffer+20 */
      printf( "%.2x ", *((p->buffer+20)+i) );
      if( (i+1)%16 == 0 ) printf( "\n" );
   }
   printf( "\n" );

   } /* end of for(;;) */
}



附录B tcpdump 过滤规则表达式参考
   expression

          selects  which  packets  will  be  dumped.  If  no
          expression is given, all packets on the net will be
          dumped.  Otherwise, only packets for which  expres-
          sion is `true&#39; will be dumped.

          The  expression consists of one or more primitives.
          Primitives usually consist of an id (name  or  num-
          ber) preceded by one or more qualifiers.  There are
          three different kinds of qualifier:

          type  qualifiers say what kind  of  thing  the  id
              name  or  number  refers to.  Possible types
              are host, net and port.  E.g.,  `host  foo&#39;,
              `net 128.3&#39;, `port 20&#39;.  If there is no type
              qualifier, host is assumed.

          dir   qualifiers  specify  a  particular  tranfer
              direction  to  and/or  from  id.  Possible
              directions are src, dst, src or dst and  src
              and  dst.  E.g., `src foo&#39;, `dst net 128.3&#39;,
              `src or dst port ftp-data&#39;.  If there is  no
              dir qualifier, src or dst is assumed.

          proto  qualifiers  restrict the match to a particu-
              lar protocol.  Possible protos  are:  ether,
              fddi,  ip,  arp,  rarp,  decnet, lat, moprc,
              mopdl, tcp and udp.  E.g., `ether src  foo&#39;,
              `arp net 128.3&#39;, `tcp port 21&#39;.  If there is
              no proto qualifier, all protocols consistent
              with  the type are assumed.  E.g., `src foo&#39;
              means `(ip or arp or rarp) src foo&#39;  (except
              the  latter  is not legal syntax), `net bar&#39;
              means `(ip or arp  or  rarp)  net  bar&#39;  and
              `port 53&#39; means `(tcp or udp) port 53&#39;.

          [`fddi&#39;  is  actually  an  alias  for  `ether&#39;; the
          parser treats them  identically  as  meaning  ``the
          data  link  level  used  on  the  specified network
          interface.&#39;&#39;  FDDI  headers  contain  Ethernet-like
          source and destination addresses, and often contain
          Ethernet-like packet types, so you  can  filter  on
          these FDDI fields just as with the analogous Ether-
          net  fields.  FDDI  headers  also  contain  other
          fields,  but  you  cannot name them explicitly in a
          filter expression.]

          In addition to the above, there  are  some  special
          `primitive&#39; keywords that don&#39;t follow the pattern:
          gateway, broadcast, less,  greater  and  arithmetic
          expressions.  All of these are described below.
          More  complex  filter  expressions  are built up by
          using the words and, or and not to  combine  primi-
          tives.  E.g.,  `host  foo and not port ftp and not
          port ftp-data&#39;.  To save typing,  identical  quali-
          fier lists can be omitted.  E.g., `tcp dst port ftp
          or ftp-data or domain&#39; is exactly the same as  `tcp
          dst  port  ftp  or tcp dst port ftp-data or tcp dst
          port domain&#39;.

          Allowable primitives are:

          dst host host
              True if the  IP  destination  field  of  the

              packet  is  host,  which  may  be  either an
              address or a name.


          src host host
              True if the IP source field of the packet is
              host.


          host host
              True  if either the IP source or destination
              of the packet is host.  Any  of  the  above
              host  expressions  can be prepended with the
              keywords, ip, arp, or rarp as in:
                  ip host host
              which is equivalent to:
                  ether proto \ip and host host
              If  host  is  a  name  with  multiple  IP
              addresses,  each address will be checked for
              a match.


          ether dst ehost
              True if the ethernet destination address  is
              ehost.  Ehost  may  be  either  a name from
              /etc/ethers or a number (see ethers(3N)  for
              numeric format).


          ether src ehost
              True  if  the  ethernet  source  address  is
              ehost.


          ether host ehost
              True if either the ethernet source or desti-
              nation address is ehost.


          gateway host
              True  if  the packet used host as a gateway.
              I.e., the  ethernet  source  or  destination
              address  was  host but neither the IP source
              nor the IP destination was host.  Host  must
              be  a  name  and  must  be  found  in  both
              /etc/hosts and /etc/ethers.  (An  equivalent
              expression is ether host ehost and not host host
              which  can be used with either names or num-
              bers for host / ehost.)


          dst net net
              True if the IP destination  address  of  the
              packet  has  a  network number of net, which
              may be either an address or a name.


          src net net
              True if the IP source address of the  packet
              has a network number of net.


          net net
              True  if either the IP source or destination
              address of the packet has a  network  number
              of net.


          dst port port
              True  if  the packet is ip/tcp or ip/udp and
              has a destination port value of  port.  The
              port  can  be  a  number  or  a name used in
              /etc/services (see tcp(4P) and udp(4P)).  If
              a  name  is  used,  both the port number and
              protocol  are  checked.  If  a  number  or
              ambiguous name is used, only the port number
              is checked (e.g., dst port  513  will  print
              both  tcp/login traffic and udp/who traffic,
              and port domain will print  both  tcp/domain
              and udp/domain traffic).


          src port port
              True  if  the packet has a source port value
              of port.


          port port
              True if either  the  source  or  destination
              port  of  the  packet  is  port.  Any of the
              above port expressions can be prepended with
              the keywords, tcp or udp, as in:
                  tcp src port port
              which matches only tcp packets.


          less length
              True if the packet has a length less than or
              equal to length.  This is equivalent to:
                  len <= length.


          greater length
              True if the packet has a length greater than
              or equal to length.  This is equivalent to:
                  len >= length.


          ip proto protocol
              True  if  the  packet  is  an ip packet (see
              ip(4P)) of protocol type protocol.  Protocol
              can  be  a  number or one of the names icmp,
              udp, nd, or tcp.  Note that the  identifiers
              tcp,  udp,  and  icmp  are also keywords and
              must be escaped via backslash (\), which  is
              \\ in the C-shell.


          ether broadcast
              True  if the packet is an ethernet broadcast
              packet.  The ether keyword is optional.


          ip broadcast
              True  if  the  packet  is  an  IP  broadcast
              packet.  It  checks for both the all-zeroes
              and  all-ones  broadcast  conventions,  and
              looks up the local subnet mask.


          ether multicast
              True  if the packet is an ethernet multicast
              packet.  The  ether  keyword  is  optional.
              This is shorthand for `ether[0] & 1 != 0&#39;.


          ip multicast
              True  if  the  packet  is  an  IP  multicast
              packet.


          ether proto protocol
              True if the packet is of ether  type  proto-
              col.  Protocol  can  be  a number or a name
              like ip, arp, or rarp.  Note  these  identi-
              fiers  are also keywords and must be escaped
              via backslash (\).  [In  the  case  of  FDDI
              (e.g.,  `fddi  protocol  arp&#39;), the protocol
              identification comes from the 802.2  Logical
              Link  Control (LLC) header, which is usually
              layered on top of the FDDI header.  tcpdump
              assumes,  when  filtering  on  the  protocol
              identifier, that all FDDI packets include an
              LLC  header,  and  that the LLC header is in
              so-called SNAP format.]


          decnet src host
              True if the DECNET source address  is  host,
              which  may  be  an  address  of  the  form
              ``10.123&#39;&#39;, or a DECNET host name.  [DECNET
              host  name  support  is  only  available  on
              Ultrix systems that are  configured  to  run
              DECNET.]


          decnet dst host
              True  if  the  DECNET destination address is
              host.


          decnet host host
              True if either the DECNET source or destina-
              tion address is host.


          ip, arp, rarp, decnet
              Abbreviations for:
                  ether proto p
              where p is one of the above protocols.


          lat, moprc, mopdl
              Abbreviations for:
                  ether proto p
              where p is one of the above protocols.  Note
              that tcpdump does not currently know how  to
              parse these protocols.


          tcp, udp, icmp
              Abbreviations for:
                  ip proto p
              where p is one of the above protocols.


          expr relop expr
              True  if  the relation holds, where relop is
              one of >, <, >=, <=, =, !=, and expr  is  an
              arithmetic  expression  composed  of integer
              constants (expressed in standard C  syntax),
              the  normal binary operators [+, -, *, /, &,
              |], a length operator,  and  special  packet
              data  accessors.  To access data inside the
              packet, use the following syntax:
                  proto [ expr : size ]
              Proto is one of ether, fddi, ip, arp,  rarp,
              tcp,  udp, or icmp, and indicates the proto-
              col layer for the index operation.  The byte
              offset,  relative  to the indicated protocol
              layer, is given by expr.  Size  is  optional
              and  indicates  the  number  of bytes in the
              field of interest; it  can  be  either  one,
              two,  or  four,  and  defaults  to one.  The
              length operator, indicated  by  the  keyword
              len, gives the length of the packet.

              For example, `ether[0] & 1 != 0&#39; catches all
              multicast traffic.  The expression `ip[0]  &
              0xf  !=  5&#39;  catches  all  IP  packets  with
              options. The expression `ip[6:2] & 0x1fff  =
              0&#39;  catches  only unfragmented datagrams and
              frag zero  of  fragmented  datagrams.  This
              check  is  implicitly applied to the tcp and
              udp index operations.  For instance,  tcp[0]
              always  means  the  first  byte  of  the TCP
              header, and never means the first byte of an
              intervening fragment.

          Primitives may be combined using:

              A  parenthesized  group  of  primitives  and
              operators (parentheses are  special  to  the
              Shell and must be escaped).

              Negation (`!&#39; or `not&#39;).

              Concatenation (`&&&#39; or `and&#39;).

              Alternation (`||&#39; or `or&#39;).

          Negation  has  highest precedence.  Alternation and
          concatenation have equal precedence  and  associate
          left  to right.  Note that explicit and tokens, not
          juxtaposition, are now required for  concatenation.

          If  an  identifier  is given without a keyword, the
          most recent keyword is assumed.  For example,
             not host vs and ace
          is short for
             not host vs and host ace
          which should not be confused with
             not ( host vs or ace )

          Expression arguments can be passed  to  tcpdump  as
          either  a single argument or as multiple arguments,
          whichever is more convenient.  Generally,  if  the
          expression  contains  Shell  metacharacters,  it is
          easier to pass it as  a  single,  quoted  argument.
          Multiple  arguments  are  concatenated  with spaces
          before being parsed.

EXAMPLES
     To print all packets arriving at or  departing  from  sun-
     down:
          tcpdump host sundown

     To print traffic between helios and either hot or ace:
          tcpdump host helios and \( hot or ace \)

     To  print  all  IP packets between ace and any host except
     helios:
          tcpdump ip host ace and not helios

     To print all traffic between  local  hosts  and  hosts  at
     Berkeley:
          tcpdump net ucb-ether

     To  print  all  ftp traffic through internet gateway snup:
     (note that the expression is quoted to prevent  the  shell
     from (mis-)interpreting the parentheses):
          tcpdump &#39;gateway snup and (port ftp or ftp-data)&#39;

     To  print  traffic  neither  sourced from nor destined for
     local hosts (if you gateway to one other net,  this  stuff
     should never make it onto your local net).
          tcpdump ip and not net localnet

     To  print the start and end packets (the SYN and FIN pack-
     ets) of each TCP conversation that  involves  a  non-local
     host.
          tcpdump &#39;tcp[13] & 3 != 0 and not src and dst net localnet&#39;

     To  print  IP  packets  longer than 576 bytes sent through
     gateway snup:
          tcpdump &#39;gateway snup and ip[2:2] > 576&#39;

     To print IP broadcast or multicast packets that  were  not
     sent via ethernet broadcast or multicast:
          tcpdump &#39;ether[0] & 1 = 0 and ip[16] >= 224&#39;

     To  print  all  ICMP  packets  that  are  not  echo
     requests/replies (i.e., not ping packets):
          tcpdump &#39;icmp[0] != 8 and icmp[0] != 0’

页: [1]
© 1999-2008 EvilOctal Security Team