[转载]函数库 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' 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',
`net 128.3', `port 20'. 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', `dst net 128.3',
`src or dst port ftp-data'. 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',
`arp net 128.3', `tcp port 21'. If there is
no proto qualifier, all protocols consistent
with the type are assumed. E.g., `src foo'
means `(ip or arp or rarp) src foo' (except
the latter is not legal syntax), `net bar'
means `(ip or arp or rarp) net bar' and
`port 53' means `(tcp or udp) port 53'.
[`fddi' is actually an alias for `ether'; the
parser treats them identically as meaning ``the
data link level used on the specified network
interface.'' 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' keywords that don'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'. To save typing, identical quali-
fier lists can be omitted. E.g., `tcp dst port ftp
or ftp-data or domain' is exactly the same as `tcp
dst port ftp or tcp dst port ftp-data or tcp dst
port domain'.
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'.
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'), 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'', 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' catches all
multicast traffic. The expression `ip[0] &
0xf != 5' catches all IP packets with
options. The expression `ip[6:2] & 0x1fff =
0' 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 (`!' or `not').
Concatenation (`&&' or `and').
Alternation (`||' or `or').
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 'gateway snup and (port ftp or ftp-data)'
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 'tcp[13] & 3 != 0 and not src and dst net localnet'
To print IP packets longer than 576 bytes sent through
gateway snup:
tcpdump 'gateway snup and ip[2:2] > 576'
To print IP broadcast or multicast packets that were not
sent via ethernet broadcast or multicast:
tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
To print all ICMP packets that are not echo
requests/replies (i.e., not ping packets):
tcpdump 'icmp[0] != 8 and icmp[0] != 0’
页:
[1]