From c14b8944132ada3ab36d8e3bd0bd9c3b97461da9 Mon Sep 17 00:00:00 2001 From: dyoung Date: Mon, 27 Sep 2004 23:02:53 +0000 Subject: [PATCH] Resolve conflicts in libpcap-0.8.3 import. Remove some extraneous files. --- lib/libpcap/CHANGES | 136 +- lib/libpcap/Makefile | 12 +- lib/libpcap/README | 83 +- lib/libpcap/bpf_dump.c | 6 +- lib/libpcap/bpf_image.c | 28 +- lib/libpcap/etherent.c | 23 +- lib/libpcap/ethertype.h | 33 +- lib/libpcap/fad-getad.c | 6 +- lib/libpcap/gencode.c | 3143 ++++++++++++++++++++++++++++++++----- lib/libpcap/gencode.h | 154 +- lib/libpcap/gnuc.h | 45 - lib/libpcap/grammar.y | 137 +- lib/libpcap/inet.c | 680 ++++++-- lib/libpcap/nametoaddr.c | 115 +- lib/libpcap/optimize.c | 127 +- lib/libpcap/pcap-bpf.c | 662 +++++++- lib/libpcap/pcap-bpf.h | 598 ------- lib/libpcap/pcap-int.h | 153 +- lib/libpcap/pcap-namedb.h | 12 +- lib/libpcap/pcap-stdinc.h | 63 - lib/libpcap/pcap.3 | 1008 +++++++++++- lib/libpcap/pcap.c | 619 +++++++- lib/libpcap/pcap.h | 139 +- lib/libpcap/ppp.h | 6 +- lib/libpcap/savefile.c | 742 ++++++++- lib/libpcap/scanner.l | 147 +- lib/libpcap/version.c | 4 +- 27 files changed, 7207 insertions(+), 1674 deletions(-) delete mode 100644 lib/libpcap/gnuc.h delete mode 100644 lib/libpcap/pcap-bpf.h delete mode 100644 lib/libpcap/pcap-stdinc.h diff --git a/lib/libpcap/CHANGES b/lib/libpcap/CHANGES index a450f5e779a9..3a6abeb6907e 100644 --- a/lib/libpcap/CHANGES +++ b/lib/libpcap/CHANGES @@ -1,7 +1,126 @@ -$NetBSD: CHANGES,v 1.4 1997/10/03 15:53:00 christos Exp $ -@(#) Header: CHANGES,v 1.43 97/09/24 19:48:58 leres Exp (LBL) +$NetBSD: CHANGES,v 1.5 2004/09/27 23:02:53 dyoung Exp $ +@(#) Header: /tcpdump/master/libpcap/CHANGES,v 1.56.4.3 2004/03/30 14:29:16 mcr Exp (LBL) -v0.4 Wed Sep 24 19:48:54 PDT 1997 +Tue. March 30, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.3 release + + Fixed minor problem in gencode.c that would appear on 64-bit + platforms. + Version number is now sane. + +Mon. March 29, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.2 release + + updates for autoconf 2.5 + fixes for ppp interfaces for freebsd 4.1 + pcap gencode can generate code for 802.11, IEEE1394, and pflog. + +Wed. November 12, 2003. mcr@sandelman.ottawa.on.ca. Summary for 0.8 release + + added pcap_findalldevs() + Win32 patches from NetGroup, Politecnico di Torino (Italy) + OpenBSD pf, DLT_PFLOG added + Many changes to ATM support. + lookup pcap_lookupnet() + Added DLT_ARCNET_LINUX, DLT_ENC, DLT_IEEE802_11_RADIO, DLT_SUNATM, + DLT_IP_OVER_FC, DLT_FRELAY, others. + Sigh. More AIX wonderfulness. + Document updates. + Changes to API: pcap_next_ex(), pcap_breakloop(), pcap_dump_flush(), + pcap_list_datalinks(), pcap_set_datalink(), + pcap_lib_version(), pcap_datalink_val_to_name(), + pcap_datalink_name_to_val(), new error returns. + +Tuesday, February 25, 2003. fenner@research.att.com. 0.7.2 release + + Support link types that use 802.2 always, never, and sometimes. + Don't decrease the size of the BPF buffer from the default. + Support frame relay. + Handle 32-bit timestamps in DLPI, and pass the right buffer size. + Handle Linux systems with modern kernel but without + SOL_PACKET in the userland headers. + Linux support for ARPHRD_RAWHDLC. + Handle 32-bit timestamps in snoop. + Support eg (Octane/O2xxx/O3xxx Gigabit) devices. + Add new reserved DLT types. + +Monday October 23, 2001. mcr@sandelman.ottawa.on.ca. Summary for 0.7 release + + Added pcap_findalldevs() call to get list of interfaces in a MI way. + + pcap_stats() has been documented as to what its counters mean on + each platform. + +Tuesday January 9, 2001. guy@alum.mit.edu. Summary for 0.6 release + + New Linux libpcap implementation, which, in 2.2 and later + kernels, uses PF_PACKET sockets and supports kernel packet + filtering (if compiled into the kernel), and supports the "any" + device for capturing on all interfaces. Cleans up promiscuous + mode better on pre-2.2 kernels, and has various other fixes + (handles 2.4 ARPHRD_IEEE802_TR, handles ISDN devices better, + doesn't show duplicate packets on loopback interface, etc.). + + Fixed HP-UX libpcap implementation to correctly get the PPA for + an interface, to allow interfaces to be opened by interface name. + + libpcap savefiles have system-independent link-layer type values + in the header, rather than sometimes platform-dependent DLT_ + values, to make it easier to exchange capture files between + different OSes. + + Non-standard capture files produced by some Linux tcpdumps, e.g. + the one from Red Hat Linux 6.2 and later, can now be read. + + Updated autoconf stock files. + + Filter expressions can filter on VLAN IDs and various OSI + protocols, and work on Token Ring (with non-source-routed + packets). + + "pcap_open_dead()" added to allow compiling filter expressions + to pcap code without opening a capture device or capture file. + + Header files fixed to allow use in C++ programs. + + Removed dependancy on native headers for packet layout. + Removed Linux specific headers that were shipped. + + Security fixes: Strcpy replaced with strlcpy, sprintf replaced + with snprintf. + + Fixed bug that could cause subsequent "pcap_compile()"s to fail + erroneously after one compile failed. + + Assorted other bug fixes. + + README.aix and README.linux files added to describe + platform-specific issues. + + "getifaddrs()" rather than SIOCGIFCONF used, if available. + +v0.5 Sat Jun 10 11:09:15 PDT 2000 + +itojun@iijlab.net +- Brought in KAME IPv6/IPsec bpf compiler. +- Fixes for NetBSD. +- Support added for OpenBSD DLT_LOOP and BSD/OS DLT_C_HDLC (Cisco HDLC), + and changes to work around different BSDs having different DLT_ types + with the same numeric value. + +Assar Westerlund +- Building outside the source code tree fixed. +- Changed to write out time stamps with 32-bit seconds and microseconds + fields, regardless of whether those fields are 32 bits or 64 bits in + the OS's native "struct timeval". +- Changed "pcap_lookupdev()" to dynamically grow the buffer into which + the list of interfaces is read as necessary in order to hold the + entire list. + +Greg Troxel +- Added a new "pcap_compile_nopcap()", which lets you compile a filter + expression into a BPF program without having an open live capture or + capture file. + +v0.4 Sat Jul 25 12:40:09 PDT 1998 - Fix endian problem with DLT_NULL devices. From FreeBSD via Bill Fenner (fenner@parc.xerox.com) @@ -67,6 +186,17 @@ v0.4 Wed Sep 24 19:48:54 PDT 1997 - Ifdef ARPHRD_FDDI since not all versions of the Linux kernel have it. Reported reported by Eric Jacksch (jacksch@tenebris.ca) +- Fixed bug in pcap_dispatch() that kept it from returning on packet + timeouts. + +- Changed ISLOOPBACK() macro when IFF_LOOPBACK isn't available to check + for "lo" followed by an eos or digit (newer versions of Linux + apparently call the loopback "lo" instead of "lo0"). + +- Fixed Linux networking include files to use ints instead of longs to + avoid problems with 64 bit longs on the alpha. Thanks to Cristian + Gafton (gafton@redhat.com) + v0.3 Sat Nov 30 20:56:27 PST 1996 - Added Linux support. diff --git a/lib/libpcap/Makefile b/lib/libpcap/Makefile index 5a9568eb642c..68b0ba939dd2 100644 --- a/lib/libpcap/Makefile +++ b/lib/libpcap/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.25 2004/06/25 12:22:23 itojun Exp $ +# $NetBSD: Makefile,v 1.26 2004/09/27 23:02:53 dyoung Exp $ .include @@ -10,8 +10,10 @@ WARNS?= 1 CPPFLAGS+=-I. -I${.CURDIR} -I${NETBSDSRCDIR}/sys/dist/pf -DYYBISON CPPFLAGS+=-DINET6 CPPFLAGS+=-DHAVE_MALLOC_H=1 -DHAVE_SYS_IOCCOM_H=1 -DHAVE_SYS_SOCKIO_H=1 +CPPFLAGS+=-DHAVE_NETINET_IF_ETHER_H CPPFLAGS+=-DHAVE_ETHER_HOSTTON=1 -DHAVE_STRERROR=1 -DHAVE_SOCKADDR_SA_LEN=1 -CPPFLAGS+=-DHAVE_IFADDRS_H=1 +CPPFLAGS+=-DHAVE_IFADDRS_H=1 -DHAVE_LIMITS_H=1 +CPPFLAGS+=-DHAVE_SNPRINTF=1 -DHAVE_STRLCPY=1 -DHAVE_VSNPRINTF=1 # used in no place #CPPFLAGS+=-DLBL_ALIGN=1 LPREFIX=pcap_ @@ -19,7 +21,8 @@ YPREFIX=pcap_ YHEADER=1 SRCS= scanner.l savefile.c pcap.c pcap-bpf.c optimize.c nametoaddr.c \ - inet.c grammar.y gencode.c etherent.c bpf_image.c +inet.c grammar.y gencode.c fad-getad.c etherent.c bpf_image.c \ +bpf_dump.c SRCS+= bpf_filter.c version.c .PATH: ${NETBSDSRCDIR}/sys/net @@ -27,4 +30,7 @@ SRCS+= bpf_filter.c version.c INCS= pcap-namedb.h pcap.h INCSDIR=/usr/include +# XXX -dcy +scanner.c: grammar.h + .include diff --git a/lib/libpcap/README b/lib/libpcap/README index d75da981bb4c..fb84900e9a6b 100644 --- a/lib/libpcap/README +++ b/lib/libpcap/README @@ -1,11 +1,25 @@ -$NetBSD: README,v 1.5 2003/02/05 00:02:25 perry Exp $ -@(#) Header: README,v 1.18 97/06/12 14:23:56 leres Exp (LBL) +$NetBSD: README,v 1.6 2004/09/27 23:02:53 dyoung Exp $ +@(#) Header: /tcpdump/master/libpcap/README,v 1.27.2.1 2003/11/15 23:29:19 guy Exp (LBL) -LIBPCAP 0.4 -Lawrence Berkeley National Laboratory -Network Research Group -libpcap@ee.lbl.gov -ftp://ftp.ee.lbl.gov/libpcap.tar.Z +LIBPCAP 0.8 +Now maintained by "The Tcpdump Group" +See www.tcpdump.org + +Please send inquiries/comments/reports to tcpdump-workers@tcpdump.org + +Anonymous CVS is available via: + cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master login + (password "anoncvs") + cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master checkout libpcap + +Version 0.8 of LIBPCAP can be retrieved with the CVS tag "libpcap_0_8rel1": + cvs -d :pserver:tcpdump@cvs.tcpdump.org:/tcpdump/master checkout -r libpcap_0_8rel1 libpcap + +Please send patches against the master copy to patches@tcpdump.org. + +formerly from Lawrence Berkeley National Laboratory + Network Research Group + ftp://ftp.ee.lbl.gov/libpcap.tar.Z (0.4) This directory contains source code for libpcap, a system-independent interface for user-level packet capture. libpcap provides a portable @@ -19,12 +33,30 @@ system-dependent packet capture modules in each application. Note well: this interface is new and is likely to change. +For some platforms there are README.{system} files that discuss issues +with the OS's interface for packet capture on those platforms, such as +how to enable support for that interface in the OS, if it's not built in +by default. + The libpcap interface supports a filtering mechanism based on the architecture in the BSD packet filter. BPF is described in the 1993 Winter Usenix paper ``The BSD Packet Filter: A New Architecture for -User-level Packet Capture''. A compressed postscript version is in: +User-level Packet Capture''. A compressed PostScript version can be +found at - ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z. + ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z + +or + + http://www.tcpdump.org/papers/bpf-usenix93.ps.Z + +and a gzipped version can be found at + + http://www.tcpdump.org/papers/bpf-usenix93.ps.gz + +A PDF version can be found at + + http://www.tcpdump.org/papers/bpf-usenix93.pdf Although most packet capture interfaces support in-kernel filtering, libpcap uses in-kernel filtering only for the BPF interface. @@ -34,17 +66,30 @@ added overhead (especially, for selective filters). Ideally, libpcap would translate BPF filters into a filter program that is compatible with the underlying kernel subsystem, but this is not yet implemented. -BPF is standard in 4.4BSD, BSD/386, NetBSD, and FreeBSD. DEC OSF/1 -uses the packetfilter interface but has been extended to accept BPF -filters (which libpcap uses). Also, you can add BPF filter support -to Ultrix using the kernel source and/or object patches available in: +BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, and OpenBSD. DEC +OSF/1/Digital UNIX/Tru64 UNIX uses the packetfilter interface but has +been extended to accept BPF filters (which libpcap utilizes). Also, you +can add BPF filter support to Ultrix using the kernel source and/or +object patches available in: ftp://gatekeeper.dec.com/pub/DEC/net/bpfext42.tar.Z. -Problems, bugs, questions, desirable enhancements, source code -contributions, etc., should be sent to the email address -"libpcap@ee.lbl.gov". +Linux, in the 2.2 kernel and later kernels, has a "Socket Filter" +mechanism that accepts BPF filters; see the README.linux file for +information on configuring that option. - - Steve McCanne - Craig Leres - Van Jacobson +Problems, bugs, questions, desirable enhancements, etc. should be sent +to the address "tcpdump-workers@tcpdump.org". Bugs, support requests, +and feature requests may also be submitted on the SourceForge site for +libpcap at + + http://sourceforge.net/projects/libpcap/ + +Source code contributions, etc. should be sent to the email address +"patches@tcpdump.org", or submitted as patches on the SourceForge site +for libpcap. + +Current versions can be found at www.tcpdump.org, or the SourceForge +site for libpcap. + + - The TCPdump team diff --git a/lib/libpcap/bpf_dump.c b/lib/libpcap/bpf_dump.c index a7453e903e84..bbcedf304c0c 100644 --- a/lib/libpcap/bpf_dump.c +++ b/lib/libpcap/bpf_dump.c @@ -1,4 +1,4 @@ -/* $NetBSD: bpf_dump.c,v 1.1.1.2 2004/09/19 21:57:48 dyoung Exp $ */ +/* $NetBSD: bpf_dump.c,v 1.2 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1992, 1993, 1994, 1995, 1996 @@ -23,10 +23,10 @@ #include #ifndef lint #if 0 -static const char rcsid[] _U_ = +static const char rcsid[] = "@(#) Header: /tcpdump/master/libpcap/bpf_dump.c,v 1.13.2.1 2003/11/15 23:26:37 guy Exp (LBL)"; #else -__RCSID("$NetBSD: bpf_dump.c,v 1.1.1.2 2004/09/19 21:57:48 dyoung Exp $"); +__RCSID("$NetBSD: bpf_dump.c,v 1.2 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif diff --git a/lib/libpcap/bpf_image.c b/lib/libpcap/bpf_image.c index c93d3f5a175b..ff1bf9257aee 100644 --- a/lib/libpcap/bpf_image.c +++ b/lib/libpcap/bpf_image.c @@ -1,4 +1,4 @@ -/* $NetBSD: bpf_image.c,v 1.6 2000/10/10 19:12:48 is Exp $ */ +/* $NetBSD: bpf_image.c,v 1.7 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1990, 1991, 1992, 1994, 1995, 1996 @@ -25,21 +25,21 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: bpf_image.c,v 1.22 96/09/26 23:27:56 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/bpf_image.c,v 1.25.2.1 2003/11/15 23:26:38 guy Exp (LBL)"; #else -__RCSID("$NetBSD: bpf_image.c,v 1.6 2000/10/10 19:12:48 is Exp $"); +__RCSID("$NetBSD: bpf_image.c,v 1.7 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif -#include -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include #include "pcap-int.h" -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -256,15 +256,11 @@ bpf_image(p, n) op = "txa"; break; } - - if (BPF_CLASS(p->code) == BPF_JMP && - BPF_OP(p->code) != BPF_JA) - (void)snprintf(image, sizeof image, - "(%03d) %-8s %-16s jt %d\tjf %d", - n, op, operand, n + 1 + p->jt, n + 1 + p->jf); - else - (void)snprintf(image, sizeof image, - "(%03d) %-8s %s", - n, op, operand); + (void)snprintf(image, sizeof image, + (BPF_CLASS(p->code) == BPF_JMP && + BPF_OP(p->code) != BPF_JA) ? + "(%03d) %-8s %-16s jt %d\tjf %d" + : "(%03d) %-8s %s", + n, op, operand, n + 1 + p->jt, n + 1 + p->jf); return image; } diff --git a/lib/libpcap/etherent.c b/lib/libpcap/etherent.c index a8e560efbc76..f5b3e30e7c83 100644 --- a/lib/libpcap/etherent.c +++ b/lib/libpcap/etherent.c @@ -1,4 +1,4 @@ -/* $NetBSD: etherent.c,v 1.4 1997/10/03 15:53:03 christos Exp $ */ +/* $NetBSD: etherent.c,v 1.5 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1990, 1993, 1994, 1995, 1996 @@ -25,12 +25,16 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: etherent.c,v 1.20 96/09/26 23:28:00 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/etherent.c,v 1.21.6.1 2003/11/15 23:26:38 guy Exp (LBL)"; #else -__RCSID("$NetBSD: etherent.c,v 1.4 1997/10/03 15:53:03 christos Exp $"); +__RCSID("$NetBSD: etherent.c,v 1.5 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include @@ -42,17 +46,16 @@ __RCSID("$NetBSD: etherent.c,v 1.4 1997/10/03 15:53:03 christos Exp $"); #include -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif -static inline int xdtoi(int); -static inline int skip_space(FILE *); -static inline int skip_line(FILE *); +static __inline int xdtoi(int); +static __inline int skip_space(FILE *); +static __inline int skip_line(FILE *); /* Hex digit to integer. */ -static inline int +static __inline int xdtoi(c) register int c; { @@ -64,7 +67,7 @@ xdtoi(c) return c - 'A' + 10; } -static inline int +static __inline int skip_space(f) FILE *f; { @@ -77,7 +80,7 @@ skip_space(f) return c; } -static inline int +static __inline int skip_line(f) FILE *f; { diff --git a/lib/libpcap/ethertype.h b/lib/libpcap/ethertype.h index 487b66db79c3..b04533bc6068 100644 --- a/lib/libpcap/ethertype.h +++ b/lib/libpcap/ethertype.h @@ -1,4 +1,4 @@ -/* $NetBSD: ethertype.h,v 1.6 2002/12/19 16:33:47 hannken Exp $ */ +/* $NetBSD: ethertype.h,v 1.7 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1993, 1994, 1996 @@ -20,11 +20,33 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * @(#) Header: ethertype.h,v 1.6 96/07/14 18:21:49 leres Exp (LBL) + * @(#) Header: /tcpdump/master/libpcap/ethertype.h,v 1.12 2001/01/14 21:26:52 guy Exp (LBL) */ -/* Types missing from some systems */ +/* + * Ethernet types. + * + * We wrap the declarations with #ifdef, so that if a file includes + * , which may declare some of these, we don't + * get a bunch of complaints from the C compiler about redefinitions + * of these values. + * + * We declare all of them here so that no file has to include + * if all it needs are ETHERTYPE_ values. + */ +#ifndef ETHERTYPE_PUP +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */ +#endif #ifndef ETHERTYPE_NS #define ETHERTYPE_NS 0x0600 #endif @@ -76,8 +98,11 @@ #ifndef ETHERTYPE_8021Q #define ETHERTYPE_8021Q 0x8100 #endif +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 +#endif #ifndef ETHERTYPE_IPV6 -#define ETHERTYPE_IPV6 0x80f3 +#define ETHERTYPE_IPV6 0x86dd #endif #ifndef ETHERTYPE_LOOPBACK #define ETHERTYPE_LOOPBACK 0x9000 diff --git a/lib/libpcap/fad-getad.c b/lib/libpcap/fad-getad.c index 11fbde57f2cc..69adf5ddc730 100644 --- a/lib/libpcap/fad-getad.c +++ b/lib/libpcap/fad-getad.c @@ -1,4 +1,4 @@ -/* $NetBSD: fad-getad.c,v 1.1.1.2 2004/09/19 21:57:48 dyoung Exp $ */ +/* $NetBSD: fad-getad.c,v 1.2 2004/09/27 23:02:53 dyoung Exp $ */ /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* @@ -37,10 +37,10 @@ #include #ifndef lint #if 0 -static const char rcsid[] _U_ = +static const char rcsid[] = "@(#) Header: /tcpdump/master/libpcap/fad-getad.c,v 1.7.2.2 2004/03/11 23:04:52 guy Exp (LBL)"; #else -__RCSID("$NetBSD: fad-getad.c,v 1.1.1.2 2004/09/19 21:57:48 dyoung Exp $"); +__RCSID("$NetBSD: fad-getad.c,v 1.2 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif diff --git a/lib/libpcap/gencode.c b/lib/libpcap/gencode.c index d533bcca3978..5e0257dd0f09 100644 --- a/lib/libpcap/gencode.c +++ b/lib/libpcap/gencode.c @@ -1,7 +1,7 @@ -/* $NetBSD: gencode.c,v 1.34 2004/06/25 12:22:23 itojun Exp $ */ +/* $NetBSD: gencode.c,v 1.35 2004/09/27 23:02:53 dyoung Exp $ */ /* - * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,9 +24,9 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: gencode.c,v 1.93 97/06/12 14:22:47 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/gencode.c,v 1.193.2.8 2004/03/29 20:53:47 guy Exp (LBL)"; #else -__RCSID("$NetBSD: gencode.c,v 1.34 2004/06/25 12:22:23 itojun Exp $"); +__RCSID("$NetBSD: gencode.c,v 1.35 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif @@ -53,32 +53,46 @@ struct rtentry; #include #include +#include #include #include -#if __STDC__ #include -#else -#include -#endif #include "pcap-int.h" #include "ethertype.h" +#include "nlpid.h" +#include "llc.h" #include "gencode.h" +#include "atmuni31.h" +#include "sunatmpos.h" #include "ppp.h" +#include "sll.h" +#ifndef offsetof +#define offsetof(s, e) ((size_t)&((s *)0)->e) +#endif +#ifdef INET6 +#ifndef WIN32 +#include /* for "struct addrinfo" */ +#endif /* WIN32 */ +#endif /*INET6*/ #include #ifdef INET6 #include #include #endif /*INET6*/ -#include "gnuc.h" +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #ifdef __NetBSD__ #include +#include #endif #define JMP(c) ((c)|BPF_JMP|BPF_K) @@ -87,43 +101,39 @@ struct rtentry; static jmp_buf top_ctx; static pcap_t *bpf_pcap; +#define OFF_UNDEFINED UINT_MAX + /* Hack for updating VLAN offsets. */ -static u_int orig_linktype = (u_int)-1; -static u_int orig_nl = (u_int)-1; +static u_int orig_linktype = OFF_UNDEFINED; +static u_int orig_nl = OFF_UNDEFINED; +static u_int orig_nl_nosnap = OFF_UNDEFINED; /* XXX */ #ifdef PCAP_FDDIPAD -int pcap_fddipad = PCAP_FDDIPAD; +u_int pcap_fddipad = PCAP_FDDIPAD; #else -int pcap_fddipad; +u_int pcap_fddipad; #endif /* VARARGS */ -__dead void -#if __STDC__ +void bpf_error(const char *fmt, ...) -#else -bpf_error(fmt, va_alist) - const char *fmt; - va_dcl -#endif + { va_list ap; -#if __STDC__ va_start(ap, fmt); -#else - va_start(ap); -#endif if (bpf_pcap != NULL) - (void)vsnprintf(pcap_geterr(bpf_pcap), - PCAP_ERRBUF_SIZE, fmt, ap); + (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE, + fmt, ap); va_end(ap); longjmp(top_ctx, 1); /* NOTREACHED */ } static void init_linktype(int); +static int pcap_compile1(pcap_t *, struct bpf_program *, char *, int, + bpf_u_int32, char *); static int alloc_reg(void); static void free_reg(int); @@ -148,20 +158,26 @@ static int cur_chunk; static void *newchunk(u_int); static void freechunks(void); -static inline struct block *new_block(int); -static inline struct slist *new_stmt(int); +static __inline struct block *new_block(int); +static __inline struct slist *new_stmt(int); static struct block *gen_retblk(int); -static inline void syntax(void); +static __inline void syntax(void); static void backpatch(struct block *, struct block *); static void merge(struct block *, struct block *); static struct block *gen_cmp(u_int, u_int, bpf_int32); +static struct block *gen_cmp_gt(u_int, u_int, bpf_int32); static struct block *gen_mcmp(u_int, u_int, bpf_int32, bpf_u_int32); static struct block *gen_bcmp(u_int, u_int, const u_char *); +static struct block *gen_ncmp(bpf_u_int32, bpf_u_int32, bpf_u_int32, + bpf_u_int32, bpf_u_int32, int); static struct block *gen_uncond(int); -static inline struct block *gen_true(void); -static inline struct block *gen_false(void); +static __inline struct block *gen_true(void); +static __inline struct block *gen_false(void); +static struct block *gen_ether_linktype(int); static struct block *gen_linktype(int); +static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int); +static struct block *gen_llc(int); static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int); #ifdef INET6 static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int); @@ -169,6 +185,9 @@ static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, static struct block *gen_ahostop(const u_char *, int); static struct block *gen_ehostop(const u_char *, int); static struct block *gen_fhostop(const u_char *, int); +static struct block *gen_thostop(const u_char *, int); +static struct block *gen_wlanhostop(const u_char *, int); +static struct block *gen_ipfchostop(const u_char *, int); static struct block *gen_dnhostop(bpf_u_int32, int, u_int); static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int); #ifdef INET6 @@ -193,17 +212,26 @@ static struct block *gen_protochain(int, int, int); static struct block *gen_proto(int, int, int); static struct slist *xfer_to_x(struct arth *); static struct slist *xfer_to_a(struct arth *); +static struct block *gen_mac_multicast(u_int); static struct block *gen_len(int, int); +static struct block *gen_msg_abbrev(int type); + static void * newchunk(n) - u_int n; + size_t n; { struct chunk *cp; - int k, size; + int k; + size_t size; - /* XXX Round to structure boundary. */ +#ifndef __NetBSD__ + /* XXX Round up to nearest long. */ + n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); +#else + /* XXX Round up to structure boundary. */ n = ALIGN(n); +#endif cp = &chunks[cur_chunk]; if (n > cp->n_left) { @@ -212,6 +240,8 @@ newchunk(n) bpf_error("out of memory"); size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); + if (cp->m == NULL) + bpf_error("out of memory"); memset((char *)cp->m, 0, size); cp->n_left = size; if (n > size) @@ -241,14 +271,14 @@ char * sdup(s) register const char *s; { - int n = strlen(s) + 1; + size_t n = strlen(s) + 1; char *cp = newchunk(n); - strcpy(cp, s); /* XXX strcpy is safe */ + strlcpy(cp, s, n); return (cp); } -static inline struct block * +static __inline struct block * new_block(code) int code; { @@ -261,7 +291,7 @@ new_block(code) return p; } -static inline struct slist * +static __inline struct slist * new_stmt(code) int code; { @@ -283,7 +313,7 @@ gen_retblk(v) return b; } -static inline void +static __inline void syntax() { bpf_error("syntax error in filter expression"); @@ -294,9 +324,9 @@ static int snaplen; int no_optimize; extern int n_errors; -int -pcap_compile(pcap_t *p, struct bpf_program *program, - char *buf, int optimize, bpf_u_int32 mask) +static int +pcap_compile1(pcap_t *p, struct bpf_program *program, + char *buf, int optimize, bpf_u_int32 mask, char *errbuf) { int len; @@ -305,12 +335,19 @@ pcap_compile(pcap_t *p, struct bpf_program *program, root = NULL; bpf_pcap = p; if (setjmp(top_ctx)) { + lex_cleanup(); freechunks(); - return (-1); + goto err; } netmask = mask; + snaplen = pcap_snapshot(p); + if (snaplen == 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snaplen of 0 rejects all packets"); + goto err; + } lex_init(buf ? buf : ""); init_linktype(pcap_datalink(p)); @@ -331,8 +368,21 @@ pcap_compile(pcap_t *p, struct bpf_program *program, program->bf_insns = icode_to_fcode(root, &len); program->bf_len = len; + lex_cleanup(); freechunks(); return (0); +err: + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_geterr(p)); + return (-1); +} + +int +pcap_compile(pcap_t *p, struct bpf_program *program, + char *buf, int optimize, bpf_u_int32 mask) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + + return pcap_compile1(p, program, buf, optimize, mask, errbuf); } /* @@ -344,45 +394,29 @@ pcap_compile_nopcap(int snaplen_arg, int linktype_arg, struct bpf_program *program, char *buf, int optimize, bpf_u_int32 mask, char *errbuf) { - pcap_t p; - int len; + pcap_t *p; + int ret; - memset(&p, 0, sizeof(p)); - - no_optimize = 0; - n_errors = 0; - root = NULL; - bpf_pcap = &p; - if (setjmp(top_ctx)) { - strncpy(errbuf, pcap_geterr(&p), PCAP_ERRBUF_SIZE - 1); - freechunks(); + p = pcap_open_dead(linktype_arg, snaplen_arg); + if (p == NULL) return (-1); + ret = pcap_compile1(p, program, buf, optimize, mask, errbuf); + pcap_close(p); + return (ret); +} + +/* + * Clean up a "struct bpf_program" by freeing all the memory allocated + * in it. + */ +void +pcap_freecode(struct bpf_program *program) +{ + program->bf_len = 0; + if (program->bf_insns != NULL) { + free((void *)program->bf_insns); + program->bf_insns = NULL; } - - netmask = mask; - snaplen = snaplen_arg; /* basis of filter match return value */ - - lex_init(buf ? buf : ""); - init_linktype(linktype_arg); - (void)pcap_parse(); - - if (n_errors) - syntax(); - - if (root == NULL) - root = gen_retblk(snaplen_arg); - - if (optimize && !no_optimize) { - bpf_optimize(&root); - if (root == NULL || - (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) - bpf_error("expression rejects all packets"); - } - program->bf_insns = icode_to_fcode(root, &len); - program->bf_len = len; - - freechunks(); - return (0); } /* @@ -475,7 +509,7 @@ gen_cmp(offset, size, v) struct slist *s; struct block *b; - s = new_stmt(BPF_LD|BPF_ABS|size); + s = new_stmt(BPF_LD|BPF_ABS|(int)size); s->s.k = offset; b = new_block(JMP(BPF_JEQ)); @@ -485,6 +519,24 @@ gen_cmp(offset, size, v) return b; } +static struct block * +gen_cmp_gt(offset, size, v) + u_int offset, size; + bpf_int32 v; +{ + struct slist *s; + struct block *b; + + s = new_stmt(BPF_LD|BPF_ABS|(int)size); + s->s.k = offset; + + b = new_block(JMP(BPF_JGT)); + b->stmts = s; + b->s.k = v; + + return b; +} + static struct block * gen_mcmp(offset, size, v, mask) u_int offset, size; @@ -540,16 +592,114 @@ gen_bcmp(offset, size, v) return b; } +static struct block * +gen_ncmp(datasize, offset, mask, jtype, jvalue, reverse) + bpf_u_int32 datasize, offset, mask, jtype, jvalue; + int reverse; +{ + struct slist *s; + struct block *b; + + s = new_stmt(BPF_LD|(int)datasize|BPF_ABS); + s->s.k = offset; + + if (mask != 0xffffffff) { + s->next = new_stmt(BPF_ALU|BPF_AND|BPF_K); + s->next->s.k = mask; + } + + b = new_block(JMP((int)jtype)); + b->stmts = s; + b->s.k = jvalue; + if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE)) + gen_not(b); + return b; +} + /* * Various code constructs need to know the layout of the data link - * layer. These variables give the necessary offsets. off_linktype - * is set to -1 for no encapsulation, in which case the check is then + * layer. These variables give the necessary offsets. + */ + +/* + * This is the offset of the beginning of the MAC-layer header. + * It's usually 0, except for ATM LANE. + */ +static u_int off_mac; + +/* + * "off_linktype" is the offset to information in the link-layer header + * giving the packet type. + * + * For Ethernet, it's the offset of the Ethernet type field. + * + * For link-layer types that always use 802.2 headers, it's the + * offset of the LLC header. + * + * For PPP, it's the offset of the PPP type field. + * + * For Cisco HDLC, it's the offset of the CHDLC type field. + * + * For BSD loopback, it's the offset of the AF_ value. + * + * For Linux cooked sockets, it's the offset of the type field. + * + * It's set to -1 for no encapsulation, in which case the check is then * deferred to linktype_af. If that is AF_UNSPEC, AF_INET and AF_INET6 * are allowed, for backwards compatibility. Otherwise, it is the * family to expect. */ static u_int off_linktype; + +/* + * TRUE if the link layer includes an ATM pseudo-header. + */ +static int is_atm = 0; + +/* + * TRUE if "lane" appeared in the filter; it causes us to generate + * code that assumes LANE rather than LLC-encapsulated traffic in SunATM. + */ +static int is_lane = 0; + +/* + * These are offsets for the ATM pseudo-header. + */ +static u_int off_vpi; +static u_int off_vci; +static u_int off_proto; + +/* + * This is the offset of the first byte after the ATM pseudo_header, + * or -1 if there is no ATM pseudo-header. + */ +static u_int off_payload; + +/* + * These are offsets to the beginning of the network-layer header. + * + * If the link layer never uses 802.2 LLC: + * + * "off_nl" and "off_nl_nosnap" are the same. + * + * If the link layer always uses 802.2 LLC: + * + * "off_nl" is the offset if there's a SNAP header following + * the 802.2 header; + * + * "off_nl_nosnap" is the offset if there's no SNAP header. + * + * If the link layer is Ethernet: + * + * "off_nl" is the offset if the packet is an Ethernet II packet + * (we assume no 802.3+802.2+SNAP); + * + * "off_nl_nosnap" is the offset if the packet is an 802.3 packet + * with an 802.2 header following it. + */ static u_int off_nl; +static u_int off_nl_nosnap; + static int linktype; static int linktype_af; @@ -558,11 +708,24 @@ init_linktype(type) int type; { linktype = type; - orig_linktype = -1; - orig_nl = -1; + + /* + * Assume it's not raw ATM with a pseudo-header, for now. + */ + off_mac = 0; + is_atm = 0; + is_lane = 0; + off_vpi = OFF_UNDEFINED; + off_vci = OFF_UNDEFINED; + off_proto = OFF_UNDEFINED; + off_payload = OFF_UNDEFINED; + + orig_linktype = OFF_UNDEFINED; + orig_nl = OFF_UNDEFINED; + orig_nl_nosnap = OFF_UNDEFINED; if (DLT_IS_RAWAF(type)) { - off_linktype = -1; + off_linktype = OFF_UNDEFINED; off_nl = 0; linktype_af = DLT_RAWAF_AF(type); return; @@ -572,17 +735,20 @@ init_linktype(type) case DLT_ARCNET: off_linktype = 2; - off_nl = 6; /* XXX in reality, variable! */ + off_nl = 6; /* XXX in reality, variable! */ + off_nl_nosnap = 6; /* no 802.2 LLC */ return; - case DLT_IEEE802_11: - off_linktype = 30; /* XXX variable */ - off_nl = 32; + case DLT_ARCNET_LINUX: + off_linktype = 4; + off_nl = 8; /* XXX in reality, variable! */ + off_nl_nosnap = 8; /* no 802.2 LLC */ return; case DLT_EN10MB: off_linktype = 12; - off_nl = 14; + off_nl = 14; /* Ethernet II */ + off_nl_nosnap = 17; /* 802.3+802.2 */ return; case DLT_SLIP: @@ -590,36 +756,39 @@ init_linktype(type) * SLIP doesn't have a link level type. The 16 byte * header is hacked into our SLIP driver. */ - off_linktype = -1; + off_linktype = OFF_UNDEFINED; off_nl = 16; + off_nl_nosnap = 16; /* no 802.2 LLC */ linktype_af = AF_INET; return; case DLT_SLIP_BSDOS: /* XXX this may be the same as the DLT_PPP_BSDOS case */ - off_linktype = -1; + off_linktype = OFF_UNDEFINED; /* XXX end */ off_nl = 24; + off_nl_nosnap = 24; /* no 802.2 LLC */ return; case DLT_NULL: + case DLT_LOOP: off_linktype = 0; off_nl = 4; + off_nl_nosnap = 4; /* no 802.2 LLC */ + return; + + case DLT_ENC: + off_linktype = 0; + off_nl = 12; + off_nl_nosnap = 12; /* no 802.2 LLC */ return; case DLT_PPP: - off_linktype = 2; - off_nl = 4; - return; - - case DLT_PPP_BSDOS: - off_linktype = 5; - off_nl = 24; - return; - + case DLT_C_HDLC: /* BSD/OS Cisco HDLC */ case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */ off_linktype = 2; off_nl = 4; + off_nl_nosnap = 4; /* no 802.2 LLC */ return; case DLT_PPP_ETHER: @@ -629,36 +798,171 @@ init_linktype(type) */ off_linktype = 6; off_nl = 8; + off_nl_nosnap = 8; /* no 802.2 LLC */ + return; + + case DLT_PPP_BSDOS: + off_linktype = 5; + off_nl = 24; + off_nl_nosnap = 24; /* no 802.2 LLC */ return; case DLT_FDDI: /* * FDDI doesn't really have a link-level type field. - * We assume that SSAP = SNAP is being used and pick - * out the encapsulated Ethernet type. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? */ - off_linktype = 19; + off_linktype = 13; #ifdef PCAP_FDDIPAD off_linktype += pcap_fddipad; #endif - off_nl = 21; + off_nl = 21; /* FDDI+802.2+SNAP */ + off_nl_nosnap = 16; /* FDDI+802.2 */ #ifdef PCAP_FDDIPAD off_nl += pcap_fddipad; + off_nl_nosnap += pcap_fddipad; #endif return; case DLT_IEEE802: - off_linktype = 20; - off_nl = 22; + /* + * Token Ring doesn't really have a link-level type field. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + * + * XXX - the header is actually variable-length. + * Some various Linux patched versions gave 38 + * as "off_linktype" and 40 as "off_nl"; however, + * if a token ring packet has *no* routing + * information, i.e. is not source-routed, the correct + * values are 20 and 22, as they are in the vanilla code. + * + * A packet is source-routed iff the uppermost bit + * of the first byte of the source address, at an + * offset of 8, has the uppermost bit set. If the + * packet is source-routed, the total number of bytes + * of routing information is 2 plus bits 0x1F00 of + * the 16-bit value at an offset of 14 (shifted right + * 8 - figure out which byte that is). + */ + off_linktype = 14; + off_nl = 22; /* Token Ring+802.2+SNAP */ + off_nl_nosnap = 17; /* Token Ring+802.2 */ + return; + + case DLT_IEEE802_11: + /* + * 802.11 doesn't really have a link-level type field. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + * + * XXX - the header is actually variable-length. We + * assume a 24-byte link-layer header, as appears in + * data frames in networks with no bridges. If the + * fromds and tods 802.11 header bits are both set, + * it's actually supposed to be 30 bytes. + */ + off_linktype = 24; + off_nl = 32; /* 802.11+802.2+SNAP */ + off_nl_nosnap = 27; /* 802.11+802.2 */ + return; + + case DLT_PRISM_HEADER: + /* + * Same as 802.11, but with an additional header before + * the 802.11 header, containing a bunch of additional + * information including radio-level information. + * + * The header is 144 bytes long. + * + * XXX - same variable-length header problem; at least + * the Prism header is fixed-length. + */ + off_linktype = 144+24; + off_nl = 144+32; /* Prism+802.11+802.2+SNAP */ + off_nl_nosnap = 144+27; /* Prism+802.11+802.2 */ + return; + + case DLT_IEEE802_11_RADIO_AVS: + /* + * Same as 802.11, but with an additional header before + * the 802.11 header, containing a bunch of additional + * information including radio-level information. + * + * The header is 64 bytes long, at least in its + * current incarnation. + * + * XXX - same variable-length header problem, only + * more so; this header is also variable-length, + * with the length being the 32-bit big-endian + * number at an offset of 4 from the beginning + * of the radio header. + */ + off_linktype = 64+24; + off_nl = 64+32; /* Radio+802.11+802.2+SNAP */ + off_nl_nosnap = 64+27; /* Radio+802.11+802.2 */ + return; + + case DLT_IEEE802_11_RADIO: + /* + * Same as 802.11, but with an additional header before + * the 802.11 header, containing a bunch of additional + * information including radio-level information. + * + * XXX - same variable-length header problem, only + * even *more* so; this header is also variable-length, + * with the length being the 16-bit number at an offset + * of 2 from the beginning of the radio header, and it's + * device-dependent (different devices might supply + * different amounts of information), so we can't even + * assume a fixed length for the current version of the + * header. + * + * Therefore, currently, only raw "link[N:M]" filtering is + * supported. + */ + off_linktype = OFF_UNDEFINED; + off_nl = OFF_UNDEFINED; + off_nl_nosnap = OFF_UNDEFINED; return; case DLT_ATM_RFC1483: + case DLT_ATM_CLIP: /* Linux ATM defines this */ /* * assume routed, non-ISO PDUs * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) */ - off_linktype = 6; - off_nl = 8; + off_linktype = 0; + off_nl = 8; /* 802.2+SNAP */ + off_nl_nosnap = 3; /* 802.2 */ + return; + + case DLT_SUNATM: + /* + * Full Frontal ATM; you get AALn PDUs with an ATM + * pseudo-header. + */ + is_atm = 1; + off_vpi = SUNATM_VPI_POS; + off_vci = SUNATM_VCI_POS; + off_proto = PROTO_POS; + /* LLC-encapsulated, so no MAC-layer header */ + off_mac = OFF_UNDEFINED; + + off_payload = SUNATM_PKT_BEGIN_POS; + off_linktype = off_payload; + off_nl = off_payload+8; /* 802.2+SNAP */ + off_nl_nosnap = off_payload+3; /* 802.2 */ return; case DLT_HDLC: @@ -666,18 +970,87 @@ init_linktype(type) off_nl = 4; return; - case DLT_PFLOG: - off_linktype = 0; - off_nl = PFLOG_HDRLEN; - return; - case DLT_RAW: - off_linktype = -1; + off_linktype = OFF_UNDEFINED; off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ linktype_af = AF_UNSPEC; return; + + case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ + off_linktype = 14; + off_nl = 16; + off_nl_nosnap = 16; /* no 802.2 LLC */ + return; + + case DLT_LTALK: + /* + * LocalTalk does have a 1-byte type field in the LLAP header, + * but really it just indicates whether there is a "short" or + * "long" DDP packet following. + */ + off_linktype = OFF_UNDEFINED; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + return; + + case DLT_IP_OVER_FC: + /* + * RFC 2625 IP-over-Fibre-Channel doesn't really have a + * link-level type field. We set "off_linktype" to the + * offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? RFC + * 2625 says SNAP should be used. + */ + off_linktype = 16; + off_nl = 24; /* IPFC+802.2+SNAP */ + off_nl_nosnap = 19; /* IPFC+802.2 */ + return; + + case DLT_FRELAY: + /* + * XXX - we should set this to handle SNAP-encapsulated + * frames (NLPID of 0x80). + */ + off_linktype = OFF_UNDEFINED; + off_nl = 0; + off_nl_nosnap = 0; /* no 802.2 LLC */ + return; + + case DLT_APPLE_IP_OVER_IEEE1394: + off_linktype = 16; + off_nl = 18; + off_nl_nosnap = 0; /* no 802.2 LLC */ + return; + + case DLT_LINUX_IRDA: + /* + * Currently, only raw "link[N:M]" filtering is supported. + */ + off_linktype = OFF_UNDEFINED; + off_nl = OFF_UNDEFINED; + off_nl_nosnap = OFF_UNDEFINED; + return; + + case DLT_PFLOG: + off_linktype = 0; + /* XXX read from header? */ + off_nl = PFLOG_HDRLEN; + off_nl_nosnap = PFLOG_HDRLEN; + return; + +#ifdef DLT_PFSYNC + case DLT_PFSYNC: + off_linktype = OFF_UNDEFINED; + off_nl = 4; + off_nl_nosnap = 4; + return; +#endif } - bpf_error("libpcap: unknown data link type 0x%x", linktype); + bpf_error("libpcap: unknown data link type %d", linktype); /* NOTREACHED */ } @@ -696,23 +1069,751 @@ gen_uncond(rsense) return b; } -static inline struct block * +static __inline struct block * gen_true() { return gen_uncond(1); } -static inline struct block * +static __inline struct block * gen_false() { return gen_uncond(0); } +/* + * Byte-swap a 32-bit number. + * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on + * big-endian platforms.) + */ +#define SWAPLONG(y) \ +((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) + +static struct block * +gen_ether_linktype(proto) + register int proto; +{ + struct block *b0, *b1; + + switch (proto) { + + case LLCSAP_ISONS: + /* + * OSI protocols always use 802.2 encapsulation. + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP? + */ + b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32) + ((LLCSAP_ISONS << 8) | LLCSAP_ISONS)); + gen_and(b0, b1); + return b1; + + case LLCSAP_IP: + b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32) + ((LLCSAP_IP << 8) | LLCSAP_IP)); + gen_and(b0, b1); + return b1; + + case LLCSAP_NETBEUI: + /* + * NetBEUI always uses 802.2 encapsulation. + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP? + */ + b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32) + ((LLCSAP_NETBEUI << 8) | LLCSAP_NETBEUI)); + gen_and(b0, b1); + return b1; + + case LLCSAP_IPX: + /* + * Check for; + * + * Ethernet_II frames, which are Ethernet + * frames with a frame type of ETHERTYPE_IPX; + * + * Ethernet_802.3 frames, which are 802.3 + * frames (i.e., the type/length field is + * a length field, <= ETHERMTU, rather than + * a type field) with the first two bytes + * after the Ethernet/802.3 header being + * 0xFFFF; + * + * Ethernet_802.2 frames, which are 802.3 + * frames with an 802.2 LLC header and + * with the IPX LSAP as the DSAP in the LLC + * header; + * + * Ethernet_SNAP frames, which are 802.3 + * frames with an LLC header and a SNAP + * header and with an OUI of 0x000000 + * (encapsulated Ethernet) and a protocol + * ID of ETHERTYPE_IPX in the SNAP header. + * + * XXX - should we generate the same code both + * for tests for LLCSAP_IPX and for ETHERTYPE_IPX? + */ + + /* + * This generates code to check both for the + * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. + */ + b0 = gen_cmp(off_linktype + 2, BPF_B, (bpf_int32)LLCSAP_IPX); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32)0xFFFF); + gen_or(b0, b1); + + /* + * Now we add code to check for SNAP frames with + * ETHERTYPE_IPX, i.e. Ethernet_SNAP. + */ + b0 = gen_snap(0x000000, ETHERTYPE_IPX, 14); + gen_or(b0, b1); + + /* + * Now we generate code to check for 802.3 + * frames in general. + */ + b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * Now add the check for 802.3 frames before the + * check for Ethernet_802.2 and Ethernet_802.3, + * as those checks should only be done on 802.3 + * frames, not on Ethernet frames. + */ + gen_and(b0, b1); + + /* + * Now add the check for Ethernet_II frames, and + * do that before checking for the other frame + * types. + */ + b0 = gen_cmp(off_linktype, BPF_H, (bpf_int32)ETHERTYPE_IPX); + gen_or(b0, b1); + return b1; + + case ETHERTYPE_ATALK: + case ETHERTYPE_AARP: + /* + * EtherTalk (AppleTalk protocols on Ethernet link + * layer) may use 802.2 encapsulation. + */ + + /* + * Check for 802.2 encapsulation (EtherTalk phase 2?); + * we check for an Ethernet type field less than + * 1500, which means it's an 802.3 length field. + */ + b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * 802.2-encapsulated ETHERTYPE_AARP packets are + * SNAP packets with an organization code of + * 0x000000 (encapsulated Ethernet) and a protocol + * type of ETHERTYPE_AARP (Appletalk ARP). + */ + if (proto == ETHERTYPE_ATALK) + b1 = gen_snap(0x080007, ETHERTYPE_ATALK, 14); + else /* proto == ETHERTYPE_AARP */ + b1 = gen_snap(0x000000, ETHERTYPE_AARP, 14); + gen_and(b0, b1); + + /* + * Check for Ethernet encapsulation (Ethertalk + * phase 1?); we just check for the Ethernet + * protocol type. + */ + b0 = gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); + + gen_or(b0, b1); + return b1; + + default: + if (proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so the frames + * that match would be 802.2 frames. + * Check that the frame is an 802.2 frame + * (i.e., that the length/type field is + * a length field, <= ETHERMTU) and + * then check the DSAP. + */ + b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(off_linktype + 2, BPF_B, (bpf_int32)proto); + gen_and(b0, b1); + return b1; + } else { + /* + * This is an Ethernet type, so compare + * the length/type field with it (if + * the frame is an 802.2 frame, the length + * field will be <= ETHERMTU, and, as + * "proto" is > ETHERMTU, this test + * will fail and the frame won't match, + * which is what we want). + */ + return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); + } + } +} + static struct block * gen_linktype(proto) register int proto; { - struct block *b0, *b1; + struct block *b0, *b1, *b2; + + switch (linktype) { + + case DLT_EN10MB: + return gen_ether_linktype(proto); + + case DLT_C_HDLC: + switch (proto) { + + case LLCSAP_ISONS: + proto = (proto << 8 | LLCSAP_ISONS); + /*FALLTHROUGH*/ + default: + return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); + } + /*NOTREACHED*/ + break; + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO: + case DLT_FDDI: + case DLT_IEEE802: + case DLT_ATM_RFC1483: + case DLT_ATM_CLIP: + case DLT_IP_OVER_FC: + return gen_llc(proto); + + case DLT_SUNATM: + /* + * If "is_lane" is set, check for a LANE-encapsulated + * version of this protocol, otherwise check for an + * LLC-encapsulated version of this protocol. + * + * We assume LANE means Ethernet, not Token Ring. + */ + if (is_lane) { + /* + * Check that the packet doesn't begin with an + * LE Control marker. (We've already generated + * a test for LANE.) + */ + b0 = gen_cmp(SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(b0); + + /* + * Now generate an Ethernet test. + */ + b1 = gen_ether_linktype(proto); + gen_and(b0, b1); + return b1; + } else { + /* + * Check for LLC encapsulation and then check the + * protocol. + */ + b0 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + b1 = gen_llc(proto); + gen_and(b0, b1); + return b1; + } + + case DLT_LINUX_SLL: + switch (proto) { + + case LLCSAP_IP: + b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32) + ((LLCSAP_IP << 8) | LLCSAP_IP)); + gen_and(b0, b1); + return b1; + + case LLCSAP_ISONS: + /* + * OSI protocols always use 802.2 encapsulation. + * XXX - should we check both the DSAP and the + * LSAP, like this, or should we check just the + * DSAP? + */ + b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32) + ((LLCSAP_ISONS << 8) | LLCSAP_ISONS)); + gen_and(b0, b1); + return b1; + + case LLCSAP_NETBEUI: + /* + * NetBEUI always uses 802.2 encapsulation. + * XXX - should we check both the DSAP and the + * LSAP, like this, or should we check just the + * DSAP? + */ + b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(off_linktype + 2, BPF_H, (bpf_int32) + ((LLCSAP_NETBEUI << 8) | LLCSAP_NETBEUI)); + gen_and(b0, b1); + return b1; + + case LLCSAP_IPX: + /* + * Ethernet_II frames, which are Ethernet + * frames with a frame type of ETHERTYPE_IPX; + * + * Ethernet_802.3 frames, which have a frame + * type of LINUX_SLL_P_802_3; + * + * Ethernet_802.2 frames, which are 802.3 + * frames with an 802.2 LLC header (i.e, have + * a frame type of LINUX_SLL_P_802_2) and + * with the IPX LSAP as the DSAP in the LLC + * header; + * + * Ethernet_SNAP frames, which are 802.3 + * frames with an LLC header and a SNAP + * header and with an OUI of 0x000000 + * (encapsulated Ethernet) and a protocol + * ID of ETHERTYPE_IPX in the SNAP header. + * + * First, do the checks on LINUX_SLL_P_802_2 + * frames; generate the check for either + * Ethernet_802.2 or Ethernet_SNAP frames, and + * then put a check for LINUX_SLL_P_802_2 frames + * before it. + */ + b0 = gen_cmp(off_linktype + 2, BPF_B, + (bpf_int32)LLCSAP_IPX); + b1 = gen_snap(0x000000, ETHERTYPE_IPX, + off_linktype + 2); + gen_or(b0, b1); + b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_2); + gen_and(b0, b1); + + /* + * Now check for 802.3 frames and OR that with + * the previous test. + */ + b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_3); + gen_or(b0, b1); + + /* + * Now add the check for Ethernet_II frames, and + * do that before checking for the other frame + * types. + */ + b0 = gen_cmp(off_linktype, BPF_H, + (bpf_int32)ETHERTYPE_IPX); + gen_or(b0, b1); + return b1; + + case ETHERTYPE_ATALK: + case ETHERTYPE_AARP: + /* + * EtherTalk (AppleTalk protocols on Ethernet link + * layer) may use 802.2 encapsulation. + */ + + /* + * Check for 802.2 encapsulation (EtherTalk phase 2?); + * we check for the 802.2 protocol type in the + * "Ethernet type" field. + */ + b0 = gen_cmp(off_linktype, BPF_H, LINUX_SLL_P_802_2); + + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * 802.2-encapsulated ETHERTYPE_AARP packets are + * SNAP packets with an organization code of + * 0x000000 (encapsulated Ethernet) and a protocol + * type of ETHERTYPE_AARP (Appletalk ARP). + */ + if (proto == ETHERTYPE_ATALK) + b1 = gen_snap(0x080007, ETHERTYPE_ATALK, + off_linktype + 2); + else /* proto == ETHERTYPE_AARP */ + b1 = gen_snap(0x000000, ETHERTYPE_AARP, + off_linktype + 2); + gen_and(b0, b1); + + /* + * Check for Ethernet encapsulation (Ethertalk + * phase 1?); we just check for the Ethernet + * protocol type. + */ + b0 = gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); + + gen_or(b0, b1); + return b1; + + default: + if (proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so the frames + * that match would be 802.2 frames. + * Check for the 802.2 protocol type + * in the "Ethernet type" field, and + * then check the DSAP. + */ + b0 = gen_cmp(off_linktype, BPF_H, + LINUX_SLL_P_802_2); + b1 = gen_cmp(off_linktype + 2, BPF_B, + (bpf_int32)proto); + gen_and(b0, b1); + return b1; + } else { + /* + * This is an Ethernet type, so compare + * the length/type field with it (if + * the frame is an 802.2 frame, the length + * field will be <= ETHERMTU, and, as + * "proto" is > ETHERMTU, this test + * will fail and the frame won't match, + * which is what we want). + */ + return gen_cmp(off_linktype, BPF_H, + (bpf_int32)proto); + } + } + /*NOTREACHED*/ + break; + + case DLT_SLIP: + case DLT_SLIP_BSDOS: + case DLT_RAW: + /* + * These types don't provide any type field; packets + * are always IP. + * + * XXX - for IPv4, check for a version number of 4, and, + * for IPv6, check for a version number of 6? + */ + switch (proto) { + + case ETHERTYPE_IP: +#ifdef INET6 + case ETHERTYPE_IPV6: +#endif + return gen_true(); /* always true */ + + default: + return gen_false(); /* always false */ + } + + case DLT_PPP: + case DLT_PPP_SERIAL: + case DLT_PPP_ETHER: + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + switch (proto) { + + case ETHERTYPE_IP: + proto = PPP_IP; + break; + +#ifdef INET6 + case ETHERTYPE_IPV6: + proto = PPP_IPV6; + break; +#endif + + case ETHERTYPE_DN: + proto = PPP_DECNET; + break; + + case ETHERTYPE_ATALK: + proto = PPP_APPLE; + break; + + case ETHERTYPE_NS: + proto = PPP_NS; + break; + + case LLCSAP_ISONS: + proto = PPP_OSI; + break; + + case LLCSAP_8021D: + /* + * I'm assuming the "Bridging PDU"s that go + * over PPP are Spanning Tree Protocol + * Bridging PDUs. + */ + proto = PPP_BRPDU; + break; + + case LLCSAP_IPX: + proto = PPP_IPX; + break; + } + break; + + case DLT_PPP_BSDOS: + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + switch (proto) { + + case ETHERTYPE_IP: + b0 = gen_cmp(off_linktype, BPF_H, PPP_IP); + b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC); + gen_or(b0, b1); + b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC); + gen_or(b1, b0); + return b0; + +#ifdef INET6 + case ETHERTYPE_IPV6: + proto = PPP_IPV6; + /* more to go? */ + break; +#endif + + case ETHERTYPE_DN: + proto = PPP_DECNET; + break; + + case ETHERTYPE_ATALK: + proto = PPP_APPLE; + break; + + case ETHERTYPE_NS: + proto = PPP_NS; + break; + + case LLCSAP_ISONS: + proto = PPP_OSI; + break; + + case LLCSAP_8021D: + /* + * I'm assuming the "Bridging PDU"s that go + * over PPP are Spanning Tree Protocol + * Bridging PDUs. + */ + proto = PPP_BRPDU; + break; + + case LLCSAP_IPX: + proto = PPP_IPX; + break; + } + break; + + case DLT_NULL: + case DLT_LOOP: + case DLT_ENC: + /* + * For DLT_NULL, the link-layer header is a 32-bit + * word containing an AF_ value in *host* byte order, + * and for DLT_ENC, the link-layer header begins + * with a 32-bit work containing an AF_ value in + * host byte order. + * + * In addition, if we're reading a saved capture file, + * the host byte order in the capture may not be the + * same as the host byte order on this machine. + * + * For DLT_LOOP, the link-layer header is a 32-bit + * word containing an AF_ value in *network* byte order. + * + * XXX - AF_ values may, unfortunately, be platform- + * dependent; for example, FreeBSD's AF_INET6 is 24 + * whilst NetBSD's and OpenBSD's is 26. + * + * This means that, when reading a capture file, just + * checking for our AF_INET6 value won't work if the + * capture file came from another OS. + */ + switch (proto) { + + case ETHERTYPE_IP: + proto = AF_INET; + break; + +#ifdef INET6 + case ETHERTYPE_IPV6: + proto = AF_INET6; + break; +#endif + + default: + /* + * Not a type on which we support filtering. + * XXX - support those that have AF_ values + * #defined on this platform, at least? + */ + return gen_false(); + } + + if (linktype == DLT_NULL || linktype == DLT_ENC) { + /* + * The AF_ value is in host byte order, but + * the BPF interpreter will convert it to + * network byte order. + * + * If this is a save file, and it's from a + * machine with the opposite byte order to + * ours, we byte-swap the AF_ value. + * + * Then we run it through "htonl()", and + * generate code to compare against the result. + */ + if (bpf_pcap->sf.rfile != NULL && + bpf_pcap->sf.swapped) + proto = SWAPLONG(proto); + proto = htonl(proto); + } + return (gen_cmp(0, BPF_W, (bpf_int32)proto)); + + case DLT_PFLOG: + /* + * af field is host byte order in contrast to the rest of + * the packet. + */ + if (proto == ETHERTYPE_IP) + return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, + (bpf_int32)AF_INET)); +#ifdef INET6 + else if (proto == ETHERTYPE_IPV6) + return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, + (bpf_int32)AF_INET6)); +#endif /* INET6 */ + else + return gen_false(); + /*NOTREACHED*/ + break; + + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + /* + * XXX should we check for first fragment if the protocol + * uses PHDS? + */ + switch (proto) { + + default: + return gen_false(); + +#ifdef INET6 + case ETHERTYPE_IPV6: + return (gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_INET6)); +#endif /* INET6 */ + + case ETHERTYPE_IP: + b0 = gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_IP); + b1 = gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_IP_OLD); + gen_or(b0, b1); + return (b1); + + case ETHERTYPE_ARP: + b0 = gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_ARP); + b1 = gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_ARP_OLD); + gen_or(b0, b1); + return (b1); + + case ETHERTYPE_REVARP: + return (gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_REVARP)); + + case ETHERTYPE_ATALK: + return (gen_cmp(off_linktype, BPF_B, + (bpf_int32)ARCTYPE_ATALK)); + } + /*NOTREACHED*/ + break; + + case DLT_LTALK: + switch (proto) { + case ETHERTYPE_ATALK: + return gen_true(); + default: + return gen_false(); + } + /*NOTREACHED*/ + break; + + case DLT_FRELAY: + /* + * XXX - assumes a 2-byte Frame Relay header with + * DLCI and flags. What if the address is longer? + */ + switch (proto) { + + case ETHERTYPE_IP: + /* + * Check for the special NLPID for IP. + */ + return gen_cmp(2, BPF_H, (0x03<<8) | 0xcc); + +#ifdef INET6 + case ETHERTYPE_IPV6: + /* + * Check for the special NLPID for IPv6. + */ + return gen_cmp(2, BPF_H, (0x03<<8) | 0x8e); +#endif + + case LLCSAP_ISONS: + /* + * Check for several OSI protocols. + * + * Frame Relay packets typically have an OSI + * NLPID at the beginning; we check for each + * of them. + * + * What we check for is the NLPID and a frame + * control field of UI, i.e. 0x03 followed + * by the NLPID. + */ + b0 = gen_cmp(2, BPF_H, (0x03<<8) | ISO8473_CLNP); + b1 = gen_cmp(2, BPF_H, (0x03<<8) | ISO9542_ESIS); + b2 = gen_cmp(2, BPF_H, (0x03<<8) | ISO10589_ISIS); + gen_or(b1, b2); + gen_or(b0, b2); + return b2; + + default: + return gen_false(); + } + /*NOTREACHED*/ + break; + + case DLT_LINUX_IRDA: + bpf_error("IrDA link-layer type filtering not implemented"); + } /* * If we're not using encapsulation, compare the proto against @@ -720,7 +1821,7 @@ gen_linktype(proto) * * Note: this catches the RAWAF case. */ - if (off_linktype == -1) { + if (off_linktype == OFF_UNDEFINED) { switch (linktype_af) { case AF_UNSPEC: if (proto == ETHERTYPE_IP) @@ -740,130 +1841,134 @@ gen_linktype(proto) return gen_true(); else return gen_false(); - break; #ifdef INET6 case AF_INET6: if (proto == ETHERTYPE_IPV6) return gen_true(); else return gen_false(); - break; #endif } } - switch (linktype) { - - case DLT_SLIP: - return gen_false(); - - case DLT_PPP: - case DLT_PPP_SERIAL: - case DLT_PPP_ETHER: - if (proto == ETHERTYPE_IP) - proto = PPP_IP; -#ifdef INET6 - else if (proto == ETHERTYPE_IPV6) - proto = PPP_IPV6; -#endif /* INET6 */ - break; - - case DLT_PPP_BSDOS: - switch (proto) { - - case ETHERTYPE_IP: - b0 = gen_cmp(off_linktype, BPF_H, PPP_IP); - b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC); - gen_or(b0, b1); - b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC); - gen_or(b1, b0); - return b0; - -#ifdef INET6 - case ETHERTYPE_IPV6: - proto = PPP_IPV6; - /* more to go? */ - break; -#endif /* INET6 */ - - case ETHERTYPE_DN: - proto = PPP_DECNET; - break; - - case ETHERTYPE_ATALK: - proto = PPP_APPLE; - break; - - case ETHERTYPE_NS: - proto = PPP_NS; - break; - } - break; - - case DLT_NULL: - switch (proto) { - case ETHERTYPE_IP: - return (gen_cmp(0, BPF_W, (bpf_int32)htonl(AF_INET))); - break; -#ifdef INET6 - case ETHERTYPE_IPV6: - return (gen_cmp(0, BPF_W, (bpf_int32)htonl(AF_INET6))); - break; -#endif - default: - return gen_false(); - } - break; - - case DLT_PFLOG: - if (proto == ETHERTYPE_IP) - return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, - (bpf_int32)AF_INET)); -#ifdef INET6 - else if (proto == ETHERTYPE_IPV6) - return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, - (bpf_int32)AF_INET6)); -#endif /* INET6 */ - else - return gen_false(); - break; - - case DLT_ARCNET: - /* - * XXX should we check for first fragment if the protocol - * uses PHDS? - */ - switch(proto) { - default: - return gen_false(); -#ifdef INET6 - case ETHERTYPE_IPV6: - return(gen_cmp(2, BPF_B, - (bpf_int32)htonl(ARCTYPE_INET6))); -#endif /* INET6 */ - case ETHERTYPE_IP: - b0 = gen_cmp(2, BPF_B, (bpf_int32)htonl(ARCTYPE_IP)); - b1 = gen_cmp(2, BPF_B, - (bpf_int32)htonl(ARCTYPE_IP_OLD)); - gen_or(b0, b1); - return(b1); - case ETHERTYPE_ARP: - b0 = gen_cmp(2, BPF_B, (bpf_int32)htonl(ARCTYPE_ARP)); - b1 = gen_cmp(2, BPF_B, - (bpf_int32)htonl(ARCTYPE_ARP_OLD)); - gen_or(b0, b1); - return(b1); - case ETHERTYPE_REVARP: - return(gen_cmp(2, BPF_B, - (bpf_int32)htonl(ARCTYPE_REVARP))); - case ETHERTYPE_ATALK: - return(gen_cmp(2, BPF_B, - (bpf_int32)htonl(ARCTYPE_ATALK))); - } - } + /* + * Any type not handled above should always have an Ethernet + * type at an offset of "off_linktype". (PPP is partially + * handled above - the protocol type is mapped from the + * Ethernet and LLC types we use internally to the corresponding + * PPP type - but the PPP type is always specified by a value + * at "off_linktype", so we don't have to do the code generation + * above.) + */ return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); } +/* + * Check for an LLC SNAP packet with a given organization code and + * protocol type; we check the entire contents of the 802.2 LLC and + * snap headers, checking for DSAP and SSAP of SNAP and a control + * field of 0x03 in the LLC header, and for the specified organization + * code and protocol type in the SNAP header. + */ +static struct block * +gen_snap(orgcode, ptype, offset) + bpf_u_int32 orgcode; + bpf_u_int32 ptype; + u_int offset; +{ + u_char snapblock[8]; + + snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ + snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ + snapblock[2] = 0x03; /* control = UI */ + snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */ + snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */ + snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */ + snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */ + snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */ + return gen_bcmp(offset, 8, snapblock); +} + +/* + * Check for a given protocol value assuming an 802.2 LLC header. + */ +static struct block * +gen_llc(proto) + int proto; +{ + /* + * XXX - handle token-ring variable-length header. + */ + switch (proto) { + + case LLCSAP_IP: + return gen_cmp(off_linktype, BPF_H, (bpf_int32) + ((LLCSAP_IP << 8) | LLCSAP_IP)); + + case LLCSAP_ISONS: + return gen_cmp(off_linktype, BPF_H, (bpf_int32) + ((LLCSAP_ISONS << 8) | LLCSAP_ISONS)); + + case LLCSAP_NETBEUI: + return gen_cmp(off_linktype, BPF_H, (bpf_int32) + ((LLCSAP_NETBEUI << 8) | LLCSAP_NETBEUI)); + + case LLCSAP_IPX: + /* + * XXX - are there ever SNAP frames for IPX on + * non-Ethernet 802.x networks? + */ + return gen_cmp(off_linktype, BPF_B, (bpf_int32)LLCSAP_IPX); + + case ETHERTYPE_ATALK: + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * XXX - check for an organization code of + * encapsulated Ethernet as well? + */ + return gen_snap(0x080007, ETHERTYPE_ATALK, off_linktype); + + default: + /* + * XXX - we don't have to check for IPX 802.3 + * here, but should we check for the IPX Ethertype? + */ + if (proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so check + * the DSAP. + */ + return gen_cmp(off_linktype, BPF_B, (bpf_int32)proto); + } else { + /* + * This is an Ethernet type; we assume that it's + * unlikely that it'll appear in the right place + * at random, and therefore check only the + * location that would hold the Ethernet type + * in a SNAP frame with an organization code of + * 0x000000 (encapsulated Ethernet). + * + * XXX - if we were to check for the SNAP DSAP and + * LSAP, as per XXX, and were also to check for an + * organization code of 0x000000 (encapsulated + * Ethernet), we'd do + * + * return gen_snap(0x000000, proto, + * off_linktype); + * + * here; for now, we don't, as per the above. + * I don't know whether it's worth the extra CPU + * time to do the right check or not. + */ + return gen_cmp(off_linktype+6, BPF_H, (bpf_int32)proto); + } + } +} + static struct block * gen_hostop(addr, mask, dir, proto, src_off, dst_off) bpf_u_int32 addr; @@ -947,12 +2052,12 @@ gen_hostop6(addr, mask, dir, proto, src_off, dst_off) /* this order is important */ a = (u_int32_t *)addr; m = (u_int32_t *)mask; - b1 = gen_mcmp(offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); - b0 = gen_mcmp(offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); + b1 = gen_mcmp(offset + 12, BPF_W, (bpf_int32)ntohl(a[3]), ntohl(m[3])); + b0 = gen_mcmp(offset + 8, BPF_W, (bpf_int32)ntohl(a[2]), ntohl(m[2])); gen_and(b0, b1); - b0 = gen_mcmp(offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); + b0 = gen_mcmp(offset + 4, BPF_W, (bpf_int32)ntohl(a[1]), ntohl(m[1])); gen_and(b0, b1); - b0 = gen_mcmp(offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); + b0 = gen_mcmp(offset + 0, BPF_W, (bpf_int32)ntohl(a[0]), ntohl(m[0])); gen_and(b0, b1); b0 = gen_linktype(proto); gen_and(b0, b1); @@ -969,10 +2074,10 @@ gen_ehostop(eaddr, dir) switch (dir) { case Q_SRC: - return gen_bcmp(6, 6, eaddr); + return gen_bcmp(off_mac + 6, 6, eaddr); case Q_DST: - return gen_bcmp(0, 6, eaddr); + return gen_bcmp(off_mac + 0, 6, eaddr); case Q_AND: b0 = gen_ehostop(eaddr, Q_SRC); @@ -1033,6 +2138,382 @@ gen_fhostop(eaddr, dir) /* NOTREACHED */ } +/* + * Like gen_ehostop, but for DLT_IEEE802 (Token Ring) + */ +static struct block * +gen_thostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(8, 6, eaddr); + + case Q_DST: + return gen_bcmp(2, 6, eaddr); + + case Q_AND: + b0 = gen_thostop(eaddr, Q_SRC); + b1 = gen_thostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_thostop(eaddr, Q_SRC); + b1 = gen_thostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + } + abort(); + /* NOTREACHED */ +} + +/* + * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) + */ +static struct block * +gen_wlanhostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1, *b2; + register struct slist *s; + + switch (dir) { + case Q_SRC: + /* + * Oh, yuk. + * + * For control frames, there is no SA. + * + * For management frames, SA is at an + * offset of 10 from the beginning of + * the packet. + * + * For data frames, SA is at an offset + * of 10 from the beginning of the packet + * if From DS is clear, at an offset of + * 16 from the beginning of the packet + * if From DS is set and To DS is clear, + * and an offset of 24 from the beginning + * of the packet if From DS is set and To DS + * is set. + */ + + /* + * Generate the tests to be done for data frames + * with From DS set. + * + * First, check for To DS set, i.e. check "link[1] & 0x01". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the SA is at 24. + */ + b0 = gen_bcmp(24, 6, eaddr); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the SA is at 16. + */ + b1 = gen_bcmp(16, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames with + * From DS set. + */ + gen_or(b1, b0); + + /* + * Now check for From DS being set, and AND that with + * the ORed-together checks. + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x02; /* From DS */ + b1->stmts = s; + gen_and(b1, b0); + + /* + * Now check for data frames with From DS not set. + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x02; /* From DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If From DS isn't set, the SA is at 10. + */ + b1 = gen_bcmp(10, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the checks for data frames with + * From DS not set and for data frames with From DS + * set; that gives the checks done for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the SA is at 10. + */ + b1 = gen_bcmp(10, 6, eaddr); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + + case Q_DST: + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_bcmp(16, 6, eaddr); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_bcmp(4, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_bcmp(4, 6, eaddr); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + + case Q_AND: + b0 = gen_wlanhostop(eaddr, Q_SRC); + b1 = gen_wlanhostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_wlanhostop(eaddr, Q_SRC); + b1 = gen_wlanhostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + } + abort(); + /* NOTREACHED */ +} + +/* + * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel. + * (We assume that the addresses are IEEE 48-bit MAC addresses, + * as the RFC states.) + */ +static struct block * +gen_ipfchostop(eaddr, dir) + register const u_char *eaddr; + register int dir; +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(10, 6, eaddr); + + case Q_DST: + return gen_bcmp(2, 6, eaddr); + + case Q_AND: + b0 = gen_ipfchostop(eaddr, Q_SRC); + b1 = gen_ipfchostop(eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ipfchostop(eaddr, Q_SRC); + b1 = gen_ipfchostop(eaddr, Q_DST); + gen_or(b0, b1); + return b1; + } + abort(); + /* NOTREACHED */ +} + /* * This is quite tricky because there may be pad bytes in front of the * DECNET header, and then there are two possible data packet formats that @@ -1088,13 +2569,17 @@ gen_dnhostop(addr, dir, base_off) gen_or(b0, b1); return b1; + case Q_ISO: + bpf_error("ISO host filtering not implemented"); + /*NOTREACHED*/ default: abort(); + /*NOTREACHED*/ } b0 = gen_linktype(ETHERTYPE_DN); /* Check for pad = 1, long header case */ tmp = gen_mcmp(base_off + 2, BPF_H, - (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); + (bpf_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF)); b1 = gen_cmp(base_off + 2 + 1 + offset_lh, BPF_H, (bpf_int32)ntohs(addr)); gen_and(tmp, b1); @@ -1105,7 +2590,7 @@ gen_dnhostop(addr, dir, base_off) gen_or(b2, b1); /* Check for pad = 1, short header case */ tmp = gen_mcmp(base_off + 2, BPF_H, - (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF)); + (bpf_int32)ntohs(0x0281), (bpf_u_int32)ntohs(0x07FF)); b2 = gen_cmp(base_off + 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs(addr)); gen_and(tmp, b2); @@ -1134,10 +2619,12 @@ gen_host(addr, mask, proto, dir) case Q_DEFAULT: b0 = gen_host(addr, mask, Q_IP, dir); - b1 = gen_host(addr, mask, Q_ARP, dir); - gen_or(b0, b1); - b0 = gen_host(addr, mask, Q_RARP, dir); - gen_or(b1, b0); + if (off_linktype != OFF_UNDEFINED) { + b1 = gen_host(addr, mask, Q_ARP, dir); + gen_or(b0, b1); + b0 = gen_host(addr, mask, Q_RARP, dir); + gen_or(b1, b0); + } return b0; case Q_IP: @@ -1154,61 +2641,88 @@ gen_host(addr, mask, proto, dir) case Q_TCP: bpf_error("'tcp' modifier applied to host"); - + /*NOTREACHED*/ + case Q_SCTP: + bpf_error("'sctp' modifier applied to host"); + /*NOTREACHED*/ case Q_UDP: bpf_error("'udp' modifier applied to host"); - + /*NOTREACHED*/ case Q_ICMP: bpf_error("'icmp' modifier applied to host"); - + /*NOTREACHED*/ case Q_IGMP: bpf_error("'igmp' modifier applied to host"); - + /*NOTREACHED*/ case Q_IGRP: bpf_error("'igrp' modifier applied to host"); - + /*NOTREACHED*/ case Q_PIM: bpf_error("'pim' modifier applied to host"); - + /*NOTREACHED*/ case Q_VRRP: bpf_error("'vrrp' modifier applied to host"); - + /*NOTREACHED*/ case Q_ATALK: bpf_error("ATALK host filtering not implemented"); - + /*NOTREACHED*/ + case Q_AARP: + bpf_error("AARP host filtering not implemented"); + /*NOTREACHED*/ case Q_DECNET: return gen_dnhostop(addr, dir, off_nl); case Q_SCA: bpf_error("SCA host filtering not implemented"); - + /*NOTREACHED*/ case Q_LAT: bpf_error("LAT host filtering not implemented"); - + /*NOTREACHED*/ case Q_MOPDL: bpf_error("MOPDL host filtering not implemented"); - + /*NOTREACHED*/ case Q_MOPRC: bpf_error("MOPRC host filtering not implemented"); - + /*NOTREACHED*/ #ifdef INET6 case Q_IPV6: bpf_error("'ip6' modifier applied to ip host"); - + /*NOTREACHED*/ case Q_ICMPV6: bpf_error("'icmp6' modifier applied to host"); #endif /* INET6 */ - + /*NOTREACHED*/ case Q_AH: bpf_error("'ah' modifier applied to host"); - + /*NOTREACHED*/ case Q_ESP: bpf_error("'esp' modifier applied to host"); - + /*NOTREACHED*/ + case Q_ISO: + bpf_error("ISO host filtering not implemented"); + /*NOTREACHED*/ + case Q_ESIS: + bpf_error("'esis' modifier applied to host"); + /*NOTREACHED*/ + case Q_ISIS: + bpf_error("'isis' modifier applied to host"); + /*NOTREACHED*/ + case Q_CLNP: + bpf_error("'clnp' modifier applied to host"); + /*NOTREACHED*/ + case Q_STP: + bpf_error("'stp' modifier applied to host"); + /*NOTREACHED*/ + case Q_IPX: + bpf_error("IPX host filtering not implemented"); + /*NOTREACHED*/ + case Q_NETBEUI: + bpf_error("'netbeui' modifier applied to host"); + /*NOTREACHED*/ default: abort(); } - /* NOTREACHED */ + /*NOTREACHED*/ } #ifdef INET6 @@ -1226,65 +2740,92 @@ gen_host6(addr, mask, proto, dir) case Q_IP: bpf_error("'ip' modifier applied to ip6 host"); - + /*NOTREACHED*/ case Q_RARP: bpf_error("'rarp' modifier applied to ip6 host"); - + /*NOTREACHED*/ case Q_ARP: bpf_error("'arp' modifier applied to ip6 host"); - + /*NOTREACHED*/ + case Q_SCTP: + bpf_error("'sctp' modifier applied to host"); + /*NOTREACHED*/ case Q_TCP: bpf_error("'tcp' modifier applied to host"); - + /*NOTREACHED*/ case Q_UDP: bpf_error("'udp' modifier applied to host"); - + /*NOTREACHED*/ case Q_ICMP: bpf_error("'icmp' modifier applied to host"); - + /*NOTREACHED*/ case Q_IGMP: bpf_error("'igmp' modifier applied to host"); - + /*NOTREACHED*/ case Q_IGRP: bpf_error("'igrp' modifier applied to host"); - + /*NOTREACHED*/ case Q_PIM: bpf_error("'pim' modifier applied to host"); - + /*NOTREACHED*/ case Q_VRRP: bpf_error("'vrrp' modifier applied to host"); - + /*NOTREACHED*/ case Q_ATALK: bpf_error("ATALK host filtering not implemented"); - + /*NOTREACHED*/ + case Q_AARP: + bpf_error("AARP host filtering not implemented"); + /*NOTREACHED*/ case Q_DECNET: bpf_error("'decnet' modifier applied to ip6 host"); - + /*NOTREACHED*/ case Q_SCA: bpf_error("SCA host filtering not implemented"); - + /*NOTREACHED*/ case Q_LAT: bpf_error("LAT host filtering not implemented"); - + /*NOTREACHED*/ case Q_MOPDL: bpf_error("MOPDL host filtering not implemented"); - + /*NOTREACHED*/ case Q_MOPRC: bpf_error("MOPRC host filtering not implemented"); - + /*NOTREACHED*/ case Q_IPV6: return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, off_nl + 8, off_nl + 24); case Q_ICMPV6: bpf_error("'icmp6' modifier applied to host"); - + /*NOTREACHED*/ case Q_AH: bpf_error("'ah' modifier applied to host"); - + /*NOTREACHED*/ case Q_ESP: bpf_error("'esp' modifier applied to host"); - + /*NOTREACHED*/ + case Q_ISO: + bpf_error("ISO host filtering not implemented"); + /*NOTREACHED*/ + case Q_ESIS: + bpf_error("'esis' modifier applied to host"); + /*NOTREACHED*/ + case Q_ISIS: + bpf_error("'isis' modifier applied to host"); + /*NOTREACHED*/ + case Q_CLNP: + bpf_error("'clnp' modifier applied to host"); + /*NOTREACHED*/ + case Q_STP: + bpf_error("'stp' modifier applied to host"); + /*NOTREACHED*/ + case Q_IPX: + bpf_error("IPX host filtering not implemented"); + /*NOTREACHED*/ + case Q_NETBEUI: + bpf_error("'netbeui' modifier applied to host"); + /*NOTREACHED*/ default: abort(); } @@ -1314,9 +2855,29 @@ gen_gateway(eaddr, alist, proto, dir) b0 = gen_ehostop(eaddr, Q_OR); else if (linktype == DLT_FDDI) b0 = gen_fhostop(eaddr, Q_OR); + else if (linktype == DLT_IEEE802) + b0 = gen_thostop(eaddr, Q_OR); + else if (linktype == DLT_IEEE802_11) + b0 = gen_wlanhostop(eaddr, Q_OR); + else if (linktype == DLT_SUNATM && is_lane) { + /* + * Check that the packet doesn't begin with an + * LE Control marker. (We've already generated + * a test for LANE.) + */ + b1 = gen_cmp(SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(b1); + + /* + * Now check the MAC address. + */ + b0 = gen_ehostop(eaddr, Q_OR); + gen_and(b1, b0); + } else if (linktype == DLT_IP_OVER_FC) + b0 = gen_ipfchostop(eaddr, Q_OR); else bpf_error( - "'gateway' supported only on ethernet or FDDI"); + "'gateway' supported only on ethernet/FDDI/token ring/802.11/Fibre Channel"); b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR); while (*alist) { @@ -1331,19 +2892,25 @@ gen_gateway(eaddr, alist, proto, dir) bpf_error("illegal modifier of 'gateway'"); /* NOTREACHED */ } -#endif /*INET6*/ +#endif struct block * gen_proto_abbrev(proto) int proto; { -#ifdef INET6 struct block *b0; -#endif struct block *b1; switch (proto) { + case Q_SCTP: + b1 = gen_proto(IPPROTO_SCTP, Q_IP, Q_DEFAULT); +#ifdef INET6 + b0 = gen_proto(IPPROTO_SCTP, Q_IPV6, Q_DEFAULT); + gen_or(b0, b1); +#endif + break; + case Q_TCP: b1 = gen_proto(IPPROTO_TCP, Q_IP, Q_DEFAULT); #ifdef INET6 @@ -1413,11 +2980,15 @@ gen_proto_abbrev(proto) case Q_LINK: bpf_error("link layer applied in wrong context"); - + /*NOTREACHED*/ case Q_ATALK: b1 = gen_linktype(ETHERTYPE_ATALK); break; + case Q_AARP: + b1 = gen_linktype(ETHERTYPE_AARP); + break; + case Q_DECNET: b1 = gen_linktype(ETHERTYPE_DN); break; @@ -1473,6 +3044,94 @@ gen_proto_abbrev(proto) #endif break; + case Q_ISO: + b1 = gen_linktype(LLCSAP_ISONS); + break; + + case Q_ESIS: + b1 = gen_proto(ISO9542_ESIS, Q_ISO, Q_DEFAULT); + break; + + case Q_ISIS: + b1 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT); + break; + + case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */ + b0 = gen_proto(ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */ + b0 = gen_proto(ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */ + b0 = gen_proto(ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_LSP: + b0 = gen_proto(ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_SNP: + b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_CSNP: + b0 = gen_proto(ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_PSNP: + b0 = gen_proto(ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_CLNP: + b1 = gen_proto(ISO8473_CLNP, Q_ISO, Q_DEFAULT); + break; + + case Q_STP: + b1 = gen_linktype(LLCSAP_8021D); + break; + + case Q_IPX: + b1 = gen_linktype(LLCSAP_IPX); + break; + + case Q_NETBEUI: + b1 = gen_linktype(LLCSAP_NETBEUI); + break; + default: abort(); } @@ -1576,12 +3235,29 @@ gen_port(port, ip_proto, dir) { struct block *b0, *b1, *tmp; - /* ether proto ip */ + /* + * ether proto ip + * + * For FDDI, RFC 1188 says that SNAP encapsulation is used, + * not LLC encapsulation with LLCSAP_IP. + * + * For IEEE 802 networks - which includes 802.5 token ring + * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 + * says that SNAP encapsulation is used, not LLC encapsulation + * with LLCSAP_IP. + * + * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and + * RFC 2225 say that SNAP encapsulation is used, not LLC + * encapsulation with LLCSAP_IP. + * + * So we always check for ETHERTYPE_IP. + */ b0 = gen_linktype(ETHERTYPE_IP); switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: + case IPPROTO_SCTP: b1 = gen_portop(port, ip_proto, dir); break; @@ -1589,6 +3265,8 @@ gen_port(port, ip_proto, dir) tmp = gen_portop(port, IPPROTO_TCP, dir); b1 = gen_portop(port, IPPROTO_UDP, dir); gen_or(tmp, b1); + tmp = gen_portop(port, IPPROTO_SCTP, dir); + gen_or(tmp, b1); break; default: @@ -1652,6 +3330,7 @@ gen_port6(port, ip_proto, dir) switch (ip_proto) { case IPPROTO_UDP: case IPPROTO_TCP: + case IPPROTO_SCTP: b1 = gen_portop6(port, ip_proto, dir); break; @@ -1659,6 +3338,8 @@ gen_port6(port, ip_proto, dir) tmp = gen_portop6(port, IPPROTO_TCP, dir); b1 = gen_portop6(port, IPPROTO_UDP, dir); gen_or(tmp, b1); + tmp = gen_portop6(port, IPPROTO_SCTP, dir); + gen_or(tmp, b1); break; default: @@ -1680,6 +3361,7 @@ lookup_proto(name, proto) case Q_DEFAULT: case Q_IP: + case Q_IPV6: v = pcap_nametoproto(name); if (v == PROTO_UNDEF) bpf_error("unknown ip proto '%s'", name); @@ -1692,6 +3374,17 @@ lookup_proto(name, proto) bpf_error("unknown ether proto '%s'", name); break; + case Q_ISO: + if (strcmp(name, "esis") == 0) + v = ISO9542_ESIS; + else if (strcmp(name, "isis") == 0) + v = ISO10589_ISIS; + else if (strcmp(name, "clnp") == 0) + v = ISO8473_CLNP; + else + bpf_error("unknown osi proto '%s'", name); + break; + default: v = PROTO_UNDEF; break; @@ -1705,12 +3398,14 @@ gen_protochain(v, proto, dir) int proto; int dir; { +#ifdef NO_PROTOCHAIN + return gen_proto(v, proto, dir); +#else struct block *b0, *b; struct slist *s[100]; int fix2, fix3, fix4, fix5; int ahcheck, again, end; int i, max; - int reg1 = alloc_reg(); int reg2 = alloc_reg(); memset(s, 0, sizeof(s)); @@ -1754,6 +3449,7 @@ gen_protochain(v, proto, dir) s[i]->s.k = off_nl; i++; break; +#ifdef INET6 case Q_IPV6: b0 = gen_linktype(ETHERTYPE_IPV6); @@ -1766,6 +3462,7 @@ gen_protochain(v, proto, dir) s[i]->s.k = 40; i++; break; +#endif default: bpf_error("unsupported proto to gen_protochain"); /*NOTREACHED*/ @@ -1780,6 +3477,9 @@ gen_protochain(v, proto, dir) fix5 = i; i++; +#ifndef IPPROTO_NONE +#define IPPROTO_NONE 59 +#endif /* if (A == IPPROTO_NONE) goto end */ s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); s[i]->s.jt = NULL; /*later*/ @@ -1789,6 +3489,7 @@ gen_protochain(v, proto, dir) fix2 = i; i++; +#ifdef INET6 if (proto == Q_IPV6) { int v6start, v6end, v6advance, j; @@ -1826,15 +3527,22 @@ gen_protochain(v, proto, dir) /* * in short, - * A = P[X + 1]; - * X = X + (P[X] + 1) * 8; + * A = P[X]; + * X = X + (P[X + 1] + 1) * 8; */ /* A = X */ s[i] = new_stmt(BPF_MISC|BPF_TXA); i++; - /* MEM[reg1] = A */ + /* A = P[X + packet head] */ + s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = off_nl; + i++; + /* MEM[reg2] = A */ s[i] = new_stmt(BPF_ST); - s[i]->s.k = reg1; + s[i]->s.k = reg2; + i++; + /* A = X */ + s[i] = new_stmt(BPF_MISC|BPF_TXA); i++; /* A += 1 */ s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); @@ -1847,18 +3555,6 @@ gen_protochain(v, proto, dir) s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); s[i]->s.k = off_nl; i++; - /* MEM[reg2] = A */ - s[i] = new_stmt(BPF_ST); - s[i]->s.k = reg2; - i++; - /* X = MEM[reg1] */ - s[i] = new_stmt(BPF_LDX|BPF_MEM); - s[i]->s.k = reg1; - i++; - /* A = P[X + packet head] */ - s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); - s[i]->s.k = off_nl; - i++; /* A += 1 */ s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 1; @@ -1884,7 +3580,9 @@ gen_protochain(v, proto, dir) /* fixup */ for (j = v6start; j <= v6end; j++) s[j]->s.jt = s[v6advance]; - } else { + } else +#endif + { /* nop */ s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); s[i]->s.k = 0; @@ -1906,23 +3604,12 @@ gen_protochain(v, proto, dir) /* * in short, - * A = P[X + 1]; - * X = X + (P[X] + 2) * 4; + * A = P[X]; + * X = X + (P[X + 1] + 2) * 4; */ /* A = X */ s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); i++; - /* MEM[reg1] = A */ - s[i] = new_stmt(BPF_ST); - s[i]->s.k = reg1; - i++; - /* A += 1 */ - s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); - s[i]->s.k = 1; - i++; - /* X = A */ - s[i] = new_stmt(BPF_MISC|BPF_TAX); - i++; /* A = P[X + packet head]; */ s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); s[i]->s.k = off_nl; @@ -1931,9 +3618,15 @@ gen_protochain(v, proto, dir) s[i] = new_stmt(BPF_ST); s[i]->s.k = reg2; i++; - /* X = MEM[reg1] */ - s[i] = new_stmt(BPF_LDX|BPF_MEM); - s[i]->s.k = reg1; + /* A = X */ + s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); + i++; + /* A += 1 */ + s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 1; + i++; + /* X = A */ + s[i] = new_stmt(BPF_MISC|BPF_TAX); i++; /* A = P[X + packet head] */ s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); @@ -1984,11 +3677,11 @@ gen_protochain(v, proto, dir) b->stmts = s[1]; /*remember, s[0] is dummy*/ b->s.k = v; - free_reg(reg1); free_reg(reg2); gen_and(b0, b); return b; +#endif } static struct block * @@ -2013,6 +3706,21 @@ gen_proto(v, proto, dir) /*FALLTHROUGH*/ #endif case Q_IP: + /* + * For FDDI, RFC 1188 says that SNAP encapsulation is used, + * not LLC encapsulation with LLCSAP_IP. + * + * For IEEE 802 networks - which includes 802.5 token ring + * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 + * says that SNAP encapsulation is used, not LLC encapsulation + * with LLCSAP_IP. + * + * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and + * RFC 2225 say that SNAP encapsulation is used, not LLC + * encapsulation with LLCSAP_IP. + * + * So we always check for ETHERTYPE_IP. + */ b0 = gen_linktype(ETHERTYPE_IP); #ifndef CHASE_CHAIN b1 = gen_cmp(off_nl + 9, BPF_B, (bpf_int32)v); @@ -2022,6 +3730,58 @@ gen_proto(v, proto, dir) gen_and(b0, b1); return b1; + case Q_ISO: + switch (linktype) { + + case DLT_FRELAY: + /* + * Frame Relay packets typically have an OSI + * NLPID at the beginning; "gen_linktype(LLCSAP_ISONS)" + * generates code to check for all the OSI + * NLPIDs, so calling it and then adding a check + * for the particular NLPID for which we're + * looking is bogus, as we can just check for + * the NLPID. + * + * What we check for is the NLPID and a frame + * control field value of UI, i.e. 0x03 followed + * by the NLPID. + * + * XXX - assumes a 2-byte Frame Relay header with + * DLCI and flags. What if the address is longer? + * + * XXX - what about SNAP-encapsulated frames? + */ + return gen_cmp(2, BPF_H, (0x03<<8) | v); + + case DLT_C_HDLC: + /* + * Cisco uses an Ethertype lookalike - for OSI, + * it's 0xfefe. + */ + b0 = gen_linktype(LLCSAP_ISONS<<8 | LLCSAP_ISONS); + /* OSI in C-HDLC is stuffed with a fudge byte */ + b1 = gen_cmp(off_nl_nosnap+1, BPF_B, (bpf_int32)v); + gen_and(b0, b1); + return b1; + + default: + b0 = gen_linktype(LLCSAP_ISONS); + b1 = gen_cmp(off_nl_nosnap, BPF_B, (bpf_int32)v); + gen_and(b0, b1); + return b1; + } + + case Q_ISIS: + b0 = gen_proto(ISO10589_ISIS, Q_ISO, Q_DEFAULT); + /* + * 4 is the offset of the PDU type relative to the IS-IS + * header. + */ + b1 = gen_cmp(off_nl_nosnap+4, BPF_B, (bpf_int32)v); + gen_and(b0, b1); + return b1; + case Q_ARP: bpf_error("arp does not encapsulate another protocol"); /* NOTREACHED */ @@ -2065,6 +3825,10 @@ gen_proto(v, proto, dir) bpf_error("'tcp proto' is bogus"); /* NOTREACHED */ + case Q_SCTP: + bpf_error("'sctp proto' is bogus"); + /* NOTREACHED */ + case Q_ICMP: bpf_error("'icmp proto' is bogus"); /* NOTREACHED */ @@ -2098,14 +3862,24 @@ gen_proto(v, proto, dir) case Q_ICMPV6: bpf_error("'icmp6 proto' is bogus"); + /*NOTREACHED*/ #endif /* INET6 */ case Q_AH: bpf_error("'ah proto' is bogus"); - + /*NOTREACHED*/ case Q_ESP: bpf_error("'ah proto' is bogus"); - + /*NOTREACHED*/ + case Q_STP: + bpf_error("'stp proto' is bogus"); + /*NOTREACHED*/ + case Q_IPX: + bpf_error("'ipx proto' is bogus"); + /*NOTREACHED*/ + case Q_NETBEUI: + bpf_error("'netbeui proto' is bogus"); + /*NOTREACHED*/ default: abort(); /* NOTREACHED */ @@ -2159,34 +3933,85 @@ gen_scode(name, q) if (eaddr == NULL) bpf_error( "unknown ether host '%s'", name); - return gen_ehostop(eaddr, dir); + b = gen_ehostop(eaddr, dir); + free(eaddr); + return b; case DLT_FDDI: eaddr = pcap_ether_hostton(name); if (eaddr == NULL) bpf_error( "unknown FDDI host '%s'", name); - return gen_fhostop(eaddr, dir); + b = gen_fhostop(eaddr, dir); + free(eaddr); + return b; - default: - bpf_error( - "only ethernet/FDDI supports link-level host name"); - break; + case DLT_IEEE802: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown token ring host '%s'", name); + b = gen_thostop(eaddr, dir); + free(eaddr); + return b; + + case DLT_IEEE802_11: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown 802.11 host '%s'", name); + b = gen_wlanhostop(eaddr, dir); + free(eaddr); + return b; + + case DLT_IP_OVER_FC: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown Fibre Channel host '%s'", name); + b = gen_ipfchostop(eaddr, dir); + free(eaddr); + return b; + + case DLT_SUNATM: + if (!is_lane) + break; + + /* + * Check that the packet doesn't begin + * with an LE Control marker. (We've + * already generated a test for LANE.) + */ + tmp = gen_cmp(SUNATM_PKT_BEGIN_POS, BPF_H, + 0xFF00); + gen_not(tmp); + + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error( + "unknown ether host '%s'", name); + b = gen_ehostop(eaddr, dir); + gen_and(tmp, b); + free(eaddr); + return b; } + + bpf_error("only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name"); + /*NOTREACHED*/ } else if (proto == Q_DECNET) { unsigned short dn_addr = __pcap_nametodnaddr(name); /* * I don't think DECNET hosts can be multihomed, so * there is no need to build up a list of addresses */ - return (gen_host(dn_addr, 0, proto, dir)); + return (gen_host((bpf_u_int32)dn_addr, 0, proto, dir)); } else { #ifndef INET6 alist = pcap_nametoaddr(name); if (alist == NULL || *alist == NULL) bpf_error("unknown host '%s'", name); tproto = proto; - if (off_linktype == -1 && + if (off_linktype == OFF_UNDEFINED && (linktype_af == AF_UNSPEC || linktype_af == AF_INET) && tproto == Q_DEFAULT) @@ -2206,7 +4031,7 @@ gen_scode(name, q) bpf_error("unknown host '%s'", name); b = tmp = NULL; tproto = tproto6 = proto; - if (off_linktype == -1 && + if (off_linktype == OFF_UNDEFINED && (linktype_af == AF_UNSPEC || linktype_af == AF_INET || linktype_af == AF_INET6) && @@ -2219,29 +4044,31 @@ gen_scode(name, q) case AF_INET: if (tproto == Q_IPV6) continue; - if (off_linktype == -1 && + if (off_linktype == OFF_UNDEFINED && (linktype_af != AF_INET && linktype_af != AF_UNSPEC)) continue; sin = (struct sockaddr_in *) - res->ai_addr; + (void *)res->ai_addr; tmp = gen_host(ntohl(sin->sin_addr.s_addr), 0xffffffff, tproto, dir); break; case AF_INET6: if (tproto6 == Q_IP) continue; - if (off_linktype == -1 && + if (off_linktype == OFF_UNDEFINED && (linktype_af != AF_INET6 && linktype_af != AF_UNSPEC)) continue; sin6 = (struct sockaddr_in6 *) - res->ai_addr; + (void *)res->ai_addr; tmp = gen_host6(&sin6->sin6_addr, &mask128, tproto6, dir); break; + default: + continue; } if (b) gen_or(b, tmp); @@ -2259,13 +4086,16 @@ gen_scode(name, q) } case Q_PORT: - if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP) + if (proto != Q_DEFAULT && + proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) bpf_error("illegal qualifier of 'port'"); if (pcap_nametoport(name, &port, &real_proto) == 0) bpf_error("unknown port '%s'", name); if (proto == Q_UDP) { if (real_proto == IPPROTO_TCP) bpf_error("port '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error("port '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_UDP; @@ -2273,19 +4103,29 @@ gen_scode(name, q) if (proto == Q_TCP) { if (real_proto == IPPROTO_UDP) bpf_error("port '%s' is udp", name); + + else if (real_proto == IPPROTO_SCTP) + bpf_error("port '%s' is sctp", name); else /* override PROTO_UNDEF */ real_proto = IPPROTO_TCP; } + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error("port '%s' is udp", name); + + else if (real_proto == IPPROTO_TCP) + bpf_error("port '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_SCTP; + } #ifndef INET6 return gen_port(port, real_proto, dir); #else - { - struct block *b; b = gen_port(port, real_proto, dir); gen_or(gen_port6(port, real_proto, dir), b); return b; - } #endif /* INET6 */ case Q_GATEWAY: @@ -2297,25 +4137,31 @@ gen_scode(name, q) alist = pcap_nametoaddr(name); if (alist == NULL || *alist == NULL) bpf_error("unknown host '%s'", name); - return gen_gateway(eaddr, alist, proto, dir); + b = gen_gateway(eaddr, alist, proto, dir); + free(eaddr); + return b; #else bpf_error("'gateway' not supported in this configuration"); + /*NOTREACHED*/ #endif /*INET6*/ case Q_PROTO: real_proto = lookup_proto(name, proto); if (real_proto >= 0) return gen_proto(real_proto, proto, dir); - else + else { bpf_error("unknown protocol: %s", name); + /*NOTREACHED*/ + } case Q_PROTOCHAIN: real_proto = lookup_proto(name, proto); if (real_proto >= 0) return gen_protochain(real_proto, proto, dir); - else + else { bpf_error("unknown protocol: %s", name); - + /*NOTREACHED*/ + } case Q_UNDEF: syntax(); @@ -2362,7 +4208,7 @@ gen_mcode(s1, s2, masklen, q) default: bpf_error("Mask syntax for networks only"); - /* NOTREACHED */ + /*NOTREACHED*/ } } @@ -2393,6 +4239,7 @@ gen_ncode(s, v, q) return gen_host(v, 0, proto, dir); else if (proto == Q_LINK) { bpf_error("illegal link layer address"); + /*NOTREACHED*/ } else { mask = 0xffffffff; if (s == NULL && q.addr == Q_NET) { @@ -2414,6 +4261,8 @@ gen_ncode(s, v, q) proto = IPPROTO_UDP; else if (proto == Q_TCP) proto = IPPROTO_TCP; + else if (proto == Q_SCTP) + proto = IPPROTO_SCTP; else if (proto == Q_DEFAULT) proto = PROTO_UNDEF; else @@ -2455,7 +4304,7 @@ gen_ncode(s, v, q) struct block * gen_mcode6(s1, s2, masklen, q) register const char *s1, *s2; - register int masklen; + register u_int masklen; struct qual q; { struct addrinfo *res; @@ -2472,10 +4321,11 @@ gen_mcode6(s1, s2, masklen, q) bpf_error("invalid ip6 address %s", s1); if (res->ai_next) bpf_error("%s resolved to multiple address", s1); - addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + addr = &((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_addr; if (sizeof(mask) * 8 < masklen) bpf_error("mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); + memset(&mask, 0, sizeof(mask)); memset(&mask, 0xff, masklen / 8); if (masklen % 8) { mask.s6_addr[masklen / 8] = @@ -2514,11 +4364,36 @@ gen_ecode(eaddr, q) register const u_char *eaddr; struct qual q; { + struct block *b, *tmp; + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { if (linktype == DLT_EN10MB) return gen_ehostop(eaddr, (int)q.dir); if (linktype == DLT_FDDI) return gen_fhostop(eaddr, (int)q.dir); + if (linktype == DLT_IEEE802) + return gen_thostop(eaddr, (int)q.dir); + if (linktype == DLT_IEEE802_11) + return gen_wlanhostop(eaddr, (int)q.dir); + if (linktype == DLT_SUNATM && is_lane) { + /* + * Check that the packet doesn't begin with an + * LE Control marker. (We've already generated + * a test for LANE.) + */ + tmp = gen_cmp(SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(tmp); + + /* + * Now check the MAC address. + */ + b = gen_ehostop(eaddr, (int)q.dir); + gen_and(tmp, b); + return b; + } + if (linktype == DLT_IP_OVER_FC) + return gen_ipfchostop(eaddr, (int)q.dir); + bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); } bpf_error("ethernet address used in non-ether expression"); /* NOTREACHED */ @@ -2574,6 +4449,7 @@ gen_load(proto, index, size) default: bpf_error("data size must be 1, 2, or 4"); + /*NOTREACHED*/ case 1: size = BPF_B; @@ -2590,8 +4466,17 @@ gen_load(proto, index, size) switch (proto) { default: bpf_error("unsupported index operation"); + /*NOTREACHED*/ case Q_LINK: + /* + * XXX - what about ATM LANE? Should the index be + * relative to the beginning of the AAL5 frame, so + * that 0 refers to the beginning of the LE Control + * field, or relative to the beginning of the LAN + * frame, so that 0 refers, for Ethernet LANE, to + * the beginning of the destination address? + */ s = xfer_to_x(index); tmp = new_stmt(BPF_LD|BPF_IND|size); sappend(s, tmp); @@ -2610,7 +4495,7 @@ gen_load(proto, index, size) #ifdef INET6 case Q_IPV6: #endif - /* XXX Note that we assume a fixed link link header here. */ + /* XXX Note that we assume a fixed link header here. */ s = xfer_to_x(index); tmp = new_stmt(BPF_LD|BPF_IND|size); tmp->s.k = off_nl; @@ -2623,6 +4508,7 @@ gen_load(proto, index, size) index->b = b; break; + case Q_SCTP: case Q_TCP: case Q_UDP: case Q_ICMP: @@ -2779,6 +4665,7 @@ gen_arth(code, a0, a1) sappend(a1->s, s0); sappend(a0->s, a1->s); + free_reg(a0->regno); free_reg(a1->regno); s0 = new_stmt(BPF_ST); @@ -2848,6 +4735,9 @@ gen_greater(n) return gen_len(BPF_JGE, n); } +/* + * Actually, this is less than or equal. + */ struct block * gen_less(n) int n; @@ -2870,6 +4760,7 @@ gen_byteop(op, idx, val) switch (op) { default: abort(); + /*NOTREACHED*/ case '=': return gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); @@ -2915,12 +4806,34 @@ gen_broadcast(proto) case Q_DEFAULT: case Q_LINK: - if (linktype == DLT_ARCNET) + if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX) return gen_ahostop(abroadcast, Q_DST); if (linktype == DLT_EN10MB) return gen_ehostop(ebroadcast, Q_DST); if (linktype == DLT_FDDI) return gen_fhostop(ebroadcast, Q_DST); + if (linktype == DLT_IEEE802) + return gen_thostop(ebroadcast, Q_DST); + if (linktype == DLT_IEEE802_11) + return gen_wlanhostop(ebroadcast, Q_DST); + if (linktype == DLT_IP_OVER_FC) + return gen_ipfchostop(ebroadcast, Q_DST); + if (linktype == DLT_SUNATM && is_lane) { + /* + * Check that the packet doesn't begin with an + * LE Control marker. (We've already generated + * a test for LANE.) + */ + b1 = gen_cmp(SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(b1); + + /* + * Now check the MAC address. + */ + b0 = gen_ehostop(ebroadcast, Q_DST); + gen_and(b1, b0); + return b0; + } bpf_error("not a broadcast link"); break; @@ -2934,44 +4847,205 @@ gen_broadcast(proto) gen_and(b0, b2); return b2; } - bpf_error("only ether/ip broadcast filters supported"); + bpf_error("only link-layer/IP broadcast filters supported"); + /*NOTREACHED*/ +} + +/* + * Generate code to test the low-order bit of a MAC address (that's + * the bottom bit of the *first* byte). + */ +static struct block * +gen_mac_multicast(offset) + u_int offset; +{ + register struct block *b0; + register struct slist *s; + + /* link[offset] & 1 != 0 */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = offset; + b0 = new_block(JMP(BPF_JSET)); + b0->s.k = 1; + b0->stmts = s; + return b0; } struct block * gen_multicast(proto) int proto; { - register struct block *b0, *b1; + register struct block *b0, *b1, *b2; register struct slist *s; switch (proto) { case Q_DEFAULT: case Q_LINK: - if (linktype == DLT_ARCNET) + if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX) /* all ARCnet multicasts use the same address */ return gen_ahostop(abroadcast, Q_DST); if (linktype == DLT_EN10MB) { /* ether[0] & 1 != 0 */ - s = new_stmt(BPF_LD|BPF_B|BPF_ABS); - s->s.k = 0; - b0 = new_block(JMP(BPF_JSET)); - b0->s.k = 1; - b0->stmts = s; - return b0; + return gen_mac_multicast(0); } if (linktype == DLT_FDDI) { - /* XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX */ + /* + * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX + * + * XXX - was that referring to bit-order issues? + */ /* fddi[1] & 1 != 0 */ + return gen_mac_multicast(1); + } + + if (linktype == DLT_IEEE802) { + /* tr[2] & 1 != 0 */ + return gen_mac_multicast(2); + } + + if (linktype == DLT_IEEE802_11) { + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ s = new_stmt(BPF_LD|BPF_B|BPF_ABS); s->s.k = 1; - b0 = new_block(JMP(BPF_JSET)); - b0->s.k = 1; - b0->stmts = s; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_mac_multicast(16); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 1; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_mac_multicast(4); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b2 = new_block(JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_mac_multicast(4); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = new_stmt(BPF_LD|BPF_B|BPF_ABS); + s->s.k = 0; + b1 = new_block(JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); return b0; } + + if (linktype == DLT_IP_OVER_FC) { + b0 = gen_mac_multicast(2); + return b0; + } + + if (linktype == DLT_SUNATM && is_lane) { + /* + * Check that the packet doesn't begin with an + * LE Control marker. (We've already generated + * a test for LANE.) + */ + b1 = gen_cmp(SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(b1); + + /* ether[off_mac] & 1 != 0 */ + b0 = gen_mac_multicast(off_mac); + gen_and(b1, b0); + return b0; + } + /* Link not known to support multicasts */ break; @@ -2990,7 +5064,8 @@ gen_multicast(proto) return b1; #endif /* INET6 */ } - bpf_error("only IP multicast filters supported on ethernet/FDDI"); + bpf_error("link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); + /*NOTREACHED*/ } /* @@ -3005,13 +5080,36 @@ gen_inbound(dir) register struct block *b0; /* - * Only SLIP and old-style PPP data link types support - * inbound/outbound qualifiers. + * Only some data link types support inbound/outbound qualifiers. */ switch (linktype) { case DLT_SLIP: case DLT_PPP: - /* These are okay. */ + b0 = gen_relation(BPF_JEQ, + gen_load(Q_LINK, gen_loadi(0), 1), + gen_loadi(0), + dir); + break; + + case DLT_LINUX_SLL: + if (dir) { + /* + * Match packets sent by this machine. + */ + b0 = gen_cmp(0, BPF_H, LINUX_SLL_OUTGOING); + } else { + /* + * Match packets sent to this machine. + * (No broadcast or multicast packets, or + * packets sent to some other machine and + * received promiscuously.) + * + * XXX - packets sent to other machines probably + * shouldn't be matched, but what about broadcast + * or multicast packets we received? + */ + b0 = gen_cmp(0, BPF_H, LINUX_SLL_HOST); + } break; case DLT_PFLOG: @@ -3020,21 +5118,17 @@ gen_inbound(dir) break; default: - bpf_error("inbound/outbound not supported on linktype 0x%x\n", + bpf_error("inbound/outbound not supported on linktype %d", linktype); + b0 = NULL; /* NOTREACHED */ } - - b0 = gen_relation(BPF_JEQ, - gen_load(Q_LINK, gen_loadi(0), 1), - gen_loadi(0), - dir); return (b0); } /* PF firewall log matched interface */ struct block * -gen_pf_ifname(char *ifname) +gen_pf_ifname(const char *ifname) { struct block *b0; u_int len, off; @@ -3043,15 +5137,16 @@ gen_pf_ifname(char *ifname) len = sizeof(((struct pfloghdr *)0)->ifname); off = offsetof(struct pfloghdr, ifname); } else { - bpf_error("ifname not supported on linktype 0x%x\n", linktype); + bpf_error("ifname not supported on linktype 0x%x", linktype); /* NOTREACHED */ } if (strlen(ifname) >= len) { - bpf_error("ifname interface names can only be %d characters\n", - len - 1); + bpf_error("ifname interface names can only be %d characters", + len-1); /* NOTREACHED */ } - b0 = gen_bcmp(off, strlen(ifname), ifname); + b0 = gen_bcmp(off, strlen(ifname), + (const u_char *)(const void *)ifname); return (b0); } @@ -3062,20 +5157,19 @@ gen_pf_ruleset(char *ruleset) struct block *b0; if (linktype != DLT_PFLOG) { - bpf_error("ruleset not supported on linktype 0x%x\n", linktype); + bpf_error("ruleset not supported on linktype 0x%x", linktype); /* NOTREACHED */ } if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { - bpf_error("ruleset names can only be %d characters\n", - (int)sizeof(((struct pfloghdr *)0)->ruleset) - 1); + bpf_error("ruleset names can only be %ld characters", + (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); /* NOTREACHED */ } b0 = gen_bcmp(offsetof(struct pfloghdr, ruleset), - strlen(ruleset), ruleset); + strlen(ruleset), (const u_char *)(void *)ruleset); return (b0); } - /* PF firewall log rule number */ struct block * gen_pf_rnr(int rnr) @@ -3084,9 +5178,9 @@ gen_pf_rnr(int rnr) if (linktype == DLT_PFLOG) { b0 = gen_cmp(offsetof(struct pfloghdr, rulenr), BPF_W, - (bpf_int32)rnr); + (bpf_int32)rnr); } else { - bpf_error("rnr not supported on linktype 0x%x\n", linktype); + bpf_error("rnr not supported on linktype 0x%x", linktype); /* NOTREACHED */ } @@ -3100,7 +5194,7 @@ gen_pf_srnr(int srnr) struct block *b0; if (linktype != DLT_PFLOG) { - bpf_error("srnr not supported on linktype 0x%x\n", linktype); + bpf_error("srnr not supported on linktype 0x%x", linktype); /* NOTREACHED */ } @@ -3119,7 +5213,7 @@ gen_pf_reason(int reason) b0 = gen_cmp(offsetof(struct pfloghdr, reason), BPF_B, (bpf_int32)reason); } else { - bpf_error("reason not supported on linktype 0x%x\n", linktype); + bpf_error("reason not supported on linktype 0x%x", linktype); /* NOTREACHED */ } @@ -3136,7 +5230,7 @@ gen_pf_action(int action) b0 = gen_cmp(offsetof(struct pfloghdr, action), BPF_B, (bpf_int32)action); } else { - bpf_error("action not supported on linktype 0x%x\n", linktype); + bpf_error("action not supported on linktype 0x%x", linktype); /* NOTREACHED */ } @@ -3149,7 +5243,7 @@ gen_acode(eaddr, q) struct qual q; { if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { - if (linktype == DLT_ARCNET) + if (linktype == DLT_ARCNET || linktype == DLT_ARCNET_LINUX) return gen_ahostop(eaddr, (int)q.dir); } bpf_error("ARCnet address used in non-arc expression"); @@ -3201,14 +5295,16 @@ gen_vlan(vlan_num) * Change the offsets to point to the type and data fields within * the VLAN packet. This is somewhat of a kludge. */ - if (orig_nl == (u_int)-1) { + if (orig_nl == OFF_UNDEFINED) { orig_linktype = off_linktype; /* save original values */ orig_nl = off_nl; + orig_nl_nosnap = off_nl_nosnap; switch (linktype) { case DLT_EN10MB: off_linktype = 16; + off_nl_nosnap = 18; off_nl = 18; break; @@ -3233,3 +5329,274 @@ gen_vlan(vlan_num) return (b0); } + +struct block * +gen_atmfield_code(atmfield, jvalue, jtype, reverse) + int atmfield; + bpf_u_int32 jvalue; + bpf_u_int32 jtype; + int reverse; +{ + struct block *b0; + + switch (atmfield) { + + case A_VPI: + if (!is_atm) + bpf_error("'vpi' supported only on raw ATM"); + if (off_vpi == OFF_UNDEFINED) + abort(); + b0 = gen_ncmp(BPF_B, off_vpi, 0xffffffff, (u_int)jtype, + (u_int)jvalue, reverse); + break; + + case A_VCI: + if (!is_atm) + bpf_error("'vci' supported only on raw ATM"); + if (off_vci == OFF_UNDEFINED) + abort(); + b0 = gen_ncmp(BPF_H, off_vci, 0xffffffff, (u_int)jtype, + (u_int)jvalue, reverse); + break; + + case A_PROTOTYPE: + if (off_proto == OFF_UNDEFINED) + abort(); /* XXX - this isn't on FreeBSD */ + b0 = gen_ncmp(BPF_B, off_proto, 0x0f, (u_int)jtype, + (u_int)jvalue, reverse); + break; + + case A_MSGTYPE: + if (off_payload == OFF_UNDEFINED) + abort(); + b0 = gen_ncmp(BPF_B, off_payload + MSG_TYPE_POS, 0xffffffff, + (u_int)jtype, (u_int)jvalue, reverse); + break; + + case A_CALLREFTYPE: + if (!is_atm) + bpf_error("'callref' supported only on raw ATM"); + if (off_proto == OFF_UNDEFINED) + abort(); + b0 = gen_ncmp(BPF_B, off_proto, 0xffffffff, (u_int)jtype, + (u_int)jvalue, reverse); + break; + + default: + abort(); + } + return b0; +} + +struct block * +gen_atmtype_abbrev(type) + int type; +{ + struct block *b0, *b1; + + switch (type) { + + case A_METAC: + /* Get all packets in Meta signalling Circuit */ + if (!is_atm) + bpf_error("'metac' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 1, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_BCC: + /* Get all packets in Broadcast Circuit*/ + if (!is_atm) + bpf_error("'bcc' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 2, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4SC: + /* Get all cells in Segment OAM F4 circuit*/ + if (!is_atm) + bpf_error("'oam4sc' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4EC: + /* Get all cells in End-to-End OAM F4 Circuit*/ + if (!is_atm) + bpf_error("'oam4ec' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_SC: + /* Get all packets in connection Signalling Circuit */ + if (!is_atm) + bpf_error("'sc' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 5, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_ILMIC: + /* Get all packets in ILMI Circuit */ + if (!is_atm) + bpf_error("'ilmic' supported only on raw ATM"); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 16, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_LANE: + /* Get all LANE packets */ + if (!is_atm) + bpf_error("'lane' supported only on raw ATM"); + b1 = gen_atmfield_code(A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); + + /* + * Arrange that all subsequent tests assume LANE + * rather than LLC-encapsulated packets, and set + * the offsets appropriately for LANE-encapsulated + * Ethernet. + * + * "off_mac" is the offset of the Ethernet header, + * which is 2 bytes past the ATM pseudo-header + * (skipping the pseudo-header and 2-byte LE Client + * field). The other offsets are Ethernet offsets + * relative to "off_mac". + */ + is_lane = 1; + off_mac = off_payload + 2; /* MAC header */ + off_linktype = off_mac + 12; + off_nl = off_mac + 14; /* Ethernet II */ + off_nl_nosnap = off_mac + 17; /* 802.3+802.2 */ + break; + + case A_LLC: + /* Get all LLC-encapsulated packets */ + if (!is_atm) + bpf_error("'llc' supported only on raw ATM"); + b1 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + is_lane = 0; + break; + + default: + abort(); + } + return b1; +} + + +static struct block * +gen_msg_abbrev(type) + int type; +{ + struct block *b1; + + /* + * Q.2931 signalling protocol messages for handling virtual circuits + * establishment and teardown + */ + switch (type) { + + case A_SETUP: + b1 = gen_atmfield_code(A_MSGTYPE, SETUP, BPF_JEQ, 0); + break; + + case A_CALLPROCEED: + b1 = gen_atmfield_code(A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); + break; + + case A_CONNECT: + b1 = gen_atmfield_code(A_MSGTYPE, CONNECT, BPF_JEQ, 0); + break; + + case A_CONNECTACK: + b1 = gen_atmfield_code(A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); + break; + + case A_RELEASE: + b1 = gen_atmfield_code(A_MSGTYPE, RELEASE, BPF_JEQ, 0); + break; + + case A_RELEASE_DONE: + b1 = gen_atmfield_code(A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); + break; + + default: + abort(); + } + return b1; +} + +struct block * +gen_atmmulti_abbrev(type) + int type; +{ + struct block *b0, *b1; + + switch (type) { + + case A_OAM: + if (!is_atm) + bpf_error("'oam' supported only on raw ATM"); + b1 = gen_atmmulti_abbrev(A_OAMF4); + break; + + case A_OAMF4: + if (!is_atm) + bpf_error("'oamf4' supported only on raw ATM"); + /* OAM F4 type */ + b0 = gen_atmfield_code(A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code(A_VCI, 4, BPF_JEQ, 0); + gen_or(b0, b1); + b0 = gen_atmfield_code(A_VPI, 0, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_CONNECTMSG: + /* + * Get Q.2931 signalling messages for switched + * virtual connection + */ + if (!is_atm) + bpf_error("'connectmsg' supported only on raw ATM"); + b0 = gen_msg_abbrev(A_SETUP); + b1 = gen_msg_abbrev(A_CALLPROCEED); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_CONNECT); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_CONNECTACK); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE_DONE); + gen_or(b0, b1); + b0 = gen_atmtype_abbrev(A_SC); + gen_and(b0, b1); + break; + + case A_METACONNECT: + if (!is_atm) + bpf_error("'metaconnect' supported only on raw ATM"); + b0 = gen_msg_abbrev(A_SETUP); + b1 = gen_msg_abbrev(A_CALLPROCEED); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_CONNECT); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE); + gen_or(b0, b1); + b0 = gen_msg_abbrev(A_RELEASE_DONE); + gen_or(b0, b1); + b0 = gen_atmtype_abbrev(A_METAC); + gen_and(b0, b1); + break; + + default: + abort(); + } + return b1; +} diff --git a/lib/libpcap/gencode.h b/lib/libpcap/gencode.h index 1d23136e7eda..1b6ed9cf7d6e 100644 --- a/lib/libpcap/gencode.h +++ b/lib/libpcap/gencode.h @@ -1,4 +1,4 @@ -/* $NetBSD: gencode.h,v 1.13 2004/06/25 12:22:23 itojun Exp $ */ +/* $NetBSD: gencode.h,v 1.14 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 @@ -20,11 +20,42 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * @(#) Header: gencode.h,v 1.36 96/07/17 00:11:34 leres Exp (LBL) + * @(#) Header: /tcpdump/master/libpcap/gencode.h,v 1.58.2.1 2004/03/28 21:45:31 fenner Exp (LBL) */ -/*XXX*/ -#include "gnuc.h" +/* + * ATM support: + * + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + * North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* Address qualifiers. */ @@ -41,28 +72,54 @@ #define Q_IP 2 #define Q_ARP 3 #define Q_RARP 4 -#define Q_TCP 5 -#define Q_UDP 6 -#define Q_ICMP 7 -#define Q_IGMP 8 -#define Q_IGRP 9 +#define Q_SCTP 5 +#define Q_TCP 6 +#define Q_UDP 7 +#define Q_ICMP 8 +#define Q_IGMP 9 +#define Q_IGRP 10 -#define Q_ATALK 10 -#define Q_DECNET 11 -#define Q_LAT 12 -#define Q_SCA 13 -#define Q_MOPRC 14 -#define Q_MOPDL 15 +#define Q_ATALK 11 +#define Q_DECNET 12 +#define Q_LAT 13 +#define Q_SCA 14 +#define Q_MOPRC 15 +#define Q_MOPDL 16 -#define Q_IPV6 16 -#define Q_ICMPV6 17 -#define Q_AH 18 -#define Q_ESP 19 +#define Q_IPV6 17 +#define Q_ICMPV6 18 +#define Q_AH 19 +#define Q_ESP 20 -#define Q_PIM 20 -#define Q_VRRP 21 +#define Q_PIM 21 +#define Q_VRRP 22 + +#define Q_AARP 23 + +#define Q_ISO 24 +#define Q_ESIS 25 +#define Q_ISIS 26 +#define Q_CLNP 27 + +#define Q_STP 28 + +#define Q_IPX 29 + +#define Q_NETBEUI 30 + +/* IS-IS Levels */ +#define Q_ISIS_L1 31 +#define Q_ISIS_L2 32 +/* PDU types */ +#define Q_ISIS_IIH 33 +#define Q_ISIS_LAN_IIH 34 +#define Q_ISIS_PTP_IIH 35 +#define Q_ISIS_SNP 36 +#define Q_ISIS_CSNP 37 +#define Q_ISIS_PSNP 38 +#define Q_ISIS_LSP 39 /* Directional qualifiers. */ @@ -74,6 +131,43 @@ #define Q_DEFAULT 0 #define Q_UNDEF 255 +/* ATM types */ +#define A_METAC 22 /* Meta signalling Circuit */ +#define A_BCC 23 /* Broadcast Circuit */ +#define A_OAMF4SC 24 /* Segment OAM F4 Circuit */ +#define A_OAMF4EC 25 /* End-to-End OAM F4 Circuit */ +#define A_SC 26 /* Signalling Circuit*/ +#define A_ILMIC 27 /* ILMI Circuit */ +#define A_OAM 28 /* OAM cells : F4 only */ +#define A_OAMF4 29 /* OAM F4 cells: Segment + End-to-end */ +#define A_LANE 30 /* LANE traffic */ +#define A_LLC 31 /* LLC-encapsulated traffic */ + +/* Based on Q.2931 signalling protocol */ +#define A_SETUP 41 /* Setup message */ +#define A_CALLPROCEED 42 /* Call proceeding message */ +#define A_CONNECT 43 /* Connect message */ +#define A_CONNECTACK 44 /* Connect Ack message */ +#define A_RELEASE 45 /* Release message */ +#define A_RELEASE_DONE 46 /* Release message */ + +/* ATM field types */ +#define A_VPI 51 +#define A_VCI 52 +#define A_PROTOTYPE 53 +#define A_MSGTYPE 54 +#define A_CALLREFTYPE 55 + +#define A_CONNECTMSG 70 /* returns Q.2931 signalling messages for + establishing and destroying switched + virtual connection */ +#define A_METACONNECT 71 /* returns Q.2931 signalling messages for + establishing and destroying predefined + virtual circuits, such as broadcast + circuit, oamf4 segment circuit, oamf4 + end-to-end circuits, ILMI circuits or + connection signalling circuit. */ + struct slist; struct stmt { @@ -168,7 +262,7 @@ struct block *gen_ecode(const u_char *, struct qual); struct block *gen_acode(const u_char *, struct qual); struct block *gen_mcode(const char *, const char *, int, struct qual); #ifdef INET6 -struct block *gen_mcode6(const char *, const char *, int, struct qual); +struct block *gen_mcode6(const char *, const char *, u_int, struct qual); #endif struct block *gen_ncode(const char *, bpf_u_int32, struct qual); struct block *gen_proto_abbrev(int); @@ -181,7 +275,13 @@ struct block *gen_multicast(int); struct block *gen_inbound(int); struct block *gen_vlan(int); -struct block *gen_pf_ifname(char *); +struct block *gen_vlan(int); + +struct block *gen_atmfield_code(int atmfield, bpf_u_int32 jvalue, bpf_u_int32 jtype, int reverse); +struct block *gen_atmtype_abbrev(int type); +struct block *gen_atmmulti_abbrev(int type); + +struct block *gen_pf_ifname(const char *); struct block *gen_pf_rnr(int); struct block *gen_pf_srnr(int); struct block *gen_pf_ruleset(char *); @@ -190,10 +290,9 @@ struct block *gen_pf_action(int); struct block *gen_pf_dir(int); void bpf_optimize(struct block **); -#if __STDC__ -__dead void bpf_error(const char *, ...) - __attribute__((volatile, format (printf, 1, 2))); -#endif +void bpf_error(const char *, ...) + __attribute__((noreturn, format (printf, 1, 2))) +; void finish_parse(struct block *); char *sdup(const char *); @@ -203,6 +302,7 @@ struct bpf_insn *icode_to_fcode(struct block *, int *); int pcap_parse(void); #endif void lex_init(char *); +void lex_cleanup(void); void sappend(struct slist *, struct slist *); /* XXX */ diff --git a/lib/libpcap/gnuc.h b/lib/libpcap/gnuc.h deleted file mode 100644 index e547d95bbfa4..000000000000 --- a/lib/libpcap/gnuc.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $NetBSD: gnuc.h,v 1.4 1997/10/03 15:53:07 christos Exp $ */ - -/* @(#) Header: gnuc.h,v 1.3 95/10/09 02:47:01 leres Exp (LBL) */ - -/* Define __P() macro, if necessary */ -#ifndef __P -#if __STDC__ -#define __P(protos) protos -#else -#define __P(protos) () -#endif -#endif - -/* inline foo */ -#ifdef __GNUC__ -#define inline __inline -#else -#define inline -#endif - -/* - * Handle new and old "dead" routine prototypes - * - * For example: - * - * __dead void foo(void) __attribute__((volatile)); - * - */ -#ifdef __GNUC__ -#ifndef __dead -#define __dead volatile -#endif -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) -#ifndef __attribute__ -#define __attribute__(args) -#endif -#endif -#else -#ifndef __dead -#define __dead -#endif -#ifndef __attribute__ -#define __attribute__(args) -#endif -#endif diff --git a/lib/libpcap/grammar.y b/lib/libpcap/grammar.y index 8d2f5dd7f8b2..dc9802ce6258 100644 --- a/lib/libpcap/grammar.y +++ b/lib/libpcap/grammar.y @@ -1,5 +1,5 @@ %{ -/* $NetBSD: grammar.y,v 1.10 2004/06/25 12:22:23 itojun Exp $ */ +/* $NetBSD: grammar.y,v 1.11 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 @@ -26,31 +26,42 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: grammar.y,v 1.56 96/11/02 21:54:55 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/grammar.y,v 1.79.2.3 2004/03/28 21:45:32 fenner Exp (LBL)"; #else -__RCSID("$NetBSD: grammar.y,v 1.10 2004/06/25 12:22:23 itojun Exp $"); +__RCSID("$NetBSD: grammar.y,v 1.11 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ #include #include #include +#endif /* WIN32 */ +#include + +#ifndef WIN32 #if __STDC__ struct mbuf; struct rtentry; #endif -#include - #include #ifdef __NetBSD__ +#include #include #else #include #endif #include +#endif /* WIN32 */ #include #include @@ -60,7 +71,6 @@ struct rtentry; #include "gencode.h" #include -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -102,6 +112,7 @@ pcap_parse() struct arth *a; struct { struct qual q; + int atmfieldtype; struct block *b; } blk; struct block *rblk; @@ -114,11 +125,14 @@ pcap_parse() %type byteop pname pnum relop irelop %type and or paren not null prog %type other pfvar +%type atmtype atmmultitype +%type atmfield +%type atmfieldvalue atmvalue atmlistvalue %token DST SRC HOST GATEWAY -%token NET MASK PORT LESS GREATER PROTO PROTOCHAIN BYTE -%token ARP RARP IP TCP UDP ICMP IGMP IGRP PIM VRRP -%token ATALK DECNET LAT SCA MOPRC MOPDL +%token NET NETMASK PORT LESS GREATER PROTO PROTOCHAIN CBYTE +%token ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP +%token ATALK AARP DECNET LAT SCA MOPRC MOPDL %token TK_BROADCAST TK_MULTICAST %token NUM INBOUND OUTBOUND %token PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION @@ -129,6 +143,13 @@ pcap_parse() %token LEN %token IPV6 ICMPV6 AH ESP %token VLAN +%token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP +%token STP +%token IPX +%token NETBEUI +%token LANE LLC METAC BCC SC ILMIC OAMF4EC OAMF4SC +%token OAM OAMF4 CONNECTMSG METACONNECT +%token VPI VCI %type ID %type EID @@ -171,23 +192,17 @@ id: nid nid: ID { $$.b = gen_scode($1, $$.q = $0.q); } | HID '/' NUM { $$.b = gen_mcode($1, NULL, $3, $$.q = $0.q); } - | HID MASK HID { $$.b = gen_mcode($1, $3, 0, + | HID NETMASK HID { $$.b = gen_mcode($1, $3, 0, $$.q = $0.q); } | HID { /* Decide how to parse HID based on proto */ $$.q = $0.q; - switch ($$.q.proto) { - case Q_DECNET: - $$.b = gen_ncode($1, 0, $$.q); - break; - default: - $$.b = gen_ncode($1, 0, $$.q); - break; - } + $$.b = gen_ncode($1, 0, $$.q); } | HID6 '/' NUM { #ifdef INET6 - $$.b = gen_mcode6($1, NULL, $3, + $$.b = gen_mcode6($1, NULL, + (u_int)$3, /* XXX */ $$.q = $0.q); #else bpf_error("'ip6addr/prefixlen' not supported " @@ -203,8 +218,24 @@ nid: ID { $$.b = gen_scode($1, $$.q = $0.q); } "in this configuration"); #endif /*INET6*/ } - | EID { $$.b = gen_ecode($1, $$.q = $0.q); } - | AID { $$.b = gen_acode($1, $$.q = $0.q); } + | EID { + $$.b = gen_ecode($1, $$.q = $0.q); + /* + * $1 was allocated by "pcap_ether_aton()", + * so we must free it now that we're done + * with it. + */ + free($1); + } + | AID { + $$.b = gen_acode($1, $$.q = $0.q); + /* + * $1 was allocated by "pcap_ether_aton()", + * so we must free it now that we're done + * with it. + */ + free($1); + } | not id { gen_not($2.b); $$ = $2; } ; not: '!' { $$ = $0; } @@ -237,6 +268,9 @@ rterm: head id { $$ = $2; } | arth irelop arth { $$.b = gen_relation($2, $1, $3, 1); $$.q = qerr; } | other { $$.b = $1; $$.q = qerr; } + | atmtype { $$.b = gen_atmtype_abbrev($1); $$.q = qerr; } + | atmmultitype { $$.b = gen_atmmulti_abbrev($1); $$.q = qerr; } + | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; } ; /* protocol level qualifiers */ pqual: pname @@ -262,6 +296,7 @@ pname: LINK { $$ = Q_LINK; } | IP { $$ = Q_IP; } | ARP { $$ = Q_ARP; } | RARP { $$ = Q_RARP; } + | SCTP { $$ = Q_SCTP; } | TCP { $$ = Q_TCP; } | UDP { $$ = Q_UDP; } | ICMP { $$ = Q_ICMP; } @@ -270,6 +305,7 @@ pname: LINK { $$ = Q_LINK; } | PIM { $$ = Q_PIM; } | VRRP { $$ = Q_VRRP; } | ATALK { $$ = Q_ATALK; } + | AARP { $$ = Q_AARP; } | DECNET { $$ = Q_DECNET; } | LAT { $$ = Q_LAT; } | SCA { $$ = Q_SCA; } @@ -279,12 +315,26 @@ pname: LINK { $$ = Q_LINK; } | ICMPV6 { $$ = Q_ICMPV6; } | AH { $$ = Q_AH; } | ESP { $$ = Q_ESP; } + | ISO { $$ = Q_ISO; } + | ESIS { $$ = Q_ESIS; } + | ISIS { $$ = Q_ISIS; } + | L1 { $$ = Q_ISIS_L1; } + | L2 { $$ = Q_ISIS_L2; } + | IIH { $$ = Q_ISIS_IIH; } + | LSP { $$ = Q_ISIS_LSP; } + | SNP { $$ = Q_ISIS_SNP; } + | PSNP { $$ = Q_ISIS_PSNP; } + | CSNP { $$ = Q_ISIS_CSNP; } + | CLNP { $$ = Q_CLNP; } + | STP { $$ = Q_STP; } + | IPX { $$ = Q_IPX; } + | NETBEUI { $$ = Q_NETBEUI; } ; other: pqual TK_BROADCAST { $$ = gen_broadcast($1); } | pqual TK_MULTICAST { $$ = gen_multicast($1); } | LESS NUM { $$ = gen_less($2); } | GREATER NUM { $$ = gen_greater($2); } - | BYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); } + | CBYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); } | INBOUND { $$ = gen_inbound(0); } | OUTBOUND { $$ = gen_inbound(1); } | VLAN pnum { $$ = gen_vlan($2); } @@ -304,7 +354,7 @@ reason: NUM { $$ = $1; } | ID { const char *reasons[] = PFRES_NAMES; int i; for (i = 0; reasons[i]; i++) { - if (strcasecmp($1, reasons[i]) == 0) { + if (pcap_strcasecmp($1, reasons[i]) == 0) { $$ = i; break; } @@ -314,11 +364,11 @@ reason: NUM { $$ = $1; } } ; -action: ID { if (strcasecmp($1, "pass") == 0 || - strcasecmp($1, "accept") == 0) +action: ID { if (pcap_strcasecmp($1, "pass") == 0 || + pcap_strcasecmp($1, "accept") == 0) $$ = PF_PASS; - else if (strcasecmp($1, "drop") == 0 || - strcasecmp($1, "block") == 0) + else if (pcap_strcasecmp($1, "drop") == 0 || + pcap_strcasecmp($1, "block") == 0) $$ = PF_DROP; else bpf_error("unknown PF action"); @@ -359,4 +409,37 @@ byteop: '&' { $$ = '&'; } pnum: NUM | paren pnum ')' { $$ = $2; } ; +atmtype: LANE { $$ = A_LANE; } + | LLC { $$ = A_LLC; } + | METAC { $$ = A_METAC; } + | BCC { $$ = A_BCC; } + | OAMF4EC { $$ = A_OAMF4EC; } + | OAMF4SC { $$ = A_OAMF4SC; } + | SC { $$ = A_SC; } + | ILMIC { $$ = A_ILMIC; } + ; +atmmultitype: OAM { $$ = A_OAM; } + | OAMF4 { $$ = A_OAMF4; } + | CONNECTMSG { $$ = A_CONNECTMSG; } + | METACONNECT { $$ = A_METACONNECT; } + ; + /* ATM field types quantifier */ +atmfield: VPI { $$.atmfieldtype = A_VPI; } + | VCI { $$.atmfieldtype = A_VCI; } + ; +atmvalue: atmfieldvalue + | relop NUM { $$.b = gen_atmfield_code($0.atmfieldtype, (u_int)$2, (u_int)$1, 0); } + | irelop NUM { $$.b = gen_atmfield_code($0.atmfieldtype, (u_int)$2, (u_int)$1, 1); } + | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; } + ; +atmfieldvalue: NUM { + $$.atmfieldtype = $0.atmfieldtype; + if ($$.atmfieldtype == A_VPI || + $$.atmfieldtype == A_VCI) + $$.b = gen_atmfield_code($$.atmfieldtype, (u_int) $1, BPF_JEQ, 0); + } + ; +atmlistvalue: atmfieldvalue + | atmlistvalue or atmfieldvalue { gen_or($1.b, $3.b); $$ = $3; } + ; %% diff --git a/lib/libpcap/inet.c b/lib/libpcap/inet.c index 5c6602d4be9f..bab0785b3ee3 100644 --- a/lib/libpcap/inet.c +++ b/lib/libpcap/inet.c @@ -1,7 +1,8 @@ -/* $NetBSD: inet.c,v 1.9 2004/09/07 13:20:40 jrf Exp $ */ +/* $NetBSD: inet.c,v 1.10 2004/09/27 23:02:53 dyoung Exp $ */ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* - * Copyright (c) 1994, 1995, 1996, 1997 + * Copyright (c) 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,12 +38,20 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: inet.c,v 1.21 97/07/17 14:24:58 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/inet.c,v 1.58.2.1 2003/11/15 23:26:41 guy Exp (LBL)"; #else -__RCSID("$NetBSD: inet.c,v 1.9 2004/09/07 13:20:40 jrf Exp $"); +__RCSID("$NetBSD: inet.c,v 1.10 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ + #include #include #include @@ -52,13 +61,11 @@ __RCSID("$NetBSD: inet.c,v 1.9 2004/09/07 13:20:40 jrf Exp $"); #endif #include /* concession to AIX */ -#if __STDC__ -struct mbuf; -struct rtentry; -#endif - +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ #include #include +#endif /* WIN32 */ #include #include @@ -66,26 +73,392 @@ struct rtentry; #include #include #include +#ifndef WIN32 #include +#endif /* WIN32 */ +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#endif #ifdef HAVE_IFADDRS_H #include #endif #include "pcap-int.h" -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif /* Not all systems have IFF_LOOPBACK */ #ifdef IFF_LOOPBACK -#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK) +#define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK) #else -#define ISLOOPBACK(p) ((p)->ifr_name[0] == 'l' && (p)->ifr_name[1] == 'o' && \ - (isdigit((p)->ifr_name[2]) || (p)->ifr_name[2] == '\0')) +#define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \ + (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0')) #endif +struct sockaddr * +dup_sockaddr(struct sockaddr *sa, size_t sa_length) +{ + struct sockaddr *newsa; + + if ((newsa = malloc(sa_length)) == NULL) + return (NULL); + return (memcpy(newsa, sa, sa_length)); +} + +static int +get_instance(const char *name) +{ + const char *cp, *endcp; + int n; + + if (strcmp(name, "any") == 0) { + /* + * Give the "any" device an artificially high instance + * number, so it shows up after all other non-loopback + * interfaces. + */ + return INT_MAX; + } + + endcp = name + strlen(name); + for (cp = name; cp < endcp && !isdigit((unsigned char)*cp); ++cp) + continue; + + if (isdigit((unsigned char)*cp)) + n = atoi(cp); + else + n = 0; + return (n); +} + +int +add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, + u_int flags, const char *description, char *errbuf) +{ + pcap_if_t *curdev, *prevdev, *nextdev; + int this_instance; + + /* + * Is there already an entry in the list for this interface? + */ + for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { + if (strcmp(name, curdev->name) == 0) + break; /* yes, we found it */ + } + if (curdev == NULL) { + /* + * No, we didn't find it. + * Allocate a new entry. + */ + curdev = malloc(sizeof(pcap_if_t)); + if (curdev == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Fill in the entry. + */ + curdev->next = NULL; + curdev->name = malloc(strlen(name) + 1); + strcpy(curdev->name, name); + if (description != NULL) { + /* + * We have a description for this interface. + */ + curdev->description = malloc(strlen(description) + 1); + strcpy(curdev->description, description); + } else { + /* + * We don't. + */ + curdev->description = NULL; + } + curdev->addresses = NULL; /* list starts out as empty */ + curdev->flags = 0; + if (ISLOOPBACK(name, flags)) + curdev->flags |= PCAP_IF_LOOPBACK; + + /* + * Add it to the list, in the appropriate location. + * First, get the instance number of this interface. + */ + this_instance = get_instance(name); + + /* + * Now look for the last interface with an instance number + * less than or equal to the new interface's instance + * number - except that non-loopback interfaces are + * arbitrarily treated as having interface numbers less + * than those of loopback interfaces, so the loopback + * interfaces are put at the end of the list. + * + * We start with "prevdev" being NULL, meaning we're before + * the first element in the list. + */ + prevdev = NULL; + for (;;) { + /* + * Get the interface after this one. + */ + if (prevdev == NULL) { + /* + * The next element is the first element. + */ + nextdev = *alldevs; + } else + nextdev = prevdev->next; + + /* + * Are we at the end of the list? + */ + if (nextdev == NULL) { + /* + * Yes - we have to put the new entry + * after "prevdev". + */ + break; + } + + /* + * Is the new interface a non-loopback interface + * and the next interface a loopback interface? + */ + if (!(curdev->flags & PCAP_IF_LOOPBACK) && + (nextdev->flags & PCAP_IF_LOOPBACK)) { + /* + * Yes, we should put the new entry + * before "nextdev", i.e. after "prevdev". + */ + break; + } + + /* + * Is the new interface's instance number less + * than the next interface's instance number, + * and is it the case that the new interface is a + * non-loopback interface or the next interface is + * a loopback interface? + * + * (The goal of both loopback tests is to make + * sure that we never put a loopback interface + * before any non-loopback interface and that we + * always put a non-loopback interface before all + * loopback interfaces.) + */ + if (this_instance < get_instance(nextdev->name) && + (!(curdev->flags & PCAP_IF_LOOPBACK) || + (nextdev->flags & PCAP_IF_LOOPBACK))) { + /* + * Yes - we should put the new entry + * before "nextdev", i.e. after "prevdev". + */ + break; + } + + prevdev = nextdev; + } + + /* + * Insert before "nextdev". + */ + curdev->next = nextdev; + + /* + * Insert after "prevdev" - unless "prevdev" is null, + * in which case this is the first interface. + */ + if (prevdev == NULL) { + /* + * This is the first interface. Pass back a + * pointer to it, and put "curdev" before + * "nextdev". + */ + *alldevs = curdev; + } else + prevdev->next = curdev; + } + + *curdev_ret = curdev; + return (0); +} + +int +add_addr_to_iflist(pcap_if_t **alldevs, char *name, u_int flags, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_if_t *curdev; + pcap_addr_t *curaddr, *prevaddr, *nextaddr; + + if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) { + /* + * Error - give up. + */ + return (-1); + } + if (curdev == NULL) { + /* + * Device wasn't added because it can't be opened. + * Not a fatal error. + */ + return (0); + } + + /* + * "curdev" is an entry for this interface; add an entry for this + * address to its list of addresses. + * + * Allocate the new entry and fill it in. + */ + curaddr = malloc(sizeof(pcap_addr_t)); + if (curaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + curaddr->next = NULL; + if (addr != NULL) { + curaddr->addr = dup_sockaddr(addr, addr_size); + if (curaddr->addr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curaddr); + return (-1); + } + } else + curaddr->addr = NULL; + + if (netmask != NULL) { + curaddr->netmask = dup_sockaddr(netmask, netmask_size); + if (curaddr->netmask == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curaddr); + return (-1); + } + } else + curaddr->netmask = NULL; + + if (broadaddr != NULL) { + curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); + if (curaddr->broadaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curaddr); + return (-1); + } + } else + curaddr->broadaddr = NULL; + + if (dstaddr != NULL) { + curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); + if (curaddr->dstaddr == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curaddr); + return (-1); + } + } else + curaddr->dstaddr = NULL; + + /* + * Find the end of the list of addresses. + */ + for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { + nextaddr = prevaddr->next; + if (nextaddr == NULL) { + /* + * This is the end of the list. + */ + break; + } + } + + if (prevaddr == NULL) { + /* + * The list was empty; this is the first member. + */ + curdev->addresses = curaddr; + } else { + /* + * "prevaddr" is the last member of the list; append + * this member to it. + */ + prevaddr->next = curaddr; + } + + return (0); +} + +int +pcap_add_if(pcap_if_t **devlist, char *name, u_int flags, + const char *description, char *errbuf) +{ + pcap_if_t *curdev; + + return (add_or_find_if(&curdev, devlist, name, flags, description, + errbuf)); +} + + +/* + * Free a list of interfaces. + */ +void +pcap_freealldevs(pcap_if_t *alldevs) +{ + pcap_if_t *curdev, *nextdev; + pcap_addr_t *curaddr, *nextaddr; + + for (curdev = alldevs; curdev != NULL; curdev = nextdev) { + nextdev = curdev->next; + + /* + * Free all addresses. + */ + for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) { + nextaddr = curaddr->next; + if (curaddr->addr) + free(curaddr->addr); + if (curaddr->netmask) + free(curaddr->netmask); + if (curaddr->broadaddr) + free(curaddr->broadaddr); + if (curaddr->dstaddr) + free(curaddr->dstaddr); + free(curaddr); + } + + /* + * Free the name string. + */ + free(curdev->name); + + /* + * Free the description string, if any. + */ + if (curdev->description != NULL) + free(curdev->description); + + /* + * Free the interface. + */ + free(curdev); + } +} + +#ifndef WIN32 + /* * Return the name of a network interface attached to the system, or NULL * if none can be found. The interface must be configured up; the @@ -95,138 +468,47 @@ char * pcap_lookupdev(errbuf) register char *errbuf; { -#ifdef HAVE_IFADDRS_H - struct ifaddrs *ifap, *ifa, *mp; - int n, minunit; - char *cp; + pcap_if_t *alldevs; +/* for old BSD systems, including bsdi3 */ +#ifndef IF_NAMESIZE +#define IF_NAMESIZE IFNAMSIZ +#endif static char device[IF_NAMESIZE + 1]; + char *ret; - if (getifaddrs(&ifap) != 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "getifaddrs: %s", pcap_strerror(errno)); - return NULL; - } - - mp = NULL; - minunit = 666; - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if ((ifa->ifa_flags & IFF_UP) == 0) - continue; -#ifdef IFF_LOOPBACK - if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) - continue; -#else - if (strncmp(ifa->ifa_name, "lo", 2) == 0 && - (ifa->ifa_name[2] == '\0' || isdigit(ifa->ifa_name[2]))) { - continue; - } -#endif - - for (cp = ifa->ifa_name; !isdigit(*cp); ++cp) - continue; - n = atoi(cp); - if (n < minunit) { - minunit = n; - mp = ifa; - } - } - if (mp == NULL) { - (void)strncpy(errbuf, "no suitable device found", - PCAP_ERRBUF_SIZE); - freeifaddrs(ifap); + if (pcap_findalldevs(&alldevs, errbuf) == -1) return (NULL); - } - (void)strlcpy(device, mp->ifa_name, sizeof(device)); - freeifaddrs(ifap); - return (device); -#else - register int fd, minunit, n; - register char *cp; - register struct ifreq *ifrp, *ifend, *ifnext, *mp; - struct ifconf ifc; - struct ifreq ibuf[16], ifr; - static char device[sizeof(ifrp->ifr_name) + 1]; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", - pcap_strerror(errno)); - return (NULL); - } - ifc.ifc_len = sizeof ibuf; - ifc.ifc_buf = (caddr_t)ibuf; - - memset((char *)ibuf, 0, sizeof(ibuf)); - if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || - ifc.ifc_len < sizeof(struct ifreq)) { - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFCONF: %s", - pcap_strerror(errno)); - (void)close(fd); - return (NULL); - } - ifrp = ibuf; - ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); - - mp = NULL; - minunit = 666; - for (; ifrp < ifend; ifrp = ifnext) { -#ifdef HAVE_SOCKADDR_SA_LEN - n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); - if (n < sizeof(*ifrp)) - ifnext = ifrp + 1; - else - ifnext = (struct ifreq *)((char *)ifrp + n); - if (ifrp->ifr_addr.sa_family != AF_INET) - continue; -#else - ifnext = ifrp + 1; -#endif + if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) { /* - * Need a template to preserve address info that is - * used below to locate the next entry. (Otherwise, - * SIOCGIFFLAGS stomps over it because the requests - * are returned in a union.) + * There are no devices on the list, or the first device + * on the list is a loopback device, which means there + * are no non-loopback devices on the list. This means + * we can't return any device. + * + * XXX - why not return a loopback device? If we can't + * capture on it, it won't be on the list, and if it's + * on the list, there aren't any non-loopback devices, + * so why not just supply it as the default device? */ - strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); - if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { - if (errno == ENXIO) - continue; - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFFLAGS: %.*s: %s", - (int)sizeof(ifr.ifr_name), ifr.ifr_name, - pcap_strerror(errno)); - (void)close(fd); - return (NULL); - } - - /* Must be up and not the loopback */ - if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr)) - continue; - - for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) - continue; - n = atoi(cp); - if (n < minunit) { - minunit = n; - mp = ifrp; - } - } - (void)close(fd); - if (mp == NULL) { - (void)strncpy(errbuf, "no suitable device found", - PCAP_ERRBUF_SIZE - 1); - return (NULL); + (void)strlcpy(errbuf, "no suitable device found", + PCAP_ERRBUF_SIZE); + ret = NULL; + } else { + /* + * Return the name of the first device on the list. + */ + (void)strlcpy(device, alldevs->name, sizeof(device)); + ret = device; } - (void)strlcpy(device, mp->ifr_name, sizeof(device)); - return (device); -#endif + pcap_freealldevs(alldevs); + return (ret); } int pcap_lookupnet(device, netp, maskp, errbuf) - register char *device; + register const char *device; register bpf_u_int32 *netp, *maskp; register char *errbuf; { @@ -234,6 +516,20 @@ pcap_lookupnet(device, netp, maskp, errbuf) register struct sockaddr_in *sin; struct ifreq ifr; + /* + * The pseudo-device "any" listens on all interfaces and therefore + * has the network address and -mask "0.0.0.0" therefore catching + * all traffic. Using NULL for the interface is the same as "any". + */ + if (!device || strcmp(device, "any") == 0 +#ifdef HAVE_DAG_API + || strstr(device, "dag") != NULL +#endif + ) { + *netp = *maskp = 0; + return 0; + } + fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", @@ -284,3 +580,121 @@ pcap_lookupnet(device, netp, maskp, errbuf) *netp &= *maskp; return (0); } + +#else /* WIN32 */ + +/* + * Return the name of a network interface attached to the system, or NULL + * if none can be found. The interface must be configured up; the + * lowest unit number is preferred; loopback is ignored. + */ +char * +pcap_lookupdev(errbuf) + register char *errbuf; +{ + DWORD dwVersion; + DWORD dwWindowsMajorVersion; + dwVersion = GetVersion(); /* get the OS version */ + dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + + if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { + /* + * Windows 95, 98, ME. + */ + ULONG NameLength = 8192; + static char AdaptersName[8192]; + + PacketGetAdapterNames(AdaptersName,&NameLength); + + return (AdaptersName); + } else { + /* + * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility + */ + ULONG NameLength = 8192; + static WCHAR AdaptersName[8192]; + char *tAstr; + WCHAR *tUstr; + WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR)); + int NAdapts = 0; + + if(TAdaptersName == NULL) + { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); + return NULL; + } + + PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength); + + tAstr = (char*)TAdaptersName; + tUstr = (WCHAR*)AdaptersName; + + /* + * Convert and copy the device names + */ + while(sscanf(tAstr, "%S", tUstr) > 0) + { + tAstr += strlen(tAstr) + 1; + tUstr += wcslen(tUstr) + 1; + NAdapts ++; + } + + tAstr++; + *tUstr = 0; + tUstr++; + + /* + * Copy the descriptions + */ + while(NAdapts--) + { + strcpy((char*)tUstr, tAstr); + (char*)tUstr += strlen(tAstr) + 1;; + tAstr += strlen(tAstr) + 1; + } + + return (char *)(AdaptersName); + } +} + + +int +pcap_lookupnet(device, netp, maskp, errbuf) + const register char *device; + register bpf_u_int32 *netp, *maskp; + register char *errbuf; +{ + /* + * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo() + * in order to skip non IPv4 (i.e. IPv6 addresses) + */ + npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; + LONG if_addr_size = 1; + struct sockaddr_in *t_addr; + unsigned int i; + + if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { + *netp = *maskp = 0; + return (0); + } + + for(i=0; isin_addr.S_un.S_addr; + t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask); + *maskp = t_addr->sin_addr.S_un.S_addr; + + *netp &= *maskp; + return (0); + } + + } + + *netp = *maskp = 0; + return (0); +} + +#endif /* WIN32 */ diff --git a/lib/libpcap/nametoaddr.c b/lib/libpcap/nametoaddr.c index 325f2a9a31b8..51de1950cb35 100644 --- a/lib/libpcap/nametoaddr.c +++ b/lib/libpcap/nametoaddr.c @@ -1,7 +1,7 @@ -/* $NetBSD: nametoaddr.c,v 1.13 2000/04/14 14:18:40 itojun Exp $ */ +/* $NetBSD: nametoaddr.c,v 1.14 2004/09/27 23:02:53 dyoung Exp $ */ /* - * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,26 +28,48 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: nametoaddr.c,v 1.47 97/06/13 13:16:19 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/nametoaddr.c,v 1.68.2.3 2003/11/19 18:13:48 guy Exp (LBL)"; #else -__RCSID("$NetBSD: nametoaddr.c,v 1.13 2000/04/14 14:18:40 itojun Exp $"); +__RCSID("$NetBSD: nametoaddr.c,v 1.14 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include + +#else /* WIN32 */ + #include #include /* concession to AIX */ #include #include -#if __STDC__ -struct mbuf; -struct rtentry; +#include +#endif /* WIN32 */ + +/* + * XXX - why was this included even on UNIX? + */ +#ifdef __MINGW32__ +#include "IP6_misc.h" #endif -#include -#include +#ifndef WIN32 +#ifdef HAVE_ETHER_HOSTTON +#ifdef HAVE_NETINET_IF_ETHER_H +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include /* for "struct ifnet" in "struct arpcom" on Solaris */ #include +#endif /* HAVE_NETINET_IF_ETHER_H */ +#endif /* HAVE_ETHER_HOSTTON */ #include +#include +#endif /* WIN32 */ #ifdef INET6 #include #include @@ -57,7 +79,6 @@ struct rtentry; #include #include #include -#include #include #include "pcap-int.h" @@ -65,7 +86,6 @@ struct rtentry; #include "gencode.h" #include -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -75,7 +95,7 @@ struct rtentry; #define NTOHS(x) (x) = ntohs(x) #endif -static inline int xdtoi(int); +static __inline int xdtoi(int); /* * Convert host name to internet address. @@ -130,12 +150,19 @@ pcap_nametoaddrinfo(const char *name) bpf_u_int32 pcap_nametonetaddr(const char *name) { +#ifndef WIN32 struct netent *np; if ((np = getnetbyname(name)) != NULL) return np->n_net; else return 0; +#else + /* + * There's no "getnetbyname()" on Windows. + */ + return 0; +#endif } /* @@ -147,38 +174,40 @@ int pcap_nametoport(const char *name, int *port, int *proto) { struct servent *sp; - char *other; + int tcp_port = -1; + int udp_port = -1; - sp = getservbyname(name, (char *)0); - if (sp != NULL) { - NTOHS(sp->s_port); - *port = sp->s_port; - *proto = pcap_nametoproto(sp->s_proto); - /* - * We need to check /etc/services for ambiguous entries. - * If we find the ambiguous entry, and it has the - * same port number, change the proto to PROTO_UNDEF - * so both TCP and UDP will be checked. - */ - if (*proto == IPPROTO_TCP) - other = "udp"; - else - other = "tcp"; - - sp = getservbyname(name, other); - if (sp != 0) { - NTOHS(sp->s_port); + /* + * We need to check /etc/services for ambiguous entries. + * If we find the ambiguous entry, and it has the + * same port number, change the proto to PROTO_UNDEF + * so both TCP and UDP will be checked. + */ + sp = getservbyname(name, "tcp"); + if (sp != NULL) tcp_port = ntohs(sp->s_port); + sp = getservbyname(name, "udp"); + if (sp != NULL) udp_port = ntohs(sp->s_port); + if (tcp_port >= 0) { + *port = tcp_port; + *proto = IPPROTO_TCP; + if (udp_port >= 0) { + if (udp_port == tcp_port) + *proto = PROTO_UNDEF; #ifdef notdef - if (*port != sp->s_port) + else /* Can't handle ambiguous names that refer to different port numbers. */ warning("ambiguous port %s in /etc/services", name); #endif - *proto = PROTO_UNDEF; } return 1; } + if (udp_port >= 0) { + *port = udp_port; + *proto = IPPROTO_UDP; + return 1; + } #if defined(ultrix) || defined(__osf__) /* Special hack in case NFS isn't in /etc/services */ if (strcmp(name, "nfs") == 0) { @@ -250,7 +279,7 @@ pcap_nametoeproto(const char *s) } /* Hex digit to integer. */ -static inline int +static __inline int xdtoi(c) register int c; { @@ -318,7 +347,7 @@ pcap_ether_aton(const char *s) if (*s == ':') s += 1; d = xdtoi(*s++); - if (isxdigit(*s)) { + if (isxdigit((unsigned char)*s)) { d <<= 4; d |= xdtoi(*s++); } @@ -336,7 +365,7 @@ pcap_ether_hostton(const char *name) register struct pcap_etherent *ep; register u_char *ap; static FILE *fp = NULL; - static init = 0; + static int init = 0; if (!init) { fp = fopen(PCAP_ETHERS_FILE, "r"); @@ -362,7 +391,17 @@ pcap_ether_hostton(const char *name) } #else -#if !defined(sgi) && !defined(__NetBSD__) +/* + * XXX - perhaps this should, instead, be declared in "lbl/os-XXX.h" files, + * for those OS versions that don't declare it, rather than being declared + * here? That way, for example, we could declare it on FreeBSD 2.x (which + * doesn't declare it), but not on FreeBSD 3.x (which declares it like + * this) or FreeBSD 4.x (which declares it with its first argument as + * "const char *", so no matter how we declare it here, it'll fail to + * compile on one of 3.x or 4.x). + */ +#if !defined(sgi) && !defined(__NetBSD__) && !defined(__FreeBSD__) && \ + !defined(_UNICOSMP) extern int ether_hostton(char *, struct ether_addr *); #endif diff --git a/lib/libpcap/optimize.c b/lib/libpcap/optimize.c index 6001b3721aa8..068d3df801b8 100644 --- a/lib/libpcap/optimize.c +++ b/lib/libpcap/optimize.c @@ -1,4 +1,4 @@ -/* $NetBSD: optimize.c,v 1.15 2002/08/26 11:21:19 yamt Exp $ */ +/* $NetBSD: optimize.c,v 1.16 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 @@ -26,24 +26,26 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: optimize.c,v 1.60 96/09/26 23:28:14 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/optimize.c,v 1.76.2.3 2003/12/22 00:26:36 guy Exp (LBL)"; #else -__RCSID("$NetBSD: optimize.c,v 1.15 2002/08/26 11:21:19 yamt Exp $"); +__RCSID("$NetBSD: optimize.c,v 1.16 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif -#include -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include #include +#include + #include "pcap-int.h" #include "gencode.h" -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -104,26 +106,26 @@ static void compute_local_ud(struct block *); static void find_ud(struct block *); static void init_val(void); static int F(int, int, int); -static inline void vstore(struct stmt *, int *, int, int); +static __inline void vstore(struct stmt *, int *, int, int); static void opt_blk(struct block *, int); static int use_conflict(struct block *, struct block *); static void opt_j(struct edge *); static void or_pullup(struct block *); static void and_pullup(struct block *); static void opt_blks(struct block *, int); -static inline void link_inedge(struct edge *, struct block *); +static __inline void link_inedge(struct edge *, struct block *); static void find_inedges(struct block *); static void opt_root(struct block **); static void opt_loop(struct block *, int); static void fold_op(struct stmt *, int, int); -static inline struct slist *this_op(struct slist *); +static __inline struct slist *this_op(struct slist *); static void opt_not(struct block *); static void opt_peep(struct block *); static void opt_stmt(struct stmt *, int[], int); static void deadstmt(struct stmt *, struct stmt *[]); static void opt_deadstores(struct block *); static struct block *fold_edge(struct block *, struct edge *); -static inline int eq_blk(struct block *, struct block *); +static __inline int eq_blk(struct block *, struct block *); static int slength(struct slist *); static int count_blocks(struct block *); static void number_blks_r(struct block *); @@ -567,7 +569,7 @@ F(code, v0, v1) return val; } -static inline void +static __inline void vstore(s, valp, newval, alter) struct stmt *s; int *valp; @@ -637,7 +639,7 @@ fold_op(s, v0, v1) done = 0; } -static inline struct slist * +static __inline struct slist * this_op(s) struct slist *s; { @@ -810,6 +812,16 @@ opt_peep(b) done = 0; opt_not(b); } + /* + * jset #0 -> never + * jset #ffffffff -> always + */ + if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) { + if (b->s.k == 0) + JT(b) = JF(b); + if (b->s.k == 0xffffffff) + JF(b) = JT(b); + } /* * If the accumulator is a known constant, we can compute the * comparison result. @@ -927,7 +939,10 @@ opt_stmt(s, val, alter) op = BPF_OP(s->code); if (alter) { if (s->k == 0) { - if (op == BPF_ADD || op == BPF_SUB || + /* don't optimize away "sub #0" + * as it may be needed later to + * fixup the generated math code */ + if (op == BPF_ADD || op == BPF_LSH || op == BPF_RSH || op == BPF_OR) { s->code = NOP; @@ -1501,7 +1516,7 @@ opt_blks(root, do_stmts) } } -static inline void +static __inline void link_inedge(parent, child) struct edge *parent; struct block *child; @@ -1564,8 +1579,10 @@ opt_loop(root, do_stmts) { #ifdef BDEBUG - if (dflag > 1) + if (dflag > 1) { + printf("opt_loop(root, %d) begin\n", do_stmts); opt_dump(root); + } #endif do { done = 1; @@ -1576,8 +1593,10 @@ opt_loop(root, do_stmts) find_edom(root); opt_blks(root, do_stmts); #ifdef BDEBUG - if (dflag > 1) + if (dflag > 1) { + printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, done); opt_dump(root); + } #endif } while (!done); } @@ -1597,7 +1616,19 @@ bpf_optimize(rootp) opt_loop(root, 0); opt_loop(root, 1); intern_blocks(root); +#ifdef BDEBUG + if (dflag > 1) { + printf("after intern_blocks()\n"); + opt_dump(root); + } +#endif opt_root(rootp); +#ifdef BDEBUG + if (dflag > 1) { + printf("after opt_root()\n"); + opt_dump(root); + } +#endif opt_cleanup(); } @@ -1650,7 +1681,7 @@ eq_slist(x, y) } } -static inline int +static __inline int eq_blk(b0, b1) struct block *b0, *b1; { @@ -1771,6 +1802,20 @@ number_blks_r(p) /* * Return the number of stmts in the flowgraph reachable by 'p'. * The nodes should be unmarked before calling. + * + * Note that "stmts" means "instructions", and that this includes + * + * side-effect statements in 'p' (slength(p->stmts)); + * + * statements in the true branch from 'p' (count_stmts(JT(p))); + * + * statements in the false branch from 'p' (count_stmts(JF(p))); + * + * the conditional jump itself (1); + * + * an extra long jump if the true branch requires it (p->longjt); + * + * an extra long jump if the false branch requires it (p->longjf). */ static int count_stmts(p) @@ -1782,7 +1827,7 @@ count_stmts(p) return 0; Mark(p); n = count_stmts(JT(p)) + count_stmts(JF(p)); - return slength(p->stmts) + n + 1; + return slength(p->stmts) + n + 1 + p->longjt + p->longjf; } /* @@ -1804,17 +1849,23 @@ opt_init(root) unMarkAll(); n = count_blocks(root); blocks = (struct block **)malloc(n * sizeof(*blocks)); + if (blocks == NULL) + bpf_error("malloc"); unMarkAll(); n_blocks = 0; number_blks_r(root); n_edges = 2 * n_blocks; edges = (struct edge **)malloc(n_edges * sizeof(*edges)); + if (edges == NULL) + bpf_error("malloc"); /* * The number of levels is bounded by the number of nodes. */ levels = (struct block **)malloc(n_blocks * sizeof(*levels)); + if (levels == NULL) + bpf_error("malloc"); edgewords = n_edges / (8 * sizeof(bpf_u_int32)) + 1; nodewords = n_blocks / (8 * sizeof(bpf_u_int32)) + 1; @@ -1822,6 +1873,8 @@ opt_init(root) /* XXX */ space = (bpf_u_int32 *)malloc(2 * n_blocks * nodewords * sizeof(*space) + n_edges * edgewords * sizeof(*space)); + if (space == NULL) + bpf_error("malloc"); p = space; all_dom_sets = p; for (i = 0; i < n; ++i) { @@ -1858,7 +1911,9 @@ opt_init(root) */ maxval = 3 * max_stmts; vmap = (struct vmapinfo *)malloc(maxval * sizeof(*vmap)); - vnode_base = (struct valnode *)malloc(maxval * sizeof(*vmap)); + vnode_base = (struct valnode *)malloc(maxval * sizeof(*vnode_base)); + if (vmap == NULL || vnode_base == NULL) + bpf_error("malloc"); } /* @@ -2048,7 +2103,7 @@ icode_to_fcode(root, lenp) struct bpf_insn *fp; /* - * Loop doing convert_codr_r() until no branches remain + * Loop doing convert_code_r() until no branches remain * with too-large offsets. */ while (1) { @@ -2056,6 +2111,8 @@ icode_to_fcode(root, lenp) n = *lenp = count_stmts(root); fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); + if (fp == NULL) + bpf_error("malloc"); memset((char *)fp, 0, sizeof(*fp) * n); fstart = fp; ftail = fp + n; @@ -2069,6 +2126,36 @@ icode_to_fcode(root, lenp) return fp; } +/* + * Make a copy of a BPF program and put it in the "fcode" member of + * a "pcap_t". + * + * If we fail to allocate memory for the copy, fill in the "errbuf" + * member of the "pcap_t" with an error message, and return -1; + * otherwise, return 0. + */ +int +install_bpf_program(pcap_t *p, struct bpf_program *fp) +{ + size_t prog_size; + + /* + * Free up any already installed program. + */ + pcap_freecode(&p->fcode); + + prog_size = sizeof(*fp->bf_insns) * fp->bf_len; + p->fcode.bf_len = fp->bf_len; + p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size); + if (p->fcode.bf_insns == NULL) { + snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size); + return (0); +} + #ifdef BDEBUG static void opt_dump(root) diff --git a/lib/libpcap/pcap-bpf.c b/lib/libpcap/pcap-bpf.c index ebe163606bc0..aa82c8caba71 100644 --- a/lib/libpcap/pcap-bpf.c +++ b/lib/libpcap/pcap-bpf.c @@ -1,7 +1,7 @@ -/* $NetBSD: pcap-bpf.c,v 1.11 2004/01/20 23:31:20 jonathan Exp $ */ +/* $NetBSD: pcap-bpf.c,v 1.12 2004/09/27 23:02:53 dyoung Exp $ */ /* - * Copyright (c) 1993, 1994, 1995, 1996 + * Copyright (c) 1993, 1994, 1995, 1996, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,21 +24,73 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: pcap-bpf.c,v 1.29 96/12/31 20:53:40 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.67.2.4 2003/11/22 00:06:28 guy Exp (LBL)"; #else -__RCSID("$NetBSD: pcap-bpf.c,v 1.11 2004/01/20 23:31:20 jonathan Exp $"); +__RCSID("$NetBSD: pcap-bpf.c,v 1.12 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include /* optionally get BSD define */ #include #include #include #include #include +#include #include +#ifdef _AIX + +/* + * Make "pcap.h" not include "pcap-bpf.h"; we are going to include the + * native OS version, as we need "struct bpf_config" from it. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#include + +/* + * Prevent bpf.h from redefining the DLT_ values to their + * IFT_ values, as we're going to return the standard libpcap + * values, not IBM's non-standard IFT_ values. + */ +#undef _AIX +#include +#define _AIX + +#include /* for IFT_ values */ +#include +#include +#include +#include + +#ifdef __64BIT__ +#define domakedev makedev64 +#define getmajor major64 +#define bpf_hdr bpf_hdr32 +#else /* __64BIT__ */ +#define domakedev makedev +#define getmajor major +#endif /* __64BIT__ */ + +#define BPF_NAME "bpf" +#define BPF_MINORS 4 +#define DRIVER_PATH "/usr/lib/drivers" +#define BPF_NODE "/dev/bpf" +static int bpfloadedflag = 0; +static int odmlockid = 0; + +#else /* _AIX */ + +#include + +#endif /* _AIX */ + #include #include #include @@ -49,20 +101,39 @@ __RCSID("$NetBSD: pcap-bpf.c,v 1.11 2004/01/20 23:31:20 jonathan Exp $"); #include "pcap-int.h" -#include "gnuc.h" +#ifdef HAVE_DAG_API +#include "pcap-dag.h" +#endif /* HAVE_DAG_API */ + #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif -#include "gencode.h" +#include "gencode.h" /* for "no_optimize" */ int __PCAP_MAX_BUFSIZE = (4*1024*1024); -int -pcap_stats(pcap_t *p, struct pcap_stat *ps) +static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp); +static int pcap_set_datalink_bpf(pcap_t *p, int dlt); + +static int +pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) { struct bpf_stat s; + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. This includes packets later dropped + * because we ran out of buffer space. + * + * "ps_drop" counts packets dropped inside the BPF device + * because we ran out of buffer space. It doesn't count + * packets dropped by the interface driver. It counts + * only packets that passed the filter. + * + * Both statistics include packets not yet read from the kernel + * by libpcap, and thus not yet seen by the application. + */ if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", pcap_strerror(errno)); @@ -74,14 +145,28 @@ pcap_stats(pcap_t *p, struct pcap_stat *ps) return (0); } -int -pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +static int +pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { int cc; int n = 0; register u_char *bp, *ep; + struct bpf_insn *fcode; + fcode = p->md.use_bpf ? NULL : p->fcode.bf_insns; again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return (-2); + } cc = p->cc; if (p->cc == 0) { cc = read(p->fd, (char *)p->buffer, p->bufsize); @@ -92,6 +177,32 @@ pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) case EINTR: goto again; +#ifdef _AIX + case EFAULT: + /* + * Sigh. More AIX wonderfulness. + * + * For some unknown reason the uiomove() + * operation in the bpf kernel extension + * used to copy the buffer into user + * space sometimes returns EFAULT. I have + * no idea why this is the case given that + * a kernel debugger shows the user buffer + * is correct. This problem appears to + * be mostly mitigated by the memset of + * the buffer before it is first used. + * Very strange.... Shaun Clowes + * + * In any case this means that we shouldn't + * treat EFAULT as a fatal error; as we + * don't have an API for returning + * a "some packets were dropped since + * the last packet you saw" indication, + * we just ignore EFAULT and keep reading. + */ + goto again; +#endif + case EWOULDBLOCK: return (0); #if defined(sun) && !defined(BSD) @@ -124,17 +235,65 @@ pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) ep = bp + cc; while (bp < ep) { register int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; /* - * XXX A bpf_hdr matches a pcap_pkthdr. + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now. */ - (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); - bp += BPF_WORDALIGN(caplen + hdrlen); - if (++n >= cnt && cnt > 0) { - p->bp = bp; - p->cc = ep - bp; - return (n); + if (fcode == NULL || + bpf_filter(fcode, bp + hdrlen, bhp->bh_datalen, caplen)) { +#ifdef _AIX + /* + * AIX's BPF returns seconds/nanoseconds time + * stamps, not seconds/microseconds time stamps. + * + * XXX - I'm guessing here that it's a "struct + * timestamp"; if not, this code won't compile, + * but, if not, you want to send us a bug report + * and fall back on using DLPI. It's not as if + * BPF used to work right on AIX before this + * change; this change attempts to fix the fact + * that it didn't.... + */ + bhp->bh_tstamp.tv_usec = bhp->bh_tstamp.tv_usec/1000; +#endif + /* + * XXX A bpf_hdr matches a pcap_pkthdr. + */ + (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); + bp += BPF_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && cnt > 0) { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } else { + /* + * Skip this packet. + */ + bp += BPF_WORDALIGN(caplen + hdrlen); } } #undef bhp @@ -142,18 +301,181 @@ pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) return (n); } -static inline int +#ifdef _AIX +static int +bpf_odminit(char *errbuf) +{ + char *errstr; + + if (odm_initialize() == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_initialize failed: %s", + errstr); + return (-1); + } + + if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s", + errstr); + return (-1); + } + + return (0); +} + +static int +bpf_odmcleanup(char *errbuf) +{ + char *errstr; + + if (odm_unlock(odmlockid) == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_unlock failed: %s", + errstr); + return (-1); + } + + if (odm_terminate() == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_terminate failed: %s", + errstr); + return (-1); + } + + return (0); +} + +static int +bpf_load(char *errbuf) +{ + long major; + int *minors; + int numminors, i, rc; + char buf[1024]; + struct stat sbuf; + struct bpf_config cfg_bpf; + struct cfg_load cfg_ld; + struct cfg_kmod cfg_km; + + /* + * This is very very close to what happens in the real implementation + * but I've fixed some (unlikely) bug situations. + */ + if (bpfloadedflag) + return (0); + + if (bpf_odminit(errbuf) != 0) + return (-1); + + major = genmajor(BPF_NAME); + if (major == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: genmajor failed: %s", pcap_strerror(errno)); + return (-1); + } + + minors = getminor(major, &numminors, BPF_NAME); + if (!minors) { + minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); + if (!minors) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: genminor failed: %s", + pcap_strerror(errno)); + return (-1); + } + } + + if (bpf_odmcleanup(errbuf)) + return (-1); + + rc = stat(BPF_NODE "0", &sbuf); + if (rc == -1 && errno != ENOENT) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: can't stat %s: %s", + BPF_NODE "0", pcap_strerror(errno)); + return (-1); + } + + if (rc == -1 || getmajor(sbuf.st_rdev) != major) { + for (i = 0; i < BPF_MINORS; i++) { + sprintf(buf, "%s%d", BPF_NODE, i); + unlink(buf); + if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: can't mknod %s: %s", + buf, pcap_strerror(errno)); + return (-1); + } + } + } + + /* Check if the driver is loaded */ + memset(&cfg_ld, 0x0, sizeof(cfg_ld)); + cfg_ld.path = buf; + sprintf(cfg_ld.path, "%s/%s", DRIVER_PATH, BPF_NAME); + if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || + (cfg_ld.kmid == 0)) { + /* Driver isn't loaded, load it now */ + if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: could not load driver: %s", + strerror(errno)); + return (-1); + } + } + + /* Configure the driver */ + cfg_km.cmd = CFG_INIT; + cfg_km.kmid = cfg_ld.kmid; + cfg_km.mdilen = sizeof(cfg_bpf); + cfg_km.mdiptr = (void *)&cfg_bpf; + for (i = 0; i < BPF_MINORS; i++) { + cfg_bpf.devno = domakedev(major, i); + if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: could not configure driver: %s", + strerror(errno)); + return (-1); + } + } + + bpfloadedflag = 1; + + return (0); +} +#endif + +static __inline int bpf_open(pcap_t *p, char *errbuf) { int fd; int n = 0; - char device[sizeof "/dev/bpf000"]; + char device[sizeof "/dev/bpf0000000000"]; + +#ifdef _AIX + /* + * Load the bpf driver, if it isn't already loaded, + * and create the BPF device entries, if they don't + * already exist. + */ + if (bpf_load(errbuf) == -1) + return (-1); +#endif /* * Go through all the minors and find one that isn't in use. */ do { - (void)snprintf(device, sizeof device, "/dev/bpf%d", n++); + (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); fd = open(device, O_RDWR); } while (fd < 0 && errno == EBUSY); @@ -161,21 +483,54 @@ bpf_open(pcap_t *p, char *errbuf) * XXX better message for all minors used */ if (fd < 0) - (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, - pcap_strerror(errno)); + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(no devices found) %s: %s", device, pcap_strerror(errno)); return (fd); } +static void +pcap_close_bpf(pcap_t *p) +{ + if (p->buffer != NULL) + free(p->buffer); + if (p->fd >= 0) + close(p->fd); +} + +/* + * XXX - on AIX, IBM's tcpdump (and perhaps the incompatible-with-everybody- + * else's libpcap in AIX 5.1) appears to forcibly load the BPF driver + * if it's not already loaded, and to create the BPF devices if they + * don't exist. + * + * It'd be nice if we could do the same, although the code to do so + * might be version-dependent, alas (the way to do it isn't necessarily + * documented). + */ pcap_t * -pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) +pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, + char *ebuf) { int fd; struct ifreq ifr; struct bpf_version bv; +#ifdef BIOCGDLTLIST struct bpf_dltlist bdl; +#endif u_int v; pcap_t *p; + struct utsname osinfo; + +#ifdef HAVE_DAG_API + if (strstr(device, "dag")) { + return dag_open_live(device, snaplen, promisc, to_ms, ebuf); + } +#endif /* HAVE_DAG_API */ + +#ifdef BIOCGDLTLIST + memset(&bdl, 0, sizeof(bdl)); +#endif bzero(&bdl, sizeof(bdl)); @@ -185,7 +540,7 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) pcap_strerror(errno)); return (NULL); } - bzero(p, sizeof(*p)); + memset(p, 0, sizeof(*p)); fd = bpf_open(p, ebuf); if (fd < 0) goto bad; @@ -243,6 +598,38 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) pcap_strerror(errno)); goto bad; } +#ifdef _AIX + /* + * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT. + */ + switch (v) { + + case IFT_ETHER: + case IFT_ISO88023: + v = DLT_EN10MB; + break; + + case IFT_FDDI: + v = DLT_FDDI; + break; + + case IFT_ISO88025: + v = DLT_IEEE802; + break; + + case IFT_LOOP: + v = DLT_NULL; + break; + + default: + /* + * We don't know what to map this to yet. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", + v); + goto bad; + } +#endif #if _BSDI_VERSION - 0 >= 199510 /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ switch (v) { @@ -254,16 +641,25 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) case DLT_PPP: v = DLT_PPP_BSDOS; break; + + case 11: /*DLT_FR*/ + v = DLT_FRELAY; + break; + + case 12: /*DLT_C_HDLC*/ + v = DLT_CHDLC; + break; } #endif p->linktype = v; +#ifdef BIOCGDLTLIST /* - * We know the default link type -- now determine any additional - * DLTs this interface supports. If this fails, it's not fatal; - * we just don't get to use the feature later. + * We know the default link type -- now determine all the DLTs + * this interface supports. If this fails with EINVAL, it's + * not fatal; we just don't get to use the feature later. */ - if (ioctl(fd, BIOCGDLTLIST, (caddr_t) &bdl) == 0) { + if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) { bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * bdl.bfl_len); if (bdl.bfl_list == NULL) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", @@ -271,7 +667,7 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) goto bad; } - if (ioctl(fd, BIOCGDLTLIST, (caddr_t) &bdl) < 0) { + if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLTLIST: %s", pcap_strerror(errno)); goto bad; @@ -279,10 +675,22 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) p->dlt_count = bdl.bfl_len; p->dlt_list = bdl.bfl_list; + } else { + if (errno != EINVAL) { + (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, + "BIOCGDLTLIST: %s", pcap_strerror(errno)); + goto bad; + } } +#endif /* set timeout */ if (to_ms != 0) { + /* + * XXX - is this seconds/nanoseconds in AIX? + * (Treating it as such doesn't fix the timeout + * problem described below.) + */ struct timeval to; to.tv_sec = to_ms / 1000; to.tv_usec = (to_ms * 1000) % 1000000; @@ -292,9 +700,71 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) goto bad; } } - if (promisc) + +#ifdef _AIX +#ifdef BIOCIMMEDIATE + /* + * Darren Reed notes that + * + * On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the + * timeout appears to be ignored and it waits until the buffer + * is filled before returning. The result of not having it + * set is almost worse than useless if your BPF filter + * is reducing things to only a few packets (i.e. one every + * second or so). + * + * so we turn BIOCIMMEDIATE mode on if this is AIX. + * + * We don't turn it on for other platforms, as that means we + * get woken up for every packet, which may not be what we want; + * in the Winter 1993 USENIX paper on BPF, they say: + * + * Since a process might want to look at every packet on a + * network and the time between packets can be only a few + * microseconds, it is not possible to do a read system call + * per packet and BPF must collect the data from several + * packets and return it as a unit when the monitoring + * application does a read. + * + * which I infer is the reason for the timeout - it means we + * wait that amount of time, in the hopes that more packets + * will arrive and we'll get them all with one read. + * + * Setting BIOCIMMEDIATE mode on FreeBSD (and probably other + * BSDs) causes the timeout to be ignored. + * + * On the other hand, some platforms (e.g., Linux) don't support + * timeouts, they just hand stuff to you as soon as it arrives; + * if that doesn't cause a problem on those platforms, it may + * be OK to have BIOCIMMEDIATE mode on BSD as well. + * + * (Note, though, that applications may depend on the read + * completing, even if no packets have arrived, when the timeout + * expires, e.g. GUI applications that have to check for input + * while waiting for packets to arrive; a non-zero timeout + * prevents "select()" from working right on FreeBSD and + * possibly other BSDs, as the timer doesn't start until a + * "read()" is done, so the timer isn't in effect if the + * application is blocked on a "select()", and the "select()" + * doesn't get woken up for a BPF device until the buffer + * fills up.) + */ + v = 1; + if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s", + pcap_strerror(errno)); + goto bad; + } +#endif /* BIOCIMMEDIATE */ +#endif /* _AIX */ + + if (promisc) { /* set promiscuous mode, okay if it fails */ - (void)ioctl(p->fd, BIOCPROMISC, NULL); + if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", + pcap_strerror(errno)); + } + } if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", @@ -308,54 +778,140 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) pcap_strerror(errno)); goto bad; } +#ifdef _AIX + /* For some strange reason this seems to prevent the EFAULT + * problems we have experienced from AIX BPF. */ + memset(p->buffer, 0x0, p->bufsize); +#endif + + /* + * On most BPF platforms, either you can do a "select()" or + * "poll()" on a BPF file descriptor and it works correctly, + * or you can do it and it will return "readable" if the + * hold buffer is full but not if the timeout expires *and* + * a non-blocking read will, if the hold buffer is empty + * but the store buffer isn't empty, rotate the buffers + * and return what packets are available. + * + * In the latter case, the fact that a non-blocking read + * will give you the available packets means you can work + * around the failure of "select()" and "poll()" to wake up + * and return "readable" when the timeout expires by using + * the timeout as the "select()" or "poll()" timeout, putting + * the BPF descriptor into non-blocking mode, and read from + * it regardless of whether "select()" reports it as readable + * or not. + * + * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()" + * won't wake up and return "readable" if the timer expires + * and non-blocking reads return EWOULDBLOCK if the hold + * buffer is empty, even if the store buffer is non-empty. + * + * This means the workaround in question won't work. + * + * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd" + * to -1, which means "sorry, you can't use 'select()' or 'poll()' + * here". On all other BPF platforms, we set it to the FD for + * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking + * read will, if the hold buffer is empty and the store buffer + * isn't empty, rotate the buffers and return what packets are + * there (and in sufficiently recent versions of OpenBSD + * "select()" and "poll()" should work correctly). + * + * XXX - what about AIX? + */ + if (uname(&osinfo) == 0) { + /* + * We can check what OS this is. + */ + if (strcmp(osinfo.sysname, "FreeBSD") == 0 && + (strcmp(osinfo.release, "4.3") == 0 || + strcmp(osinfo.release, "4.4") == 0)) + p->selectable_fd = -1; + else + p->selectable_fd = p->fd; + } else { + /* + * We can't find out what OS this is, so assume we can + * do a "select()" or "poll()". + */ + p->selectable_fd = p->fd; + } + + p->read_op = pcap_read_bpf; + p->setfilter_op = pcap_setfilter_bpf; + p->set_datalink_op = pcap_set_datalink_bpf; + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_bpf; + p->close_op = pcap_close_bpf; return (p); bad: (void)close(fd); +#ifdef BIOCGDLTLIST if (bdl.bfl_list != NULL) free(bdl.bfl_list); +#endif free(p); return (NULL); } int -pcap_setfilter(pcap_t *p, struct bpf_program *fp) +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ +#ifdef HAVE_DAG_API + if (dag_platform_finddevs(alldevsp, errbuf) < 0) + return (-1); +#endif /* HAVE_DAG_API */ + + return (0); +} + +static int +pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) { /* * It looks that BPF code generated by gen_protochain() is not * compatible with some of kernel BPF code (for example BSD/OS 3.1). * Take a safer side for now. */ - if (no_optimize) - p->fcode = *fp; - if (p->sf.rfile != NULL) - p->fcode = *fp; - else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { - (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", + if (no_optimize) { + /* + * XXX - what if we already have a filter in the kernel? + */ + if (install_bpf_program(p, fp) < 0) + return (-1); + p->md.use_bpf = 0; /* filtering in userland */ + return (0); + } + + /* + * Free any user-mode filter we might happen to have installed. + */ + pcap_freecode(&p->fcode); + + /* + * Try to install the kernel filter. + */ + if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); return (-1); } + p->md.use_bpf = 1; /* filtering in the kernel */ return (0); } -int -pcap_set_datalink(pcap_t *p, int dlt) +static int +pcap_set_datalink_bpf(pcap_t *p, int dlt) { - int i; - - for (i = 0; i < p->dlt_count; i++) - if (p->dlt_list[i] == dlt) - break; - if (i >= p->dlt_count) { - (void) snprintf(p->errbuf, sizeof(p->errbuf), - "No such DLT as %d", dlt); - return -1; - } +#ifdef BIOCSDLT if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { (void) snprintf(p->errbuf, sizeof(p->errbuf), "Cannot set DLT %d: %s", dlt, strerror(errno)); - return -1; + return (-1); } - p->linktype = dlt; - return 0; +#endif + return (0); } diff --git a/lib/libpcap/pcap-bpf.h b/lib/libpcap/pcap-bpf.h deleted file mode 100644 index 79e791580de6..000000000000 --- a/lib/libpcap/pcap-bpf.h +++ /dev/null @@ -1,598 +0,0 @@ -/* $NetBSD: pcap-bpf.h,v 1.1.1.2 2004/09/19 21:57:55 dyoung Exp $ */ - -/*- - * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from the Stanford/CMU enet packet filter, - * (net/enet.c) distributed as part of 4.3BSD, and code contributed - * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence - * Berkeley Laboratory. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)bpf.h 7.1 (Berkeley) 5/7/91 - * - * @(#) Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.9.2.9 2004/03/28 21:45:32 fenner Exp (LBL) - */ - -/* - * This is libpcap's cut-down version of bpf.h; it includes only - * the stuff needed for the code generator and the userland BPF - * interpreter, and the libpcap APIs for setting filters, etc.. - * - * "pcap-bpf.c" will include the native OS version, as it deals with - * the OS's BPF implementation. - * - * XXX - should this all just be moved to "pcap.h"? - */ - -#ifndef BPF_MAJOR_VERSION - -#ifdef __cplusplus -extern "C" { -#endif - -/* BSD style release date */ -#define BPF_RELEASE 199606 - -typedef int bpf_int32; -typedef u_int bpf_u_int32; - -/* - * Alignment macros. BPF_WORDALIGN rounds up to the next - * even multiple of BPF_ALIGNMENT. - */ -#ifndef __NetBSD__ -#define BPF_ALIGNMENT sizeof(bpf_int32) -#else -#define BPF_ALIGNMENT sizeof(long) -#endif -#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) - -#define BPF_MAXINSNS 512 -#define BPF_MAXBUFSIZE 0x8000 -#define BPF_MINBUFSIZE 32 - -/* - * Structure for "pcap_compile()", "pcap_setfilter()", etc.. - */ -struct bpf_program { - u_int bf_len; - struct bpf_insn *bf_insns; -}; - -/* - * Struct return by BIOCVERSION. This represents the version number of - * the filter language described by the instruction encodings below. - * bpf understands a program iff kernel_major == filter_major && - * kernel_minor >= filter_minor, that is, if the value returned by the - * running kernel has the same major number and a minor number equal - * equal to or less than the filter being downloaded. Otherwise, the - * results are undefined, meaning an error may be returned or packets - * may be accepted haphazardly. - * It has nothing to do with the source code version. - */ -struct bpf_version { - u_short bv_major; - u_short bv_minor; -}; -/* Current version number of filter architecture. */ -#define BPF_MAJOR_VERSION 1 -#define BPF_MINOR_VERSION 1 - -/* - * Data-link level type codes. - * - * Do *NOT* add new values to this list without asking - * "tcpdump-workers@tcpdump.org" for a value. Otherwise, you run the - * risk of using a value that's already being used for some other purpose, - * and of having tools that read libpcap-format captures not being able - * to handle captures with your new DLT_ value, with no hope that they - * will ever be changed to do so (as that would destroy their ability - * to read captures using that value for that other purpose). - */ - -/* - * These are the types that are the same on all platforms, and that - * have been defined by for ages. - */ -#define DLT_NULL 0 /* no link-layer encapsulation */ -#define DLT_EN10MB 1 /* Ethernet (10Mb) */ -#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ -#define DLT_AX25 3 /* Amateur Radio AX.25 */ -#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ -#define DLT_CHAOS 5 /* Chaos */ -#define DLT_IEEE802 6 /* IEEE 802 Networks */ -#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ -#define DLT_SLIP 8 /* Serial Line IP */ -#define DLT_PPP 9 /* Point-to-point Protocol */ -#define DLT_FDDI 10 /* FDDI */ - -/* - * These are types that are different on some platforms, and that - * have been defined by for ages. We use #ifdefs to - * detect the BSDs that define them differently from the traditional - * libpcap - * - * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, - * but I don't know what the right #define is for BSD/OS. - */ -#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ - -#ifdef __OpenBSD__ -#define DLT_RAW 14 /* raw IP */ -#else -#define DLT_RAW 12 /* raw IP */ -#endif - -/* - * Given that the only OS that currently generates BSD/OS SLIP or PPP - * is, well, BSD/OS, arguably everybody should have chosen its values - * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they - * didn't. So it goes. - */ -#if defined(__NetBSD__) || defined(__FreeBSD__) -#ifndef DLT_SLIP_BSDOS -#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ -#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ -#endif -#else -#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ -#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ -#endif - -/* - * 17 is used for DLT_OLD_PFLOG in OpenBSD; - * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. - * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. - */ - -#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ - -/* - * These values are defined by NetBSD; other platforms should refrain from - * using them for other purposes, so that NetBSD savefiles with link - * types of 50 or 51 can be read as this type on all platforms. - */ -#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ -#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ - -/* - * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses - * a link-layer type of 99 for the tcpdump it supplies. The link-layer - * header has 6 bytes of unknown data, something that appears to be an - * Ethernet type, and 36 bytes that appear to be 0 in at least one capture - * I've seen. - */ -#define DLT_SYMANTEC_FIREWALL 99 - -/* - * Values between 100 and 103 are used in capture file headers as - * link-layer types corresponding to DLT_ types that differ - * between platforms; don't use those values for new DLT_ new types. - */ - -/* - * This value was defined by libpcap 0.5; platforms that have defined - * it with a different value should define it here with that value - - * a link type of 104 in a save file will be mapped to DLT_C_HDLC, - * whatever value that happens to be, so programs will correctly - * handle files with that link type regardless of the value of - * DLT_C_HDLC. - * - * The name DLT_C_HDLC was used by BSD/OS; we use that name for source - * compatibility with programs written for BSD/OS. - * - * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, - * for source compatibility with programs written for libpcap 0.5. - */ -#define DLT_C_HDLC 104 /* Cisco HDLC */ -#define DLT_CHDLC DLT_C_HDLC - -#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ - -/* - * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, - * except when it isn't. (I.e., sometimes it's just raw IP, and - * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, - * so that we don't have to worry about the link-layer header.) - */ - -/* - * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides - * with other values. - * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header - * (DLCI, etc.). - */ -#define DLT_FRELAY 107 - -/* - * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except - * that the AF_ type in the link-layer header is in network byte order. - * - * OpenBSD defines it as 12, but that collides with DLT_RAW, so we - * define it as 108 here. If OpenBSD picks up this file, it should - * define DLT_LOOP as 12 in its version, as per the comment above - - * and should not use 108 as a DLT_ value. - */ -#define DLT_LOOP 108 - -/* - * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's - * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other - * than OpenBSD. - */ -#ifdef __OpenBSD__ -#define DLT_ENC 13 -#else -#define DLT_ENC 109 -#endif - -/* - * Values between 110 and 112 are reserved for use in capture file headers - * as link-layer types corresponding to DLT_ types that might differ - * between platforms; don't use those values for new DLT_ types - * other than the corresponding DLT_ types. - */ - -/* - * This is for Linux cooked sockets. - */ -#define DLT_LINUX_SLL 113 - -/* - * Apple LocalTalk hardware. - */ -#define DLT_LTALK 114 - -/* - * Acorn Econet. - */ -#define DLT_ECONET 115 - -/* - * Reserved for use with OpenBSD ipfilter. - */ -#define DLT_IPFILTER 116 - -/* - * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 - * in SuSE 6.3, so we can't use 17 for it in capture-file headers. - * - * XXX: is there a conflict with DLT_PFSYNC 18 as well? - */ -#ifdef __OpenBSD__ -#define DLT_OLD_PFLOG 17 -#define DLT_PFSYNC 18 -#endif -#define DLT_PFLOG 117 - -/* - * Registered for Cisco-internal use. - */ -#define DLT_CISCO_IOS 118 - -/* - * For 802.11 cards using the Prism II chips, with a link-layer - * header including Prism monitor mode information plus an 802.11 - * header. - */ -#define DLT_PRISM_HEADER 119 - -/* - * Reserved for Aironet 802.11 cards, with an Aironet link-layer header - * (see Doug Ambrisko's FreeBSD patches). - */ -#define DLT_AIRONET_HEADER 120 - -/* - * Reserved for Siemens HiPath HDLC. - */ -#define DLT_HHDLC 121 - -/* - * This is for RFC 2625 IP-over-Fibre Channel. - * - * This is not for use with raw Fibre Channel, where the link-layer - * header starts with a Fibre Channel frame header; it's for IP-over-FC, - * where the link-layer header starts with an RFC 2625 Network_Header - * field. - */ -#define DLT_IP_OVER_FC 122 - -/* - * This is for Full Frontal ATM on Solaris with SunATM, with a - * pseudo-header followed by an AALn PDU. - * - * There may be other forms of Full Frontal ATM on other OSes, - * with different pseudo-headers. - * - * If ATM software returns a pseudo-header with VPI/VCI information - * (and, ideally, packet type information, e.g. signalling, ILMI, - * LANE, LLC-multiplexed traffic, etc.), it should not use - * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump - * and the like don't have to infer the presence or absence of a - * pseudo-header and the form of the pseudo-header. - */ -#define DLT_SUNATM 123 /* Solaris+SunATM */ - -/* - * Reserved as per request from Kent Dahlgren - * for private use. - */ -#define DLT_RIO 124 /* RapidIO */ -#define DLT_PCI_EXP 125 /* PCI Express */ -#define DLT_AURORA 126 /* Xilinx Aurora link layer */ - -/* - * BSD header for 802.11 plus a number of bits of link-layer information - * including radio information. - */ -#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus BSD radio header */ - -/* - * Reserved for the TZSP encapsulation, as per request from - * Chris Waters - * TZSP is a generic encapsulation for any other link type, - * which includes a means to include meta-information - * with the packet, e.g. signal strength and channel - * for 802.11 packets. - */ -#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ - -/* - * BSD's ARCNET headers have the source host, destination host, - * and type at the beginning of the packet; that's what's handed - * up to userland via BPF. - * - * Linux's ARCNET headers, however, have a 2-byte offset field - * between the host IDs and the type; that's what's handed up - * to userland via PF_PACKET sockets. - * - * We therefore have to have separate DLT_ values for them. - */ -#define DLT_ARCNET_LINUX 129 /* ARCNET */ - -/* - * Juniper-private data link types, as per request from - * Hannes Gredler . The DLT_s are used - * for passing on chassis-internal metainformation such as - * QOS profiles, etc.. - */ -#define DLT_JUNIPER_MLPPP 130 -#define DLT_JUNIPER_MLFR 131 -#define DLT_JUNIPER_ES 132 -#define DLT_JUNIPER_GGSN 133 -#define DLT_JUNIPER_MFR 134 -#define DLT_JUNIPER_ATM2 135 -#define DLT_JUNIPER_SERVICES 136 -#define DLT_JUNIPER_ATM1 137 - -/* - * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund - * . The header that's presented is an Ethernet-like - * header: - * - * #define FIREWIRE_EUI64_LEN 8 - * struct firewire_header { - * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; - * u_char firewire_shost[FIREWIRE_EUI64_LEN]; - * u_short firewire_type; - * }; - * - * with "firewire_type" being an Ethernet type value, rather than, - * for example, raw GASP frames being handed up. - */ -#define DLT_APPLE_IP_OVER_IEEE1394 138 - -/* - * 139 through 142 are reserved for SS7. - */ - -/* - * Reserved for DOCSIS MAC frames. - */ -#define DLT_DOCSIS 143 - -/* - * Linux-IrDA packets. Protocol defined at http://www.irda.org. - * Those packets include IrLAP headers and above (IrLMP...), but - * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy - * framing can be handled by the hardware and depend on the bitrate. - * This is exactly the format you would get capturing on a Linux-IrDA - * interface (irdaX), but not on a raw serial port. - * Note the capture is done in "Linux-cooked" mode, so each packet include - * a fake packet header (struct sll_header). This is because IrDA packet - * decoding is dependant on the direction of the packet (incomming or - * outgoing). - * When/if other platform implement IrDA capture, we may revisit the - * issue and define a real DLT_IRDA... - * Jean II - */ -#define DLT_LINUX_IRDA 144 - -/* - * Reserved for IBM SP switch and IBM Next Federation switch. - */ -#define DLT_IBM_SP 145 -#define DLT_IBM_SN 146 - -/* - * Reserved for private use. If you have some link-layer header type - * that you want to use within your organization, with the capture files - * using that link-layer header type not ever be sent outside your - * organization, you can use these values. - * - * No libpcap release will use these for any purpose, nor will any - * tcpdump release use them, either. - * - * Do *NOT* use these in capture files that you expect anybody not using - * your private versions of capture-file-reading tools to read; in - * particular, do *NOT* use them in products, otherwise you may find that - * people won't be able to use tcpdump, or snort, or Ethereal, or... to - * read capture files from your firewall/intrusion detection/traffic - * monitoring/etc. appliance, or whatever product uses that DLT_ value, - * and you may also find that the developers of those applications will - * not accept patches to let them read those files. - * - * Also, do not use them if somebody might send you a capture using them - * for *their* private type and tools using them for *your* private type - * would have to read them. - * - * Instead, ask "tcpdump-workers@tcpdump.org" for a new DLT_ value, - * as per the comment above, and use the type you're given. - */ -#define DLT_USER0 147 -#define DLT_USER1 148 -#define DLT_USER2 149 -#define DLT_USER3 150 -#define DLT_USER4 151 -#define DLT_USER5 152 -#define DLT_USER6 153 -#define DLT_USER7 154 -#define DLT_USER8 155 -#define DLT_USER9 156 -#define DLT_USER10 157 -#define DLT_USER11 158 -#define DLT_USER12 159 -#define DLT_USER13 160 -#define DLT_USER14 161 -#define DLT_USER15 162 - -/* - * For future use with 802.11 captures - defined by AbsoluteValue - * Systems to store a number of bits of link-layer information - * including radio information: - * - * http://www.shaftnet.org/~pizza/software/capturefrm.txt - * - * but could and arguably should also be used by non-AVS Linux - * 802.11 drivers; that may happen in the future. - */ -#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ - -/* - * Juniper-private data link type, as per request from - * Hannes Gredler . The DLT_s are used - * for passing on chassis-internal metainformation such as - * QOS profiles, etc.. - */ -#define DLT_JUNIPER_MONITOR 164 - -/* - * The instruction encodings. - */ -/* instruction classes */ -#define BPF_CLASS(code) ((code) & 0x07) -#define BPF_LD 0x00 -#define BPF_LDX 0x01 -#define BPF_ST 0x02 -#define BPF_STX 0x03 -#define BPF_ALU 0x04 -#define BPF_JMP 0x05 -#define BPF_RET 0x06 -#define BPF_MISC 0x07 - -/* ld/ldx fields */ -#define BPF_SIZE(code) ((code) & 0x18) -#define BPF_W 0x00 -#define BPF_H 0x08 -#define BPF_B 0x10 -#define BPF_MODE(code) ((code) & 0xe0) -#define BPF_IMM 0x00 -#define BPF_ABS 0x20 -#define BPF_IND 0x40 -#define BPF_MEM 0x60 -#define BPF_LEN 0x80 -#define BPF_MSH 0xa0 - -/* alu/jmp fields */ -#define BPF_OP(code) ((code) & 0xf0) -#define BPF_ADD 0x00 -#define BPF_SUB 0x10 -#define BPF_MUL 0x20 -#define BPF_DIV 0x30 -#define BPF_OR 0x40 -#define BPF_AND 0x50 -#define BPF_LSH 0x60 -#define BPF_RSH 0x70 -#define BPF_NEG 0x80 -#define BPF_JA 0x00 -#define BPF_JEQ 0x10 -#define BPF_JGT 0x20 -#define BPF_JGE 0x30 -#define BPF_JSET 0x40 -#define BPF_SRC(code) ((code) & 0x08) -#define BPF_K 0x00 -#define BPF_X 0x08 - -/* ret - BPF_K and BPF_X also apply */ -#define BPF_RVAL(code) ((code) & 0x18) -#define BPF_A 0x10 - -/* misc */ -#define BPF_MISCOP(code) ((code) & 0xf8) -#define BPF_TAX 0x00 -#define BPF_TXA 0x80 - -/* - * The instruction data structure. - */ -struct bpf_insn { - u_short code; - u_char jt; - u_char jf; - bpf_int32 k; -}; - -/* - * Macros for insn array initializers. - */ -#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } -#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } - -#if __STDC__ || defined(__cplusplus) -extern int bpf_validate(struct bpf_insn *, int); -extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); -#else -extern int bpf_validate(); -extern u_int bpf_filter(); -#endif - -/* - * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). - */ -#define BPF_MEMWORDS 16 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libpcap/pcap-int.h b/lib/libpcap/pcap-int.h index 4639250cf259..f439b2bf14c2 100644 --- a/lib/libpcap/pcap-int.h +++ b/lib/libpcap/pcap-int.h @@ -1,4 +1,4 @@ -/* $NetBSD: pcap-int.h,v 1.9 2002/09/22 16:13:01 thorpej Exp $ */ +/* $NetBSD: pcap-int.h,v 1.10 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1994, 1995, 1996 @@ -32,21 +32,36 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) Header: pcap-int.h,v 1.18 96/11/27 18:43:09 leres Exp (LBL) + * @(#) Header: /tcpdump/master/libpcap/pcap-int.h,v 1.55.2.4 2003/12/15 01:42:24 guy Exp (LBL) */ #ifndef pcap_int_h #define pcap_int_h +#ifdef __cplusplus +extern "C" { +#endif + #include +#ifdef WIN32 +#include +#endif /* WIN32 */ + /* * Savefile */ +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + struct pcap_sf { FILE *rfile; int swapped; int hdrsize; + swapped_type_t lengths_swapped; int version_major; int version_minor; u_char *base; @@ -55,26 +70,48 @@ struct pcap_sf { struct pcap_md { struct pcap_stat stat; /*XXX*/ - int use_bpf; + int use_bpf; /* using kernel filter */ u_long TotPkts; /* can't oflow for 79 hrs on ether */ u_long TotAccepted; /* count accepted by filter */ u_long TotDrops; /* count of dropped packets */ long TotMissed; /* missed by i/f during this run */ long OrigMissed; /* missed by i/f before this run */ #ifdef linux - int pad; - int skip; - char *device; + int sock_packet; /* using Linux 2.0 compatible interface */ + int timeout; /* timeout specified to pcap_open_live */ + int clear_promisc; /* must clear promiscuous mode when we close */ + int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ + int lo_ifindex; /* interface index of the loopback device */ + char *device; /* device name */ + struct pcap *next; /* list of open promiscuous sock_packet pcaps */ +#endif + +#ifdef HAVE_DAG_API + void *dag_mem_base; /* DAG card memory base address */ + u_int dag_mem_bottom; /* DAG card current memory bottom pointer */ + u_int dag_mem_top; /* DAG card current memory top pointer */ + int dag_fcs_bits; /* Number of checksum bits from link layer */ + int dag_offset_flags; /* Flags to pass to dag_offset(). */ #endif }; struct pcap { +#ifdef WIN32 + ADAPTER *adapter; + LPPACKET Packet; + int timeout; + int nonblock; +#else int fd; + int selectable_fd; +#endif /* WIN32 */ int snapshot; int linktype; int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ + int break_loop; /* flag set to force break from packet-reading loop */ + struct pcap_sf sf; struct pcap_md md; @@ -91,15 +128,27 @@ struct pcap { */ u_char *pkt; + /* + * Methods. + */ + int (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *); + int (*setfilter_op)(pcap_t *, struct bpf_program *); + int (*set_datalink_op)(pcap_t *, int); + int (*getnonblock_op)(pcap_t *, char *); + int (*setnonblock_op)(pcap_t *, int, char *); + int (*stats_op)(pcap_t *, struct pcap_stat *); + void (*close_op)(pcap_t *); /* * Placeholder for filter code if bpf not in kernel. */ struct bpf_program fcode; - char errbuf[PCAP_ERRBUF_SIZE]; + char errbuf[PCAP_ERRBUF_SIZE + 1]; int dlt_count; int *dlt_list; + + struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ }; /* @@ -145,6 +194,25 @@ struct pcap_sf_pkthdr { bpf_u_int32 len; /* length this packet (off wire) */ }; +/* + * How a `pcap_pkthdr' is actually stored in dumpfiles written + * by some patched versions of libpcap (e.g. the ones in Red + * Hat Linux 6.1 and 6.2). + * + * Do not change the format of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * Instead, introduce a new structure, as per the above. + */ + +struct pcap_sf_patched_pkthdr { + struct pcap_timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ + int index; + unsigned short protocol; + unsigned char pkt_type; +}; + int yylex(void); #ifndef min @@ -155,12 +223,73 @@ int yylex(void); int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *); int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); -/* ULTRIX, Digital UNIX & NetBSD pad to make everything line - up on a nice boundary */ -#if defined(ultrix) || defined(__alpha) || defined(__NetBSD__) + +/* + * Ultrix, DEC OSF/1^H^H^H^H^H^H^H^H^HDigital UNIX^H^H^H^H^H^H^H^H^H^H^H^H + * Tru64 UNIX, and NetBSD pad to make everything line up on a nice boundary. + */ +#if defined(ultrix) || defined(__osf__) || defined(__NetBSD__) #define PCAP_FDDIPAD 3 #endif -/* XXX */ -extern int pcap_fddipad; +#ifndef HAVE_STRLCPY +#define strlcpy(x, y, z) \ + (strncpy((x), (y), (z)), \ + ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \ + strlen((y))) +#endif + +#include + +#if !defined(HAVE_SNPRINTF) +#define snprintf pcap_snprintf +extern int snprintf (char *, size_t, const char *, ...); +#endif + +#if !defined(HAVE_VSNPRINTF) +#define vsnprintf pcap_vsnprintf +extern int vsnprintf (char *, size_t, const char *, va_list ap); +#endif + +/* + * Routines that most pcap implementations can use for non-blocking mode. + */ +#ifndef WIN32 +int pcap_getnonblock_fd(pcap_t *, char *); +int pcap_setnonblock_fd(pcap_t *p, int, char *); +#endif + +/* + * Internal interfaces for "pcap_findalldevs()". + * + * "pcap_platform_finddevs()" is a platform-dependent routine to + * add devices not found by the "standard" mechanisms (SIOCGIFCONF, + * "getifaddrs()", etc.. + * + * "pcap_add_if()" adds an interface to the list of interfaces. + */ +int pcap_platform_finddevs(pcap_if_t **, char *); +int add_addr_to_iflist(pcap_if_t **, char *, u_int, struct sockaddr *, + size_t, struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *, size_t, char *); +int pcap_add_if(pcap_if_t **, char *, u_int, const char *, char *); +struct sockaddr *dup_sockaddr(struct sockaddr *, size_t); +int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, u_int, + const char *, char *); + +#ifdef WIN32 +char *pcap_win32strerror(void); +#endif + +/* XXX */ +extern u_int pcap_fddipad; + +int install_bpf_program(pcap_t *, struct bpf_program *); + +int pcap_strcasecmp(const char *, const char *); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/libpcap/pcap-namedb.h b/lib/libpcap/pcap-namedb.h index 69d5689015cf..36c318c0ead0 100644 --- a/lib/libpcap/pcap-namedb.h +++ b/lib/libpcap/pcap-namedb.h @@ -1,4 +1,4 @@ -/* $NetBSD: pcap-namedb.h,v 1.6 1999/07/02 10:05:22 itojun Exp $ */ +/* $NetBSD: pcap-namedb.h,v 1.7 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1994, 1996 @@ -32,12 +32,16 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) Header: pcap-namedb.h,v 1.5 96/07/14 03:00:14 leres Exp (LBL) + * @(#) Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.8 2000/07/29 07:36:43 guy Exp (LBL) */ #ifndef lib_pcap_ethers_h #define lib_pcap_ethers_h +#ifdef __cplusplus +extern "C" { +#endif + /* * As returned by the pcap_next_etherent() * XXX this stuff doesn't belong in this interface, but this @@ -78,4 +82,8 @@ int __pcap_atodn(const char *, bpf_u_int32 *); int __pcap_atoin(const char *, bpf_u_int32 *); u_short __pcap_nametodnaddr(const char *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/libpcap/pcap-stdinc.h b/lib/libpcap/pcap-stdinc.h deleted file mode 100644 index fdae7dcdc820..000000000000 --- a/lib/libpcap/pcap-stdinc.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $NetBSD: pcap-stdinc.h,v 1.1.1.2 2004/09/19 21:57:55 dyoung Exp $ */ - -/* - * Copyright (c) 2002 - 2003 - * NetGroup, Politecnico di Torino (Italy) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Politecnico di Torino nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#define SIZEOF_CHAR 1 -#define SIZEOF_SHORT 2 -#define SIZEOF_INT 4 - -/* - * Avoids a compiler warning in case this was already defined - * (someone defined _WINSOCKAPI_ when including 'windows.h', in order - * to prevent it from including 'winsock.h') - */ -#ifdef _WINSOCKAPI_ -#undef _WINSOCKAPI_ -#endif -#include - -#include - -#include "bittypes.h" -#include -#include - -#ifndef __MINGW32__ -#include "IP6_misc.h" -#endif - -#define caddr_t char* - -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define inline __inline diff --git a/lib/libpcap/pcap.3 b/lib/libpcap/pcap.3 index 7a165f475812..fbe8d76b7c93 100644 --- a/lib/libpcap/pcap.3 +++ b/lib/libpcap/pcap.3 @@ -1,4 +1,6 @@ -.\" $NetBSD: pcap.3,v 1.19 2003/04/16 13:35:12 wiz Exp $ +.\" $NetBSD: pcap.3,v 1.20 2004/09/27 23:02:53 dyoung Exp $ +.\ +.\" @(#) Header: /tcpdump/master/libpcap/pcap.3,v 1.51.2.9 2004/03/28 21:45:32 fenner Exp .\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. @@ -19,7 +21,7 @@ .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" -.Dd September 25, 2002 +.Dd February 27, 2004 .Os .Dt PCAP 3 .Sh NAME @@ -29,29 +31,36 @@ .Lb libpcap .Sh SYNOPSIS .In pcap.h -.Ft pcap_t * -.Fn pcap_open_live "char *device" "int snaplen" "int promisc" \ -"int to_ms" "char *ebuf" -.Ft pcap_t * -.Fn pcap_open_offline "char *fname" "char *ebuf" -.Ft pcap_dumper_t * -.Fn pcap_dump_open "pcap_t *p" "char *fname" .Ft char .Dv errbuf[PCAP_ERRBUF_SIZE]; +.Ft pcap_t * +.Fn pcap_open_live "const char *device" "int snaplen" "int promisc" \ +"int to_ms" "char *errbuf" +.Ft pcap_t * +.Fn pcap_open_dead "int linktype" "int snaplen" +.Ft pcap_t * +.Fn pcap_open_offline "const char *fname" "char *errbuf" +.Ft pcap_dumper_t * +.Fn pcap_dump_open "pcap_t *p" "const char *fname" +.Ft int +.Fn pcap_setnonblock "pcap_t *p" "int nonblock" "char *errbuf" +.Ft int +.Fn pcap_getnonblock "pcap_t *p" "char *errbuf" +.Ft int +.Fn pcap_findalldevs "pcap_if_t **alldevsp" "char *ebuf" +.Ft void +.Fn pcap_freealldevs "pcap_if_t *alldevs" .Ft char * .Fn pcap_lookupdev "char *errbuf" .Ft int -.Fn pcap_lookupnet "char *device" "bpf_u_int32 *netp" \ +.Fn pcap_lookupnet "const char *device" "bpf_u_int32 *netp" \ "bpf_u_int32 *maskp" "char *errbuf" .Ft int -.Fn pcap_dispatch "pcap_t *p" "int cnt" \ -"pcap_handler callback" "u_char *user" +.Fn pcap_dispatch "pcap_t *p" "int cnt" "pcap_handler callback" "u_char *user" .Ft int -.Fn pcap_loop "pcap_t *p" "int cnt" \ -"pcap_handler callback" "u_char *user" +.Fn pcap_loop "pcap_t *p" "int cnt" "pcap_handler callback" "u_char *user" .Ft void -.Fn pcap_dump "u_char *user" "struct pcap_pkthdr *h" \ -"u_char *sp" +.Fn pcap_dump "u_char *user" "struct pcap_pkthdr *h" "u_char *sp" .Ft int .Fn pcap_compile "pcap_t *p" "struct bpf_program *fp" \ "char *str" "int optimize" "bpf_u_int32 netmask" @@ -61,15 +70,27 @@ "bpf_uint32 netmask" "char *errbuf" .Ft int .Fn pcap_setfilter "pcap_t *p" "struct bpf_program *fp" -.Ft int -.Fn pcap_set_datalink "pcap_t *p" "int dlt" -.Ft int -.Fn pcap_list_datalinks "pcap_t *p" "int **dlt_buf" +.Ft void +.Fn pcap_freecode "struct bpf_program *" .Ft const u_char * .Fn pcap_next "pcap_t *p" "struct pcap_pkthdr *h" .Ft int +.Fn pcap_next_ex "pcap_t *p" "struct pcap_pkthdr **pkt_header" "const u_char **pkt_data" +.Ft void +.Fn pcap_breakloop "pcap_t *" +.Ft int .Fn pcap_datalink "pcap_t *p" .Ft int +.Fn pcap_list_datalinks "pcap_t *p" "int **dlt_buf" +.Ft int +.Fn pcap_set_datalink "pcap_t *p" "int dlt" +.Ft int +.Fn pcap_datalink_name_to_val "const char *name" +.Ft const char * +.Fn pcap_datalink_val_to_name "int dlt" +.Ft const char * +.Fn pcap_datalink_val_to_description "int dlt" +.Ft int .Fn pcap_snapshot "pcap_t *p" .Ft int .Fn pcap_is_swapped "pcap_t *p" @@ -83,14 +104,22 @@ .Fn pcap_file "pcap_t *p" .Ft int .Fn pcap_fileno "pcap_t *p" +.Ft int +.Fn pcap_get_selectable_fd "pcap_t *p" .Ft void .Fn pcap_perror "pcap_t *p" "char *prefix" .Ft char * .Fn pcap_geterr "pcap_t *p" .Ft char * .Fn pcap_strerror "int error" +.Ft const char * +.Fn pcap_lib_version "void" .Ft void .Fn pcap_close "pcap_t *p" +.Ft int +.Fn pcap_dump_flush "pcap_dumper_t *p" +.Ft FILE * +.Fn pcap_dump_file "pcap_dumper_t *p" .Ft void .Fn pcap_dump_close "pcap_dumper_t *p" .Sh DESCRIPTION @@ -100,24 +129,92 @@ library provides a high level interface to packet capture systems. All packets on the network, even those destined for other hosts, are accessible through this mechanism. .Sh ROUTINES +NOTE: +.Fa errbuf +in +.Fn pcap_open_live , +.Fn pcap_open_dead , +.Fn pcap_open_offline , +.Fn pcap_setnonblock , +.Fn pcap_getnonblock , +.Fn pcap_findalldevs , +.Fn pcap_lookupdev , +and +.Fn pcap_lookupnet +is assumed to be able to hold at least +.Dv PCAP_ERRBUF_SIZE +chars. +.Pp .Fn pcap_open_live -is used to obtain a packet capture descriptor to look at packets on -the network. +is used to obtain a packet capture descriptor to look +at packets on the network. .Fa device -is a string that specifies the network device to open. +is a string that specifies the network device to open; on Linux systems +with 2.2 or later kernels, a +.Fa device +argument of +.Em any +or +.Dv NULL +can be used to capture packets from all interfaces. .Fa snaplen specifies the maximum number of bytes to capture. +If this value is less +than the size of a packet that is captured, only the first +.Fa snaplen +bytes of that packet will be captured and provided as packet data. +A value of +.Li 65535 +should be sufficient, on most if not all networks, to +capture all the data available from the packet. .Fa promisc specifies if the interface is to be put into promiscuous mode. (Note that even if this parameter is false, the interface could well be in promiscuous mode for some other reason.) +For now, this doesn't work on the +.Li any +device; if an argument of +.Em any +or +.Em NULL +is supplied, the +.Fa promisc +flag is ignored. .Fa to_ms specifies the read timeout in milliseconds. -.Fa ebuf -is used to return error text and is only set when +The read timeout is used to +arrange that the read not necessarily return immediately when a packet +is seen, but that it wait for some amount of time to allow more packets +to arrive and to read multiple packets from the OS kernel in one +operation. +Not all platforms support a read timeout; on platforms that +don't, the read timeout is ignored. +A zero value for +.Fa to_ms , +on platforms that support a read timeout, +will cause a read to wait forever to allow enough packets to +arrive, with no timeout. +.Fa errbuf +is used to return error or warning text. It will be set to error text when .Fn pcap_open_live fails and returns .Em NULL . +.Fa errbuf +may also be set to warning text when +.Fn pcap_open_live +succeeds; to detect this case the caller should store a zero-length string in +.Fa errbuf +before calling +.Fn pcap_open_live() +and display the warning to the user if +.Fa errbuf +is no longer a zero-length string. +.Pp +.Fn pcap_open_dead +is used for creating a +.Vt pcap_t +structure to use when calling the other functions in libpcap. +It is typically used when just using libpcap for compiling BPF code. .Pp .Fn pcap_open_offline is called to open a @@ -131,7 +228,7 @@ The name .Dq \&- is a synonym for .Em stdin . -.Fa ebuf +.Fa errbuf is used to return error text and is only set when .Fn pcap_open_offline fails and returns @@ -163,6 +260,138 @@ is returned, .Fn pcap_geterr can be used to get the error text. .Pp +.Fn pcap_setnonblock +puts a capture descriptor, opened with +.Fn pcap_open_live , +into +.Dq non-blocking +mode, or takes it out of +.Dq non-blocking +mode, depending on whether the +.Fa nonblock +argument is non-zero or zero. +It has no effect on +.Dq savefiles . +If there is an error, \-1 is returned and +.Fa errbuf +is filled in with an appropriate error message; otherwise, 0 is +returned. +In +.Dq non-blocking +mode, an attempt to read from the capture descriptor with +.Fn pcap_dispatch +will, if no packets are currently available to be read, return 0 +immediately rather than blocking waiting for packets to arrive. +.Fn pcap_loop +and +.Fn pcap_next +will not work in +.Dq non-blocking +mode. +.Pp +.Fn pcap_getnonblock +returns the current +.Dq non-blocking +state of the capture descriptor; it +always returns 0 on +.Dq savefiles . +If there is an error, \-1 is returned and +.Fa errbuf +is filled in with an appropriate error message. +.Pp +.Fn pcap_findalldevs +constructs a list of network devices that can be opened with +.Fn pcap_open_live . +(Note that there may be network devices that cannot be opened with +.Fn pcap_open_live +by the +process calling +.Fn pcap_findalldevs , +because, for example, that process might not have sufficient privileges +to open them for capturing; if so, those devices will not appear on the +list.) +.Fa alldevsp +is set to point to the first element of the list; each element of the +list is of type +.Vt pcap_if_t , +and has the following members: +.Bl -tag -width "description" -compact -offset indent +.It Va next +if not +.Dv NULL , +a pointer to the next element in the list; +.Dv NULL +for the last element of the list +.It Va name +a pointer to a string giving a name for the device to pass to +.Fn pcap_open_live +.It Va description +if not +.Dv NULL , +a pointer to a string giving a human-readable description of the device +.It Va addresses +a pointer to the first element of a list of addresses for the interface +.It Va flags +interface flags: +.Bl -tag -width "PCAP_IF_LOOPBACK" -compact -offset indent +.It Dv PCAP_IF_LOOPBACK +set if the interface is a loopback interface +.El +.El +.Pp +Each element of the list of addresses is of type +.Vt pcap_addr_t , +and has the following members: +.Bl -tag -width "broadaddr" -compact -offset indent +.It Va next +if not +.Dv NULL , +a pointer to the next element in the list; +.Dv NULL +for the last element of the list +.It Va addr +a pointer to a +.Vt "struct sockaddr" +containing an address +.It Va netmask +if not +.Dv NULL , +a pointer to a +.Vt "struct sockaddr" +that contains the netmask corresponding to the address pointed to by +.Va addr +.It Va broadaddr +if not +.Dv NULL , +a pointer to a +.Vt "struct sockaddr" +that contains the broadcast address corresponding to the address pointed +to by +.Va addr ; +may be +.Dv NULL if the interface doesn't support broadcasts +.It Va dstaddr +if not +.Dv NULL , +a pointer to a +.Vt "struct sockaddr" +that contains the destination address corresponding to the address pointed +to by +.Va addr ; +may be null if the interface isn't a point-to-point interface +.El +.Pp +.Em \-1 +is returned on failure, in which case +.Fa errbuf +is filled in with an appropriate error message; +.Em 0 +is returned on success. +.Pp +.Fn pcap_freealldevs +is used to free a list allocated by +.Fn pcap_findalldevs . +.Pp .Fn pcap_lookupdev returns a pointer to a network device suitable for use with .Fn pcap_open_live @@ -185,7 +414,7 @@ and are .Fa bpf_u_int32 pointers. -A return of -1 indicates an error in which case +A return of \-1 indicates an error in which case .Fa errbuf is filled in with an appropriate error message. .Pp @@ -193,9 +422,15 @@ is filled in with an appropriate error message. is used to collect and process packets. .Fa cnt specifies the maximum number of packets to process before returning. +This is not a minimum number; when reading a live capture, only one +bufferful of packets is read at a time, so fewer than +.Fa cnt +packets may be processed. A .Fa cnt -of -1 processes all the packets received in one buffer. +of \-1 processes all the packets received in one buffer when reading a +live capture, or all the packets in the file when reading a +.Dq savefile . A .Fa cnt of 0 processes all packets until an error occurs (or @@ -207,22 +442,246 @@ a .Fa u_char pointer which is passed in from .Fn pcap_dispatch , -a pointer to the -.Fa pcap_pkthdr -struct (which precede the actual network headers and data), +a +.Vt const struct pcap_pkthdr +pointer to a structure (which precedes the actual network headers +and data) with the following members: +.Bl -tag -width "caplen" -compact -offset indent +.It Va ts +a +.Vt struct timeval +containing the time when the packet was captured +.It Va caplen +a +.Vt bpf_u_int32 +giving the number of bytes of the packet that are available from the +capture +.It Va len +a +.Vt bpf_u_int32 +giving the length of the packet, in bytes (which might be more than the +number of bytes available from the capture, if the length of the packet +is larger than the maximum number of bytes to capture) +.El +.Pp and a -.Fa u_char -pointer to the packet data. +.Vt const u_char +pointer to the first +.Va caplen +(as given in the +.Vt struct pcap_pkthdr +a pointer to which is passed to the callback routine) +bytes of data from the packet (which won't necessarily be the entire +packet; to capture the entire packet, you will have to provide a value +for +.Va snaplen +in your call to +.Fn pcap_open_live +that is sufficiently large to get all of the packet's data - a value of +65535 should be sufficient on most if not all networks). +.Pp The number of packets read is returned. -Zero is returned when -.Em EOF -is reached in a +Zero is returned if no packets were read from a live capture (if, for +example, they were discarded because they didn't pass the packet filter, +or if, on platforms that support a read timeout that starts before any +packets arrive, the timeout expires before any packets arrive, or if the +file descriptor for the capture device is in non-blocking mode and no +packets were available to be read) or if no more packets are available +in a .Dq savefile . -A return of -1 indicates an error in which case +A return of +.Li \-1 +indicates an error in which case .Fn pcap_perror or .Fn pcap_geterr may be used to display the error text. +A return of +.Li \-2 +indicates that the loop terminated due to a call to +.Fn pcap_breakloop +before any packets were processed. +.Bf Em +If your application uses pcap_breakloop(), +make sure that you explicitly check for +.Li \-1 +and +.Li \-2 , +rather than just +checking for a return value +\*(Lt +.Li 0 . +.Ef +.Pp +.Em NOTE : +when reading a live capture, +.Fn pcap_dispatch +will not necessarily return when the read times out; on some platforms, +the read timeout isn't supported, and, on other platforms, the timer +doesn't start until at least one packet arrives. +This means that the read timeout should +.Em not +be used in, for example, an interactive application, to allow the packet +capture loop to +.Dq poll for user input periodically, as there's no +guarantee that +.Fn pcap_dispatch +will return after the timeout expires. +.Pp +.Fn pcap_loop +is similar to +.Fn pcap_dispatch +except it keeps reading packets until +.Va cnt +packets are processed or an error occurs. +It does +.Em not +return when live read timeouts occur. +Rather, specifying a non-zero read timeout to +.Fn pcap_open_live +and then calling +.Fn pcap_dispatch +allows the reception and processing of any packets that arrive when the +timeout occurs. +A negative +.Va cnt +causes +.Fn pcap_loop +to loop forever (or at least until an error occurs). +.Li \-1 +is returned on +an error; +.Li 0 +is returned if +.Va cnt +is exhausted; +.Li \-2 +is returned if the loop terminated due to a call to +.Fn pcap_breakloop +before any packets were processed. +.Bf Em +If your application uses +.Fn pcap_breakloop , +make sure that you explicitly check for +.Li \-1 +and +.Li \-2 , +rather than just checking for a return value +\*(Lt +.Li 0. +.Ef +.Pp +.Fn pcap_next +reads the next packet (by calling +.Fn pcap_dispatch +with a +.Va cnt +of 1) and returns a +.Vt u_char +pointer to the data in that packet. (The +.Vt pcap_pkthdr +struct for that packet is not supplied.) +.Dv NULL +is returned if an error occured, or if no packets were read from a live +capture (if, for example, they were discarded because they didn't pass +the packet filter, or if, on platforms that support a read timeout that +starts before any packets arrive, the timeout expires before any packets +arrive, or if the file descriptor for the capture device is in +non-blocking mode and no packets were available to be read), or if no +more packets are available in a +.Dq savefile . +Unfortunately, there is no way to determine whether an error occured +or not. +.Pp +.Fn pcap_next_ex +reads the next packet and returns a success/failure indication: +.Bl -tag -width "\-1" -compact -offset indent +.It Li 1 +the packet was read without problems +.It Li 0 +packets are being read from a live capture, and the timeout expired +.It Li \-1 +an error occurred while reading the packet +.It Li \-2 +packets are being read from a +.Dq savefile , +and there are no more +packets to read from the savefile. +.El +.Pp +If the packet was read without problems, the pointer pointed to by the +.Va pkt_header +argument is set to point to the +.Va pcap_pkthdr +struct for the packet, and the +pointer pointed to by the +.Va pkt_data +argument is set to point to the data in the packet. +.Pp +.Fn pcap_breakloop +sets a flag that will force +.Fn pcap_dispatch +or +.Fn pcap_loop +to return rather than looping; they will return the number of packets +that have been processed so far, or \-2 if no packets have been +processed so far. +.Pp +This routine is safe to use inside a signal handler on UNIX or a console +control handler on Windows, as it merely sets a flag that is checked +within the loop. +.Pp +The flag is checked in loops reading packets from the OS - a signal by +itself will not necessarily terminate those loops - as well as in loops +processing a set of packets returned by the OS. +.Bf Em +Note that if you are catching signals on UNIX systems that support +restarting system calls after a signal, and calling pcap_breakloop() +in the signal handler, you must specify, when catching those signals, +that system calls should NOT be restarted by that signal. Otherwise, +if the signal interrupted a call reading packets in a live capture, +when your signal handler returns after calling pcap_breakloop(), the +call will be restarted, and the loop will not terminate until more +packets arrive and the call completes. +.Pp +Note also that, in a multi-threaded application, if one thread is +blocked in +.Fn pcap_dispatch , +.Fn pcap_loop , +.Fn pcap_next , +or +.Fn pcap_next_ex , +a call to +.Fn pcap_breakloop +in a different thread will not unblock that thread; you will need to use +whatever mechanism the OS provides for breaking a thread out of blocking +calls in order to unblock the thread, such as thread cancellation in +systems that support POSIX threads. +.Ef +.Pp +Note that +.Fn pcap_next +will, on some platforms, loop reading packets from the OS; that loop +will not necessarily be terminated by a signal, so +.Fn pcap_breakloop +should be used to terminate packet processing even if +.Fn pcap_next +is being used. +.Pp +.Fn pcap_breakloop +does not guarantee that no further packets will be processed by +.Fn pcap_dispatch +or +.Fn pcap_loop +after it is called; at most one more packet might be processed. +.Pp +If \-2 is returned from +.Fn pcap_dispatch +or +.Fn pcap_loop , +the flag is cleared, so a subsequent call will resume reading packets. +If a positive number is returned, the flag is not cleared, so a +subsequent call will return \-2 and clear the flag. .Pp .Fn pcap_dump outputs a packet to the @@ -230,7 +689,15 @@ outputs a packet to the opened with .Fn pcap_dump_open . Note that its calling arguments are suitable for use with -.Fn pcap_dispatch . +.Fn pcap_dispatch +or +.Fn pcap_loop . +If called directly, the +.Fa user +parameter is of type +.Vt pcap_dumper_t +as returned by +.Fn pcap_dump_open . .Pp .Fn pcap_compile is used to compile the string @@ -244,18 +711,37 @@ struct and is filled in by .Fa optimize controls whether optimization on the resulting code is performed. .Fa netmask -specifies the netmask of the local net. +specifies the IPv4 netmask of the network on which packets are being +captured; it is used only when checking for IPv4 broadcast addresses in +the filter program. +If the netmask of the network on which packets are +being captured isn't known to the program, or if packets are being +captured on the Linux "any" pseudo-interface that can capture on more +than one network, a value of 0 can be supplied; tests for IPv4 broadcast +addreses won't be done correctly, but all other tests in the filter +program will be OK. +A return of \-1 indicates an error in which case +.Fn pcap_geterr +may be used to display the error text. .Pp .Fn pcap_compile_nopcap is similar to .Fn pcap_compile -except that instead of passing a pcap descriptor, one passes the -snaplen, linktype, and error buffer (which must be -.Em PCAP_ERRBUF_SIZE -in length) explicitly. -It is intended to be used for compiling filters for direct -bpf usage, without necessarily having called +except that instead of passing a pcap structure, one passes the +snaplen and linktype explicitly. +It is intended to be used for +compiling filters for direct BPF usage, without necessarily having +called .Fn pcap_open . +A return of \-1 indicates an error; the error text is unavailable. +.Fn ( pcap_compile_nopcap +is a wrapper around +.Fn pcap_open_dead , +.Fn pcap_compile , +and +.Fn pcap_close ; +the latter three routines can be used directly in order to get the error +text for a compilation error.) .Pp .Fn pcap_setfilter is used to specify a filter program. @@ -265,32 +751,295 @@ is a pointer to an array of struct, usually the result of a call to .Fn pcap_compile . .Em \-1 -is returned on failure; +is returned on failure, in which case +.Fn pcap_geterr +may be used to display the error text; .Em 0 is returned on success. .Pp +.Fn pcap_freecode +is used to free up allocated memory pointed to by a +.Fa bpf_program +struct generated by +.Fn pcap_compile +when that BPF program is no longer needed, for example after it +has been made the filter program for a pcap structure by a call to +.Fn pcap_setfilter . +.Pp +.Fn pcap_datalink +returns the link layer type; link layer types it can return include: +.Pp +.Bl -tag -width "DLT_IEEE802_11" -compact -offset indent +.It Dv DLT_NULL +BSD loopback encapsulation; the link layer header is a 4-byte field, in +.Em host +byte order, containing a PF_ value from +.In sys/socket.h +for the network-layer protocol of the packet. +.Pp +Note that +.Dq host byte order +is the byte order of the machine on which the packets are captured, +and the PF_ values are for the OS of the machine on which the +packets are captured; if a live capture is being done, +.Dq host byte order +is the byte order of the machine capturing the packets, and the +PF_ values are those of the OS of the machine capturing the packets, +but if a +.Dq savefile +is being read, the byte order and PF_ values are +.Em not +necessarily those of the machine reading the capture file. +.Pp +.It Dv DLT_EN10MB +Ethernet (10Mb, 100Mb, 1000Mb, and up) +.Pp +.It Dv DLT_IEEE802 +IEEE 802.5 Token Ring +.Pp +.It Dv DLT_ARCNET +ARCNET +.Pp +.It Dv DLT_SLIP +SLIP; the link layer header contains, in order: +.Bd -ragged -offset indent -compact +.Pp +a 1-byte flag, which is 0 for packets received by the machine and 1 for +packets sent by the machine; +.Pp +a 1-byte field, the upper 4 bits of which indicate the type of packet, +as per RFC 1144: +.Bl -tag -width "0xNN" -offset indent +.It Li 0x40 +an unmodified IP datagram (TYPE_IP); +.It Li 0x70 +an uncompressed-TCP IP datagram (UNCOMPRESSED_TCP), with that byte being +the first byte of the raw IP header on the wire, containing the +connection number in the protocol field; +.It Li 0x80 +a compressed-TCP IP datagram (COMPRESSED_TCP), with that byte being the +first byte of the compressed TCP/IP datagram header; +.El +.Pp +for UNCOMPRESSED_TCP, the rest of the modified IP header, and for +COMPRESSED_TCP, the compressed TCP/IP datagram header; +.Ed +.Pp +for a total of 16 bytes; the uncompressed IP datagram follows the header. +.Pp +.It Dv DLT_PPP +PPP; if the first 2 bytes are 0xff and 0x03, it's PPP in HDLC-like +framing, with the PPP header following those two bytes, otherwise it's +PPP without framing, and the packet begins with the PPP header. +.Pp +.It Dv DLT_FDDI +FDDI +.Pp +.It Dv DLT_ATM_RFC1483 +RFC 1483 LLC/SNAP-encapsulated ATM; the packet begins with an IEEE 802.2 +LLC header. +.Pp +.It Dv DLT_RAW +raw IP; the packet begins with an IP header. +.Pp +.It Dv DLT_PPP_SERIAL +PPP in HDLC-like framing, as per RFC 1662, or Cisco PPP with HDLC +framing, as per section 4.3.1 of RFC 1547; the first byte will be 0xFF +for PPP in HDLC-like framing, and will be 0x0F or 0x8F for Cisco PPP +with HDLC framing. +.Pp +.It Dv DLT_PPP_ETHER +PPPoE; the packet begins with a PPPoE header, as per RFC 2516. +.Pp +.It Dv DLT_C_HDLC +Cisco PPP with HDLC framing, as per section 4.3.1 of RFC 1547. +.Pp +.It Dv DLT_IEEE802_11 +IEEE 802.11 wireless LAN +.Pp +.It Dv DLT_FRELAY +Frame Relay +.Pp +.It Dv DLT_LOOP +OpenBSD loopback encapsulation; the link layer header is a 4-byte field, in +.Em network +byte order, containing a PF_ value from OpenBSD's +.In sys/socket.h +for the network-layer protocol of the packet. +.Pp +Note that, if a +.Dq savefile +is being read, those PF_ values are +.Em not +necessarily those of the machine reading the capture file. +.Pp +.It Dv DLT_LINUX_SLL +Linux "cooked" capture encapsulation; the link layer header contains, in +order: +.Bd -ragged -offset indent -compact +.Pp +a 2-byte "packet type", in network byte order, which is one of: +.Bl -tag -width "10" -compact -offset indent +.Pp +.It Li 0 +packet was sent to us by somebody else +.It Li 1 +packet was broadcast by somebody else +.It Li 2 +packet was multicast, but not broadcast, by somebody else +.It Li 3 +packet was sent by somebody else to somebody else +.It Li 4 +packet was sent by us +.El +.Pp +a 2-byte field, in network byte order, containing a Linux ARPHRD_ value +for the link layer device type; +.Pp +a 2-byte field, in network byte order, containing the length of the +link layer address of the sender of the packet (which could be 0); +.Pp +an 8-byte field containing that number of bytes of the link layer header +(if there are more than 8 bytes, only the first 8 are present); +.Pp +a 2-byte field containing an Ethernet protocol type, in network byte +order, or containing 1 for Novell 802.3 frames without an 802.2 LLC +header or 4 for frames beginning with an 802.2 LLC header. +.Ed +.Pp +.It Dv DLT_LTALK +Apple LocalTalk; the packet begins with an AppleTalk LLAP header. +.Pp +.It Dv DLT_PFLOG +OpenBSD pflog; the link layer header contains, in order: +.Bd -ragged -offset indent -compact +.Pp +a 1-byte header length, in host byte order; +.Pp +a 4-byte PF_ value, in host byte order; +.Pp +a 2-byte action code, in network byte order, which is one of: +.Bl -tag -width "10" -compact -offset indent +.Pp +.It Li 0 +passed +.It Li 1 +dropped +.It Li 2 +scrubbed +.El +.Pp +a 2-byte reason code, in network byte order, which is one of: +.Bl -tag -width "10" -compact -offset indent +.Pp +.It Li 0 +match +.It Li 1 +bad offset +.It Li 2 +fragment +.It Li 3 +short +.It Li 4 +normalize +.It Li 5 +memory +.El +.Pp +a 16-character interface name; +.Pp +a 16-character ruleset name (only meaningful if subrule is set); +.Pp +a 4-byte rule number, in network byte order; +.Pp +a 4-byte subrule number, in network byte order; +.Pp +a 1-byte direction, in network byte order, which is one of: +.Bl -tag -width "10" -compact -offset indent +.Pp +.It Li 0 +incoming or outgoing +.It Li 1 +incoming +.It Li 2 +outgoing +.El +.Ed +.Pp +.It Dv DLT_PRISM_HEADER +Prism monitor mode information followed by an 802.11 header. +.Pp +.It Dv DLT_IP_OVER_FC +RFC 2625 IP-over-Fibre Channel, with the link-layer header being the +Network_Header as described in that RFC. +.Pp +.It Dv DLT_SUNATM +SunATM devices; the link layer header contains, in order: +.Bd -ragged -offset indent -compact +.Pp +a 1-byte flag field, containing a direction flag in the uppermost bit, +which is set for packets transmitted by the machine and clear for +packets received by the machine, and a 4-byte traffic type in the +low-order 4 bits, which is one of: +.Bl -tag -width "10" -offset indent +.It Li 0 +raw traffic +.It Li 1 +LANE traffic +.It Li 2 +LLC-encapsulated traffic +.It Li 3 +MARS traffic +.It Li 4 +IFMP traffic +.It Li 5 +ILMI traffic +.It Li 6 +Q.2931 traffic +.El +.Pp +a 1-byte VPI value; +.Pp +a 2-byte VCI field, in network byte order. +.Ed +.Pp +.It Dv DLT_IEEE802_11_RADIO +.Xr radiotap 9 +information followed by an 802.11 header. +.Pp +.It Dv DLT_ARCNET_LINUX +ARCNET, with no exception frames, reassembled packets rather than raw +frames, and an extra 16-bit offset field between the destination host +and type bytes. +.Pp +.It Dv DLT_LINUX_IRDA +Linux-IrDA packets, with a +.Dv DLT_LINUX_SLL +header followed by the IrLAP header. +.El +.Pp +.Fn pcap_list_datalinks +is used to get a list of the supported data link types of the interface +associated with the pcap descriptor. +.Fn pcap_list_datalinks +allocates an array to hold the list and sets +.Fa *dlt_buf . +The caller is responsible for freeing the array. +.Li \-1 +is returned on failure; +otherwise, the number of data link types in the array is returned. +.Pp .Fn pcap_set_datalink is used to set the current data link type of the pcap descriptor to the type specified by .Fa dlt . This operation is supported only of the interface associated with the pcap descriptor supports multiple data link types. -.Em \-1 -is return on failure; +.Li \-1 +is returned on failure; .Em 0 is returned on success. .Pp -.Fn pcap_list_datalinks -is used to get a list of the support data link types of the interface -associated with the pcap descriptor. -.Fn pcap_list_datalinks -allocates an array to hold the list and sets -.Fa *dlt_buf . -The caller is responsible for freeing the array. -.Em \-1 -is returned on failure; -otherwise, the number of data link types in the array is returned. -.Pp .Fn pcap_loop is similar to .Fn pcap_dispatch @@ -305,12 +1054,31 @@ to loop forever (or at least until an error occurs). .Pp .Fn pcap_next returns a -.Fa u_char +.Vt u_char pointer to the next packet. .Pp -.Fn pcap_datalink -returns the link layer type, e.g. -.Em DLT_EN10MB . +.Pp +.Fn pcap_datalink_name_to_val +translates a data link type name, which is a +.Dv DLT_ +name with the +.Dv DLT_ +removed, to the corresponding data link type value. The translation +is case-insensitive. +.Li \-1 +is returned on failure. +.Pp +.Fn pcap_datalink_val_to_name +translates a data link type value to the corresponding data link type +name. +.Dv NULL +is returned on failure. +.Pp +.Fn pcap_datalink_val_to_description +translates a data link type value to a short description of that data +link type. +.Dv NULL +is returned on failure. .Pp .Fn pcap_snapshot returns the snapshot length specified when @@ -323,12 +1091,10 @@ returns true if the current uses a different byte order than the current system. .Pp .Fn pcap_major_version -returns the major number of the version of the pcap used to write the -savefile. -.Pp +returns the major number of the file format of the savefile; .Fn pcap_minor_version -returns the minor number of the version of the pcap used to write the -savefile. +returns the minor number of the file format of the savefile. The +version number is stored in the header of the savefile. .Pp .Fn pcap_file returns the standard I/O stream of the @@ -342,16 +1108,23 @@ or NULL, if a network device was opened with .Pp .Fn pcap_stats returns 0 and fills in a -.Fa pcap_stat +.Vt pcap_stat struct. The values represent packet statistics from the start of the -run to the time of the call. -If there is an error or the under lying +run to the time of the call. If there is an error or the underlying packet capture doesn't support packet statistics, -1 is returned and the error text can be obtained with .Fn pcap_perror or .Fn pcap_geterr . +.Fn pcap_stats +is supported only on live captures, not on +.Dq savefiles ; +no statistics are stored in +.Dq savefiles , +so no statistics are available when reading +from a +.Dq savefile . .Pp .Fn pcap_fileno returns the file descriptor number from which captured packets are read @@ -361,26 +1134,115 @@ or \-1, if a .Dq savefile was opened with .Fn pcap_open_offline . +.Fn pcap_get_selectable_fd +returns, on UNIX, a file descriptor number for a file descriptor on +which one can +do a +.Fn select +or +.Fn poll +to wait for it to be possible to read packets without blocking, if such +a descriptor exists, or \-1, if no such descriptor exists. Some network +devices opened with +.Fn pcap_open_live +do not support +.Fn select +or +.Fn poll +(for example, regular network devices on FreeBSD 4.3 and 4.4, and Endace +DAG devices), so \-1 is returned for those devices. +.Pp +Note that on most versions of most BSDs (including Mac OS X) +.Fn select +and +.Fn poll +do not work correctly on BPF devices; +.Fn pcap_get_selectable_fd +will return a file descriptor on most of those versions (the exceptions +being FreeBSD 4.3 and 4.4), a simple +.Fn select +or +.Fn poll +will not return even after a timeout specified in +.Fn pcap_open_live +expires. To work around this, an application that uses +.Fn select +or +.Fn poll +to wait for packets to arrive must put the +.Vt pcap_t +in non-blocking mode, and must arrange that the +.Fn select +or +.Fn poll +have a timeout less than or equal to the timeout specified in +.Fn pcap_open_live , +and must try to read packets after that timeout expires, regardless of +whether +.Fn select +or +.Fn poll +indicated that the file descriptor for the +.Vt pcap_t +is ready to be read or not. +(That workaround will not work in FreeBSD 4.3 and later; however, +in FreeBSD 4.6 and later, +.Fn select +and +.Fn poll +work correctly on BPF devices, so the workaround isn't necessary, +although it does no harm.) +.Pp +.Fn pcap_get_selectable_fd +is not available on Windows. .Pp .Fn pcap_perror prints the text of the last pcap library error on -.Em stderr , +.Va stderr , prefixed by -.Em prefix . +.Va prefix . .Pp .Fn pcap_geterr returns the error text pertaining to the last pcap library error. +.Em NOTE : +the pointer it returns will no longer point to a valid error message +string after the +.Vt pcap_t +passed to it is closed; you must use or copy the string before closing +the +.Vt pcap_t . .Pp .Fn pcap_strerror is provided in case .Xr strerror 3 isn't available. .Pp +.Fn pcap_lib_version +returns a pointer to a string giving information about the version of +the libpcap library being used; note that it contains more information +than just a version number. +.Pp .Fn pcap_close closes the files associated with .Fa p and deallocates resources. .Pp +.Fn pcap_dump_file +returns the standard I/O stream of the +.Dq savefile +opened by +.Fn pcap_dump_open . +.Pp +.Fn pcap_dump_flush +flushes the output buffer to the +.Dq savefile , +so that any packets written with +.Fn pcap_dump +but not yet written to the +.Dq savefile +will be written. +-1 is returned on error, 0 on success. +.Pp .Fn pcap_dump_close closes the .Dq savefile . diff --git a/lib/libpcap/pcap.c b/lib/libpcap/pcap.c index 8ea87bc653c3..1f2d8250d271 100644 --- a/lib/libpcap/pcap.c +++ b/lib/libpcap/pcap.c @@ -1,7 +1,7 @@ -/* $NetBSD: pcap.c,v 1.9 2002/09/22 16:13:01 thorpej Exp $ */ +/* $NetBSD: pcap.c,v 1.10 2004/09/27 23:02:53 dyoung Exp $ */ /* - * Copyright (c) 1993, 1994, 1995, 1996 + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,51 +37,77 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: pcap.c,v 1.27 96/11/27 18:43:25 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/pcap.c,v 1.63.2.9 2004/03/25 22:40:52 guy Exp (LBL)"; #else -__RCSID("$NetBSD: pcap.c,v 1.9 2002/09/22 16:13:01 thorpej Exp $"); +__RCSID("$NetBSD: pcap.c,v 1.10 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include +#else /* WIN32 */ #include +#endif /* WIN32 */ #include #include #include +#ifndef _MSC_VER #include +#endif +#include #include -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #include "pcap-int.h" +#ifdef HAVE_DAG_API +#include +#include +#endif + int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - if (p->sf.rfile != NULL) - return (pcap_offline_read(p, cnt, callback, user)); - return (pcap_read(p, cnt, callback, user)); + return p->read_op(p, cnt, callback, user); +} + +/* + * XXX - is this necessary? + */ +int +pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + + return p->read_op(p, cnt, callback, user); } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - int n; + register int n; for (;;) { - if (p->sf.rfile != NULL) + if (p->sf.rfile != NULL) { + /* + * 0 means EOF, so don't loop if we get 0. + */ n = pcap_offline_read(p, cnt, callback, user); - else { + } else { /* * XXX keep reading until we get something * (or an error occurs) */ do { - n = pcap_read(p, cnt, callback, user); + n = p->read_op(p, cnt, callback, user); } while (n == 0); } if (n <= 0) @@ -119,6 +145,79 @@ pcap_next(pcap_t *p, struct pcap_pkthdr *h) return (s.pkt); } +struct pkt_for_fakecallback { + struct pcap_pkthdr *hdr; + const u_char **pkt; +}; + +static void +pcap_fakecallback(u_char *userData, const struct pcap_pkthdr *h, + const u_char *pkt) +{ + struct pkt_for_fakecallback *sp = (struct pkt_for_fakecallback *)userData; + + *sp->hdr = *h; + *sp->pkt = pkt; +} + +int +pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, + const u_char **pkt_data) +{ + struct pkt_for_fakecallback s; + + s.hdr = &p->pcap_header; + s.pkt = pkt_data; + + /* Saves a pointer to the packet headers */ + *pkt_header= &p->pcap_header; + + if (p->sf.rfile != NULL) { + int status; + + /* We are on an offline capture */ + status = pcap_offline_read(p, 1, pcap_fakecallback, + (u_char *)&s); + + /* + * Return codes for pcap_offline_read() are: + * - 0: EOF + * - -1: error + * - >1: OK + * The first one ('0') conflicts with the return code of + * 0 from pcap_read() meaning "no packets arrived before + * the timeout expired", so we map it to -2 so you can + * distinguish between an EOF from a savefile and a + * "no packets arrived before the timeout expired, try + * again" from a live capture. + */ + if (status == 0) + return (-2); + else + return (status); + } + + /* + * Return codes for pcap_read() are: + * - 0: timeout + * - -1: error + * - -2: loop was broken out of with pcap_breakloop() + * - >1: OK + * The first one ('0') conflicts with the return code of 0 from + * pcap_offline_read() meaning "end of file". + */ + return (p->read_op(p, 1, pcap_fakecallback, (u_char *)&s)); +} + +/* + * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. + */ +void +pcap_breakloop(pcap_t *p) +{ + p->break_loop = 1; +} + int pcap_datalink(pcap_t *p) { @@ -128,19 +227,243 @@ pcap_datalink(pcap_t *p) int pcap_list_datalinks(pcap_t *p, int **dlt_buffer) { - if (p->dlt_count <= 0) { - *dlt_buffer = NULL; - return -1; + if (p->dlt_count == 0) { + /* + * We couldn't fetch the list of DLTs, which means + * this platform doesn't support changing the + * DLT for an interface. Return a list of DLTs + * containing only the DLT this device supports. + */ + *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); + if (*dlt_buffer == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + **dlt_buffer = p->linktype; + return (1); + } else { + *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer) * p->dlt_count); + if (*dlt_buffer == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + (void)memcpy(*dlt_buffer, p->dlt_list, + sizeof(**dlt_buffer) * p->dlt_count); + return (p->dlt_count); } - *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer) * p->dlt_count); - if (*dlt_buffer == NULL) { - (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", - pcap_strerror(errno)); - return -1; +} + +int +pcap_set_datalink(pcap_t *p, int dlt) +{ + int i; + const char *dlt_name; + + if (p->dlt_count == 0 || p->set_datalink_op == NULL) { + /* + * We couldn't fetch the list of DLTs, or we don't + * have a "set datalink" operation, which means + * this platform doesn't support changing the + * DLT for an interface. Check whether the new + * DLT is the one this interface supports. + */ + if (p->linktype != dlt) + goto unsupported; + + /* + * It is, so there's nothing we need to do here. + */ + return (0); } - (void)memcpy(*dlt_buffer, p->dlt_list, - sizeof(**dlt_buffer) * p->dlt_count); - return (p->dlt_count); + for (i = 0; i < p->dlt_count; i++) + if (p->dlt_list[i] == dlt) + break; + if (i >= p->dlt_count) + goto unsupported; + if (p->set_datalink_op(p, dlt) == -1) + return (-1); + p->linktype = dlt; + return (0); + +unsupported: + dlt_name = pcap_datalink_val_to_name(dlt); + if (dlt_name != NULL) { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "%s is not one of the DLTs supported by this device", + dlt_name); + } else { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "DLT %d is not one of the DLTs supported by this device", + dlt); + } + return (-1); +} + +struct dlt_choice { + const char *name; + const char *description; + int dlt; +}; + +#define DLT_CHOICE(code, description) { #code, description, code } +#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 } + +static struct dlt_choice dlt_choices[] = { + DLT_CHOICE(DLT_NULL, "BSD loopback"), + DLT_CHOICE(DLT_EN10MB, "Ethernet"), + DLT_CHOICE(DLT_IEEE802, "Token ring"), + DLT_CHOICE(DLT_ARCNET, "ARCNET"), + DLT_CHOICE(DLT_SLIP, "SLIP"), + DLT_CHOICE(DLT_PPP, "PPP"), + DLT_CHOICE(DLT_FDDI, "FDDI"), + DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 IP-over-ATM"), + DLT_CHOICE(DLT_RAW, "Raw IP"), + DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"), + DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"), + DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"), + DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"), + DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"), + DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"), + DLT_CHOICE(DLT_IEEE802_11, "802.11"), + DLT_CHOICE(DLT_FRELAY, "Frame Relay"), + DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"), + DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"), + DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"), + DLT_CHOICE(DLT_LTALK, "Localtalk"), + DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"), + DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"), + DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), + DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"), + DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus BSD radio information header"), + DLT_CHOICE(DLT_APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), + DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"), + DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"), + DLT_CHOICE(DLT_IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), + DLT_CHOICE_SENTINEL +}; + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const u_char charmap[] = { + (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003', + (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007', + (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013', + (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017', + (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023', + (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027', + (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033', + (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037', + (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043', + (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047', + (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053', + (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057', + (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063', + (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067', + (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073', + (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077', + (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143', + (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', + (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', + (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', + (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', + (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', + (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133', + (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137', + (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143', + (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', + (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', + (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', + (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', + (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', + (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173', + (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177', + (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203', + (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207', + (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213', + (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217', + (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223', + (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227', + (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233', + (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237', + (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243', + (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247', + (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253', + (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257', + (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263', + (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267', + (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273', + (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277', + (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343', + (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', + (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', + (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', + (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', + (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', + (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333', + (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337', + (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343', + (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', + (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', + (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', + (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', + (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', + (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373', + (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377', +}; + +int +pcap_strcasecmp(const char *s1, const char *s2) +{ + register const u_char *cm = charmap, + *us1 = (u_char *)s1, + *us2 = (u_char *)s2; + + while (cm[*us1] == cm[*us2++]) + if (*us1++ == '\0') + return(0); + return (cm[*us1] - cm[*--us2]); +} + +int +pcap_datalink_name_to_val(const char *name) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (pcap_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1, + name) == 0) + return (dlt_choices[i].dlt); + } + return (-1); +} + +const char * +pcap_datalink_val_to_name(int dlt) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (dlt_choices[i].dlt == dlt) + return (dlt_choices[i].name + sizeof("DLT_") - 1); + } + return (NULL); +} + +const char * +pcap_datalink_val_to_description(int dlt) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (dlt_choices[i].dlt == dlt) + return (dlt_choices[i].description); + } + return (NULL); } int @@ -176,9 +499,24 @@ pcap_file(pcap_t *p) int pcap_fileno(pcap_t *p) { +#ifndef WIN32 return (p->fd); +#else + if (p->adapter != NULL) + return ((int)(DWORD)p->adapter->hFile); + else + return (-1); +#endif } +#ifndef WIN32 +int +pcap_get_selectable_fd(pcap_t *p) +{ + return (p->selectable_fd); +} +#endif + void pcap_perror(pcap_t *p, char *prefix) { @@ -191,6 +529,105 @@ pcap_geterr(pcap_t *p) return (p->errbuf); } +int +pcap_getnonblock(pcap_t *p, char *errbuf) +{ + return p->getnonblock_op(p, errbuf); +} + +/* + * Get the current non-blocking mode setting, under the assumption that + * it's just the standard POSIX non-blocking flag. + * + * We don't look at "p->nonblock", in case somebody tweaked the FD + * directly. + */ +#ifndef WIN32 +int +pcap_getnonblock_fd(pcap_t *p, char *errbuf) +{ + int fdflags; + + fdflags = fcntl(p->fd, F_GETFL, 0); + if (fdflags == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", + pcap_strerror(errno)); + return (-1); + } + if (fdflags & O_NONBLOCK) + return (1); + else + return (0); +} +#endif + +int +pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + return p->setnonblock_op(p, nonblock, errbuf); +} + +#ifndef WIN32 +/* + * Set non-blocking mode, under the assumption that it's just the + * standard POSIX non-blocking flag. (This can be called by the + * per-platform non-blocking-mode routine if that routine also + * needs to do some additional work.) + */ +int +pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf) +{ + int fdflags; + + fdflags = fcntl(p->fd, F_GETFL, 0); + if (fdflags == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s", + pcap_strerror(errno)); + return (-1); + } + if (nonblock) + fdflags |= O_NONBLOCK; + else + fdflags &= ~O_NONBLOCK; + if (fcntl(p->fd, F_SETFL, fdflags) == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s", + pcap_strerror(errno)); + return (-1); + } + return (0); +} +#endif + +#ifdef WIN32 +/* + * Generate a string for the last Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +char * +pcap_win32strerror(void) +{ + DWORD error; + static char errbuf[PCAP_ERRBUF_SIZE+1]; + int errlen; + + error = GetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + PCAP_ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + } + return (errbuf); +} +#endif + /* * Not all systems have strerror(). */ @@ -211,24 +648,132 @@ pcap_strerror(int errnum) #endif } +int +pcap_setfilter(pcap_t *p, struct bpf_program *fp) +{ + return p->setfilter_op(p, fp); +} + +int +pcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + return p->stats_op(p, ps); +} + +static int +pcap_stats_dead(pcap_t *p, struct pcap_stat *ps) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from a pcap_open_dead pcap_t"); + return (-1); +} + +static void +pcap_close_dead(pcap_t *p) +{ + /* Nothing to do. */ +} + +pcap_t * +pcap_open_dead(int linktype, int snaplen) +{ + pcap_t *p; + + p = malloc(sizeof(*p)); + if (p == NULL) + return NULL; + memset (p, 0, sizeof(*p)); + p->snapshot = snaplen; + p->linktype = linktype; + p->stats_op = pcap_stats_dead; + p->close_op = pcap_close_dead; + return p; +} + void pcap_close(pcap_t *p) { - /*XXX*/ - if (p->fd >= 0) - close(p->fd); - if (p->sf.rfile != NULL) { - (void)fclose(p->sf.rfile); - if (p->sf.base != NULL) - free(p->sf.base); - } else if (p->buffer != NULL) - free(p->buffer); -#ifdef linux - if (p->md.device != NULL) - free(p->md.device); -#endif + p->close_op(p); if (p->dlt_list != NULL) free(p->dlt_list); - + pcap_freecode(&p->fcode); free(p); } + +/* + * We make the version string static, and return a pointer to it, rather + * than exporting the version string directly. On at least some UNIXes, + * if you import data from a shared library into an program, the data is + * bound into the program binary, so if the string in the version of the + * library with which the program was linked isn't the same as the + * string in the version of the library with which the program is being + * run, various undesirable things may happen (warnings, the string + * being the one from the version of the library with which the program + * was linked, or even weirder things, such as the string being the one + * from the library but being truncated). + */ +#ifdef WIN32 +/* + * XXX - it'd be nice if we could somehow generate the WinPcap and libpcap + * version numbers when building WinPcap. (It'd be nice to do so for + * the packet.dll version number as well.) + */ +static const char wpcap_version_string[] = "3.0"; +static const char pcap_version_string_fmt[] = + "WinPcap version %s, based on libpcap version 0.8"; +static const char pcap_version_string_packet_dll_fmt[] = + "WinPcap version %s (packet.dll version %s), based on libpcap version 0.8"; +static char *pcap_version_string; + +const char * +pcap_lib_version(void) +{ + char *packet_version_string; + size_t pcap_version_string_len; + + if (pcap_version_string == NULL) { + /* + * Generate the version string. + */ + packet_version_string = PacketGetVersion(); + if (strcmp(wpcap_version_string, packet_version_string) == 0) { + /* + * WinPcap version string and packet.dll version + * string are the same; just report the WinPcap + * version. + */ + pcap_version_string_len = + (sizeof pcap_version_string_fmt - 2) + + strlen(wpcap_version_string); + pcap_version_string = malloc(pcap_version_string_len); + sprintf(pcap_version_string, pcap_version_string_fmt, + wpcap_version_string); + } else { + /* + * WinPcap version string and packet.dll version + * string are different; that shouldn't be the + * case (the two libraries should come from the + * same version of WinPcap), so we report both + * versions. + */ + pcap_version_string_len = + (sizeof pcap_version_string_packet_dll_fmt - 4) + + strlen(wpcap_version_string) + + strlen(packet_version_string); + pcap_version_string = malloc(pcap_version_string_len); + sprintf(pcap_version_string, + pcap_version_string_packet_dll_fmt, + wpcap_version_string, packet_version_string); + } + } + return (pcap_version_string); +} +#else +#include "version.h" + +const char * +pcap_lib_version(void) +{ + return (pcap_version_string); +} +#endif diff --git a/lib/libpcap/pcap.h b/lib/libpcap/pcap.h index 3a3a6736e365..bd5e25965d25 100644 --- a/lib/libpcap/pcap.h +++ b/lib/libpcap/pcap.h @@ -1,7 +1,8 @@ -/* $NetBSD: pcap.h,v 1.10 2002/09/22 16:13:01 thorpej Exp $ */ +/* $NetBSD: pcap.h,v 1.11 2004/09/27 23:02:53 dyoung Exp $ */ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ /* - * Copyright (c) 1993, 1994, 1995, 1996 + * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,19 +33,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) Header: pcap.h,v 1.20 96/07/12 19:24:15 leres Exp (LBL) + * @(#) Header: /tcpdump/master/libpcap/pcap.h,v 1.45.2.4 2004/01/27 22:56:20 guy Exp (LBL) */ #ifndef lib_pcap_h #define lib_pcap_h +#ifdef WIN32 +#include +#else /* WIN32 */ #include #include +#endif /* WIN32 */ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 @@ -61,12 +70,42 @@ typedef u_int32_t bpf_u_int32; typedef struct pcap pcap_t; typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; /* * The first record in the file contains saved values for some * of the flags used in the printout phases of tcpdump. * Many fields here are 32 bit ints so compilers won't insert unwanted * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@tcpdump.org", requesting a new + * magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes to "patches@tcpdump.org", so that future + * versions of libpcap and programs that use it (such as tcpdump) will + * be able to read your new capture file format. */ struct pcap_file_header { bpf_u_int32 magic; @@ -75,7 +114,7 @@ struct pcap_file_header { bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ - bpf_u_int32 linktype; /* data link type (DLT_*) */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ }; /* @@ -96,35 +135,69 @@ struct pcap_stat { u_int ps_recv; /* number of packets received */ u_int ps_drop; /* number of packets dropped */ u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef WIN32 + u_int bs_capt; /* number of packets that reach the application */ +#endif /* WIN32 */ +}; + +/* + * 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 */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ }; typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *); char *pcap_lookupdev(char *); -int pcap_lookupnet(char *, bpf_u_int32 *, bpf_u_int32 *, char *); -pcap_t *pcap_open_live(char *, int, int, int, char *); -pcap_t *pcap_open_offline(char *, char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); void pcap_close(pcap_t *); int pcap_loop(pcap_t *, int, pcap_handler, u_char *); int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); const u_char* pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); int pcap_stats(pcap_t *, struct pcap_stat *); int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); void pcap_perror(pcap_t *, char *); const char* pcap_strerror(int); char *pcap_geterr(pcap_t *); int pcap_compile(pcap_t *, struct bpf_program *, char *, int, bpf_u_int32); -int pcap_compile_nopcap(int, int, struct bpf_program *, char *, - int, bpf_u_int32, char *); -/* XXX */ -int pcap_freecode(pcap_t *, struct bpf_program *); +int pcap_compile_nopcap(int, int, struct bpf_program *, + char *, int, bpf_u_int32, char *errbuf); +void pcap_freecode(struct bpf_program *); int pcap_datalink(pcap_t *); int pcap_list_datalinks(pcap_t *, int **); int pcap_set_datalink(pcap_t *, int); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); int pcap_snapshot(pcap_t *); int pcap_is_swapped(pcap_t *); int pcap_major_version(pcap_t *); @@ -134,13 +207,55 @@ int pcap_minor_version(pcap_t *); FILE *pcap_file(pcap_t *); int pcap_fileno(pcap_t *); -pcap_dumper_t *pcap_dump_open(pcap_t *, char *); +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +int pcap_dump_flush(pcap_dumper_t *); void pcap_dump_close(pcap_dumper_t *); void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); +FILE *pcap_dump_file(pcap_dumper_t *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); #ifdef notdef /* XXX this guy lives in the bpf tree */ u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); #endif +int bpf_validate(struct bpf_insn *f, int len); char *bpf_image(struct bpf_insn *, int); +void bpf_dump(struct bpf_program *, int); + +#ifdef WIN32 +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_sendpacket(pcap_t *p, u_char *buf, int size); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#else +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32 */ + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/libpcap/ppp.h b/lib/libpcap/ppp.h index a7020c61140b..ac7d573c299f 100644 --- a/lib/libpcap/ppp.h +++ b/lib/libpcap/ppp.h @@ -1,6 +1,6 @@ -/* $NetBSD: ppp.h,v 1.2 1999/07/25 00:15:22 itojun Exp $ */ +/* $NetBSD: ppp.h,v 1.3 2004/09/27 23:02:53 dyoung Exp $ */ -/* @(#) Header: ppp.h,v 1.7 95/05/04 17:52:46 mccanne Exp (LBL) */ +/* @(#) Header: /tcpdump/master/libpcap/ppp.h,v 1.8 1999/10/19 15:18:31 itojun Exp (LBL) */ /* * Point to Point Protocol (PPP) RFC1331 * @@ -32,7 +32,7 @@ #define PPP_BRPDU 0x0031 /* Bridging PDU */ #define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ #define PPP_VINES 0x0035 /* Banyan Vines */ -#define PPP_IPV6 0x0057 /* Internet Protocol Version 6 */ +#define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ #define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ #define PPP_LUXCOM 0x0231 /* Luxcom */ diff --git a/lib/libpcap/savefile.c b/lib/libpcap/savefile.c index c4e61d04fffe..15bbff5ec84b 100644 --- a/lib/libpcap/savefile.c +++ b/lib/libpcap/savefile.c @@ -1,7 +1,7 @@ -/* $NetBSD: savefile.c,v 1.7 2001/02/07 17:35:56 itojun Exp $ */ +/* $NetBSD: savefile.c,v 1.8 2004/09/27 23:02:53 dyoung Exp $ */ /* - * Copyright (c) 1993, 1994, 1995, 1996 + * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,36 +34,40 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: savefile.c,v 1.36 96/12/10 23:15:02 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/savefile.c,v 1.92.2.11 2004/03/11 23:46:14 guy Exp (LBL)"; #else -__RCSID("$NetBSD: savefile.c,v 1.7 2001/02/07 17:35:56 itojun Exp $"); +__RCSID("$NetBSD: savefile.c,v 1.8 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif -#include -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include #include #include -#include +#include #include "pcap-int.h" -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif #define TCPDUMP_MAGIC 0xa1b2c3d4 +#define PATCHED_TCPDUMP_MAGIC 0xa1b2cd34 /* * We use the "receiver-makes-right" approach to byte order, * because time is at a premium when we are writing the file. * In other words, the pcap_file_header and pcap_pkthdr, * records are written in host byte order. - * Note that the packets are always written in network byte order. + * Note that the bytes of packet data are written out in the order in + * which they were received, so multi-byte fields in packets are not + * written in host byte order, they're written in whatever order the + * sending machine put them in. * * ntoh[ls] aren't sufficient because we might need to swap on a big-endian * machine (if the file was written in little-end order). @@ -78,6 +82,456 @@ __RCSID("$NetBSD: savefile.c,v 1.7 2001/02/07 17:35:56 itojun Exp $"); #define SFERR_BADF 3 #define SFERR_EOF 4 /* not really an error, just a status */ +/* + * We don't write DLT_* values to the capture file header, because + * they're not the same on all platforms. + * + * Unfortunately, the various flavors of BSD have not always used the same + * numerical values for the same data types, and various patches to + * libpcap for non-BSD OSes have added their own DLT_* codes for link + * layer encapsulation types seen on those OSes, and those codes have had, + * in some cases, values that were also used, on other platforms, for other + * link layer encapsulation types. + * + * This means that capture files of a type whose numerical DLT_* code + * means different things on different BSDs, or with different versions + * of libpcap, can't always be read on systems other than those like + * the one running on the machine on which the capture was made. + * + * Instead, we define here a set of LINKTYPE_* codes, and map DLT_* codes + * to LINKTYPE_* codes when writing a savefile header, and map LINKTYPE_* + * codes to DLT_* codes when reading a savefile header. + * + * For those DLT_* codes that have, as far as we know, the same values on + * all platforms (DLT_NULL through DLT_FDDI), we define LINKTYPE_xxx as + * DLT_xxx; that way, captures of those types can still be read by + * versions of libpcap that map LINKTYPE_* values to DLT_* values, and + * captures of those types written by versions of libpcap that map DLT_ + * values to LINKTYPE_ values can still be read by older versions + * of libpcap. + * + * The other LINKTYPE_* codes are given values starting at 100, in the + * hopes that no DLT_* code will be given one of those values. + * + * In order to ensure that a given LINKTYPE_* code's value will refer to + * the same encapsulation type on all platforms, you should not allocate + * a new LINKTYPE_* value without consulting "tcpdump-workers@tcpdump.org". + * The tcpdump developers will allocate a value for you, and will not + * subsequently allocate it to anybody else; that value will be added to + * the "pcap.h" in the tcpdump.org CVS repository, so that a future + * libpcap release will include it. + * + * You should, if possible, also contribute patches to libpcap and tcpdump + * to handle the new encapsulation type, so that they can also be checked + * into the tcpdump.org CVS repository and so that they will appear in + * future libpcap and tcpdump releases. + * + * Do *NOT* assume that any values after the largest value in this file + * are available; you might not have the most up-to-date version of this + * file, and new values after that one might have been assigned. Also, + * do *NOT* use any values below 100 - those might already have been + * taken by one (or more!) organizations. + */ +#define LINKTYPE_NULL DLT_NULL +#define LINKTYPE_ETHERNET DLT_EN10MB /* also for 100Mb and up */ +#define LINKTYPE_EXP_ETHERNET DLT_EN3MB /* 3Mb experimental Ethernet */ +#define LINKTYPE_AX25 DLT_AX25 +#define LINKTYPE_PRONET DLT_PRONET +#define LINKTYPE_CHAOS DLT_CHAOS +#define LINKTYPE_TOKEN_RING DLT_IEEE802 /* DLT_IEEE802 is used for Token Ring */ +#define LINKTYPE_ARCNET DLT_ARCNET /* BSD-style headers */ +#define LINKTYPE_SLIP DLT_SLIP +#define LINKTYPE_PPP DLT_PPP +#define LINKTYPE_FDDI DLT_FDDI + +/* + * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662 + * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol + * field) at the beginning of the packet. + * + * This is for use when there is always such a header; the address field + * might be 0xff, for regular PPP, or it might be an address field for Cisco + * point-to-point with HDLC framing as per section 4.3.1 of RFC 1547 ("Cisco + * HDLC"). This is, for example, what you get with NetBSD's DLT_PPP_SERIAL. + * + * We give it the same value as NetBSD's DLT_PPP_SERIAL, in the hopes that + * nobody else will choose a DLT_ value of 50, and so that DLT_PPP_SERIAL + * captures will be written out with a link type that NetBSD's tcpdump + * can read. + */ +#define LINKTYPE_PPP_HDLC 50 /* PPP in HDLC-like framing */ + +#define LINKTYPE_PPP_ETHER 51 /* NetBSD PPP-over-Ethernet */ + +/* + * This isn't supported in libpcap 0.8[.x], but is supported in the + * current CVS version; we include it here to note that it's not available + * for anybody else to use. + */ +#define LINKTYPE_SYMANTEC_FIREWALL 99 /* Symantec Enterprise Firewall */ + +#define LINKTYPE_ATM_RFC1483 100 /* LLC/SNAP-encapsulated ATM */ +#define LINKTYPE_RAW 101 /* raw IP */ +#define LINKTYPE_SLIP_BSDOS 102 /* BSD/OS SLIP BPF header */ +#define LINKTYPE_PPP_BSDOS 103 /* BSD/OS PPP BPF header */ +#define LINKTYPE_C_HDLC 104 /* Cisco HDLC */ +#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */ +#define LINKTYPE_ATM_CLIP 106 /* Linux Classical IP over ATM */ +#define LINKTYPE_FRELAY 107 /* Frame Relay */ +#define LINKTYPE_LOOP 108 /* OpenBSD loopback */ +#define LINKTYPE_ENC 109 /* OpenBSD IPSEC enc */ + +/* + * These three types are reserved for future use. + */ +#define LINKTYPE_LANE8023 110 /* ATM LANE + 802.3 */ +#define LINKTYPE_HIPPI 111 /* NetBSD HIPPI */ +#define LINKTYPE_HDLC 112 /* NetBSD HDLC framing */ + +#define LINKTYPE_LINUX_SLL 113 /* Linux cooked socket capture */ +#define LINKTYPE_LTALK 114 /* Apple LocalTalk hardware */ +#define LINKTYPE_ECONET 115 /* Acorn Econet */ + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define LINKTYPE_IPFILTER 116 + +#define LINKTYPE_PFLOG 117 /* OpenBSD DLT_PFLOG */ +#define LINKTYPE_CISCO_IOS 118 /* For Cisco-internal use */ +#define LINKTYPE_PRISM_HEADER 119 /* 802.11+Prism II monitor mode */ +#define LINKTYPE_AIRONET_HEADER 120 /* FreeBSD Aironet driver stuff */ + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define LINKTYPE_HHDLC 121 + +#define LINKTYPE_IP_OVER_FC 122 /* RFC 2625 IP-over-Fibre Channel */ +#define LINKTYPE_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define LINKTYPE_RIO 124 /* RapidIO */ +#define LINKTYPE_PCI_EXP 125 /* PCI Express */ +#define LINKTYPE_AURORA 126 /* Xilinx Aurora link layer */ + +#define LINKTYPE_IEEE802_11_RADIO 127 /* 802.11 plus BSD radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define LINKTYPE_TZSP 128 /* Tazmen Sniffer Protocol */ + +#define LINKTYPE_ARCNET_LINUX 129 /* Linux-style headers */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The corresponding + * DLT_s are used for passing on chassis-internal + * metainformation such as QOS profiles, etc.. + */ +#define LINKTYPE_JUNIPER_MLPPP 130 +#define LINKTYPE_JUNIPER_MLFR 131 +#define LINKTYPE_JUNIPER_ES 132 +#define LINKTYPE_JUNIPER_GGSN 133 +#define LINKTYPE_JUNIPER_MFR 134 +#define LINKTYPE_JUNIPER_ATM2 135 +#define LINKTYPE_JUNIPER_SERVICES 136 +#define LINKTYPE_JUNIPER_ATM1 137 + +#define LINKTYPE_APPLE_IP_OVER_IEEE1394 138 /* Apple IP-over-IEEE 1394 cooked header */ + +#define LINKTYPE_RAWSS7 139 /* see rawss7.h for */ +#define LINKTYPE_RAWSS7_MTP2 140 /* information on these */ +#define LINKTYPE_RAWSS7_MTP3 141 /* definitions */ +#define LINKTYPE_RAWSS7_SCCP 142 + +/* + * This isn't supported in libpcap 0.8[.x], but is supported in the + * current CVS version; we include it here to note that it's not available + * for anybody else to use. + */ +#define LINKTYPE_DOCSIS 143 /* DOCSIS MAC frames */ + +#define LINKTYPE_LINUX_IRDA 144 /* Linux-IrDA */ + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define LINKTYPE_IBM_SP 145 +#define LINKTYPE_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that LINKTYPE_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, in those cases, ask "tcpdump-workers@tcpdump.org" for a new DLT_ + * and LINKTYPE_ value, as per the comment in pcap-bpf.h, and use the type + * you're given. + */ +#define LINKTYPE_USER0 147 +#define LINKTYPE_USER1 148 +#define LINKTYPE_USER2 149 +#define LINKTYPE_USER3 150 +#define LINKTYPE_USER4 151 +#define LINKTYPE_USER5 152 +#define LINKTYPE_USER6 153 +#define LINKTYPE_USER7 154 +#define LINKTYPE_USER8 155 +#define LINKTYPE_USER9 156 +#define LINKTYPE_USER10 157 +#define LINKTYPE_USER11 158 +#define LINKTYPE_USER12 159 +#define LINKTYPE_USER13 160 +#define LINKTYPE_USER14 161 +#define LINKTYPE_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but could and arguably should also be used by non-AVS Linux + * 802.11 drivers; that may happen in the future. + */ +#define LINKTYPE_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The corresponding + * DLT_s are used for passing on chassis-internal + * metainformation such as QOS profiles, etc.. + */ +#define LINKTYPE_JUNIPER_MONITOR 164 + +static struct linktype_map { + int dlt; + int linktype; +} map[] = { + /* + * These DLT_* codes have LINKTYPE_* codes with values identical + * to the values of the corresponding DLT_* code. + */ + { DLT_NULL, LINKTYPE_NULL }, + { DLT_EN10MB, LINKTYPE_ETHERNET }, + { DLT_EN3MB, LINKTYPE_EXP_ETHERNET }, + { DLT_AX25, LINKTYPE_AX25 }, + { DLT_PRONET, LINKTYPE_PRONET }, + { DLT_CHAOS, LINKTYPE_CHAOS }, + { DLT_IEEE802, LINKTYPE_TOKEN_RING }, + { DLT_ARCNET, LINKTYPE_ARCNET }, + { DLT_SLIP, LINKTYPE_SLIP }, + { DLT_PPP, LINKTYPE_PPP }, + { DLT_FDDI, LINKTYPE_FDDI }, + + /* + * These DLT_* codes have different values on different + * platforms; we map them to LINKTYPE_* codes that + * have values that should never be equal to any DLT_* + * code. + */ +#ifdef DLT_FR + /* BSD/OS Frame Relay */ + { DLT_FR, LINKTYPE_FRELAY }, +#endif + + { DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL }, + { DLT_ATM_RFC1483, LINKTYPE_ATM_RFC1483 }, + { DLT_RAW, LINKTYPE_RAW }, + { DLT_SLIP_BSDOS, LINKTYPE_SLIP_BSDOS }, + { DLT_PPP_BSDOS, LINKTYPE_PPP_BSDOS }, + + /* BSD/OS Cisco HDLC */ + { DLT_C_HDLC, LINKTYPE_C_HDLC }, + + /* + * These DLT_* codes are not on all platforms, but, so far, + * there don't appear to be any platforms that define + * other codes with those values; we map them to + * different LINKTYPE_* values anyway, just in case. + */ + + /* Linux ATM Classical IP */ + { DLT_ATM_CLIP, LINKTYPE_ATM_CLIP }, + + /* NetBSD sync/async serial PPP (or Cisco HDLC) */ + { DLT_PPP_SERIAL, LINKTYPE_PPP_HDLC }, + + /* NetBSD PPP over Ethernet */ + { DLT_PPP_ETHER, LINKTYPE_PPP_ETHER }, + + /* IEEE 802.11 wireless */ + { DLT_IEEE802_11, LINKTYPE_IEEE802_11 }, + + /* Frame Relay */ + { DLT_FRELAY, LINKTYPE_FRELAY }, + + /* OpenBSD loopback */ + { DLT_LOOP, LINKTYPE_LOOP }, + + /* Linux cooked socket capture */ + { DLT_LINUX_SLL, LINKTYPE_LINUX_SLL }, + + /* Apple LocalTalk hardware */ + { DLT_LTALK, LINKTYPE_LTALK }, + + /* Acorn Econet */ + { DLT_ECONET, LINKTYPE_ECONET }, + + /* OpenBSD DLT_PFLOG */ + { DLT_PFLOG, LINKTYPE_PFLOG }, + + /* For Cisco-internal use */ + { DLT_CISCO_IOS, LINKTYPE_CISCO_IOS }, + + /* Prism II monitor-mode header plus 802.11 header */ + { DLT_PRISM_HEADER, LINKTYPE_PRISM_HEADER }, + + /* FreeBSD Aironet driver stuff */ + { DLT_AIRONET_HEADER, LINKTYPE_AIRONET_HEADER }, + + /* Siemens HiPath HDLC */ + { DLT_HHDLC, LINKTYPE_HHDLC }, + + /* RFC 2625 IP-over-Fibre Channel */ + { DLT_IP_OVER_FC, LINKTYPE_IP_OVER_FC }, + + /* Solaris+SunATM */ + { DLT_SUNATM, LINKTYPE_SUNATM }, + + /* RapidIO */ + { DLT_RIO, LINKTYPE_RIO }, + + /* PCI Express */ + { DLT_PCI_EXP, LINKTYPE_PCI_EXP }, + + /* Xilinx Aurora link layer */ + { DLT_AURORA, LINKTYPE_AURORA }, + + /* 802.11 plus BSD radio header */ + { DLT_IEEE802_11_RADIO, LINKTYPE_IEEE802_11_RADIO }, + + /* Tazmen Sniffer Protocol */ + { DLT_TZSP, LINKTYPE_TZSP }, + + /* Arcnet with Linux-style link-layer headers */ + { DLT_ARCNET_LINUX, LINKTYPE_ARCNET_LINUX }, + + /* Juniper-internal chassis encapsulation */ + { DLT_JUNIPER_MLPPP, LINKTYPE_JUNIPER_MLPPP }, + { DLT_JUNIPER_MLFR, LINKTYPE_JUNIPER_MLFR }, + { DLT_JUNIPER_ES, LINKTYPE_JUNIPER_ES }, + { DLT_JUNIPER_GGSN, LINKTYPE_JUNIPER_GGSN }, + { DLT_JUNIPER_MFR, LINKTYPE_JUNIPER_MFR }, + { DLT_JUNIPER_ATM2, LINKTYPE_JUNIPER_ATM2 }, + { DLT_JUNIPER_SERVICES, LINKTYPE_JUNIPER_SERVICES }, + { DLT_JUNIPER_ATM1, LINKTYPE_JUNIPER_ATM1 }, + + /* Apple IP-over-IEEE 1394 cooked header */ + { DLT_APPLE_IP_OVER_IEEE1394, LINKTYPE_APPLE_IP_OVER_IEEE1394 }, + + /* DOCSIS MAC frames */ + { DLT_DOCSIS, LINKTYPE_DOCSIS }, + + /* IrDA IrLAP packets + Linux-cooked header */ + { DLT_LINUX_IRDA, LINKTYPE_LINUX_IRDA }, + + /* IBM SP and Next Federation switches */ + { DLT_IBM_SP, LINKTYPE_IBM_SP }, + { DLT_IBM_SN, LINKTYPE_IBM_SN }, + + /* 802.11 plus AVS radio header */ + { DLT_IEEE802_11_RADIO_AVS, LINKTYPE_IEEE802_11_RADIO_AVS }, + + /* + * Any platform that defines additional DLT_* codes should: + * + * request a LINKTYPE_* code and value from tcpdump.org, + * as per the above; + * + * add, in their version of libpcap, an entry to map + * those DLT_* codes to the corresponding LINKTYPE_* + * code; + * + * redefine, in their "net/bpf.h", any DLT_* values + * that collide with the values used by their additional + * DLT_* codes, to remove those collisions (but without + * making them collide with any of the LINKTYPE_* + * values equal to 50 or above; they should also avoid + * defining DLT_* values that collide with those + * LINKTYPE_* values, either). + */ + + /* Juniper-internal chassis encapsulation */ + { DLT_JUNIPER_MONITOR, LINKTYPE_JUNIPER_MONITOR }, + + { -1, -1 } +}; + +static int +dlt_to_linktype(int dlt) +{ + int i; + + for (i = 0; map[i].dlt != -1; i++) { + if (map[i].dlt == dlt) + return (map[i].linktype); + } + + /* + * If we don't have a mapping for this DLT_ code, return an + * error; that means that the table above needs to have an + * entry added. + */ + return (-1); +} + +static int +linktype_to_dlt(int linktype) +{ + int i; + + for (i = 0; map[i].linktype != -1; i++) { + if (map[i].linktype == linktype) + return (map[i].dlt); + } + + /* + * If we don't have an entry for this link type, return + * the link type value; it may be a DLT_ value from an + * older version of libpcap. + */ + return linktype; +} + static int sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen) { @@ -109,30 +563,68 @@ swap_hdr(struct pcap_file_header *hp) hp->linktype = SWAPLONG(hp->linktype); } +static int +sf_getnonblock(pcap_t *p, char *errbuf) +{ + /* + * This is a savefile, not a live capture file, so never say + * it's in non-blocking mode. + */ + return (0); +} + +static int +sf_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + /* + * This is a savefile, not a live capture file, so ignore + * requests to put it in non-blocking mode. + */ + return (0); +} + +static int +sf_stats(pcap_t *p, struct pcap_stat *ps) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from savefiles"); + return (-1); +} + +static void +sf_close(pcap_t *p) +{ + if (p->sf.rfile != stdin) + (void)fclose(p->sf.rfile); + if (p->sf.base != NULL) + free(p->sf.base); +} + pcap_t * -pcap_open_offline(char *fname, char *errbuf) +pcap_open_offline(const char *fname, char *errbuf) { register pcap_t *p; register FILE *fp; struct pcap_file_header hdr; + bpf_u_int32 magic; int linklen; p = (pcap_t *)malloc(sizeof(*p)); if (p == NULL) { - (void)strncpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE - 1); + strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE); return (NULL); } memset((char *)p, 0, sizeof(*p)); - /* - * Set this field so we don't close stdin in pcap_close! - */ - p->fd = -1; if (fname[0] == '-' && fname[1] == '\0') fp = stdin; else { +#ifndef WIN32 fp = fopen(fname, "r"); +#else + fp = fopen(fname, "rb"); +#endif if (fp == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); @@ -144,8 +636,10 @@ pcap_open_offline(char *fname, char *errbuf) pcap_strerror(errno)); goto bad; } - if (hdr.magic != TCPDUMP_MAGIC) { - if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC) { + magic = hdr.magic; + if (magic != TCPDUMP_MAGIC && magic != PATCHED_TCPDUMP_MAGIC) { + magic = SWAPLONG(magic); + if (magic != TCPDUMP_MAGIC && magic != PATCHED_TCPDUMP_MAGIC) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "bad dump file format"); goto bad; @@ -153,16 +647,30 @@ pcap_open_offline(char *fname, char *errbuf) p->sf.swapped = 1; swap_hdr(&hdr); } - p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr); + if (magic == PATCHED_TCPDUMP_MAGIC) { + /* + * XXX - the patch that's in some versions of libpcap + * changes the packet header but not the magic number; + * we'd have to use some hacks^H^H^H^H^Hheuristics to + * detect that. + */ + p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr); + } else + p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr); if (hdr.version_major < PCAP_VERSION_MAJOR) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "archaic file format"); goto bad; } p->tzoff = hdr.thiszone; p->snapshot = hdr.snaplen; - p->linktype = hdr.linktype; + p->linktype = linktype_to_dlt(hdr.linktype); p->sf.rfile = fp; +#ifndef WIN32 p->bufsize = hdr.snaplen; +#else + /* Allocate the space for pcap_pkthdr as well. It will be used by pcap_read_ex */ + p->bufsize = hdr.snaplen+sizeof(struct pcap_pkthdr); +#endif /* Align link header as required for proper data alignment */ /* XXX should handle all types */ @@ -197,8 +705,59 @@ pcap_open_offline(char *fname, char *errbuf) pcap_fddipad = 0; #endif + /* + * We interchanged the caplen and len fields at version 2.3, + * in order to match the bpf header layout. But unfortunately + * some files were written with version 2.3 in their headers + * but without the interchanged fields. + * + * In addition, DG/UX tcpdump writes out files with a version + * number of 543.0, and with the caplen and len fields in the + * pre-2.3 order. + */ + switch (hdr.version_major) { + + case 2: + if (hdr.version_minor < 3) + p->sf.lengths_swapped = SWAPPED; + else if (hdr.version_minor == 3) + p->sf.lengths_swapped = MAYBE_SWAPPED; + else + p->sf.lengths_swapped = NOT_SWAPPED; + break; + + case 543: + p->sf.lengths_swapped = SWAPPED; + break; + + default: + p->sf.lengths_swapped = NOT_SWAPPED; + break; + } + +#ifndef WIN32 + /* + * You can do "select()" and "poll()" on plain files on most + * platforms, and should be able to do so on pipes. + * + * You can't do "select()" on anything other than sockets in + * Windows, so, on Win32 systems, we don't have "selectable_fd". + */ + p->selectable_fd = fileno(fp); +#endif + + p->read_op = pcap_offline_read; + p->setfilter_op = install_bpf_program; + p->set_datalink_op = NULL; /* we don't support munging link-layer headers */ + p->getnonblock_op = sf_getnonblock; + p->setnonblock_op = sf_setnonblock; + p->stats_op = sf_stats; + p->close_op = sf_close; + return (p); bad: + if(fp) + fclose(fp); free(p); return (NULL); } @@ -209,10 +768,12 @@ pcap_open_offline(char *fname, char *errbuf) * no more packets, and SFERR_TRUNC if a partial packet was encountered. */ static int -sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) +sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, u_int buflen) { - struct pcap_sf_pkthdr sf_hdr; + struct pcap_sf_patched_pkthdr sf_hdr; FILE *fp = p->sf.rfile; + size_t amt_read; + bpf_u_int32 t; /* * Read the packet header; the structure we use as a buffer @@ -221,9 +782,23 @@ sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) * unpatched libpcap we only read as many bytes as the regular * header has. */ - if (fread(&sf_hdr, p->sf.hdrsize, 1, fp) != 1) { - /* probably an EOF, though could be a truncated packet */ - return (1); + amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp); + if (amt_read != p->sf.hdrsize) { + if (ferror(fp)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + return (-1); + } else { + if (amt_read != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %d header bytes, only got %lu", + p->sf.hdrsize, (unsigned long)amt_read); + return (-1); + } + /* EOF */ + return (1); + } } if (p->sf.swapped) { @@ -238,17 +813,27 @@ sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) hdr->ts.tv_sec = sf_hdr.ts.tv_sec; hdr->ts.tv_usec = sf_hdr.ts.tv_usec; } - /* - * We interchanged the caplen and len fields at version 2.3, - * in order to match the bpf header layout. But unfortunately - * some files were written with version 2.3 in their headers - * but without the interchanged fields. - */ - if (p->sf.version_minor < 3 || - (p->sf.version_minor == 3 && hdr->caplen > hdr->len)) { - int t = hdr->caplen; + /* Swap the caplen and len fields, if necessary. */ + switch (p->sf.lengths_swapped) { + + case NOT_SWAPPED: + break; + + case MAYBE_SWAPPED: + if (hdr->caplen <= hdr->len) { + /* + * The captured length is <= the actual length, + * so presumably they weren't swapped. + */ + break; + } + /* FALLTHROUGH */ + + case SWAPPED: + t = hdr->caplen; hdr->caplen = hdr->len; hdr->len = t; + break; } if (hdr->caplen > buflen) { @@ -259,13 +844,14 @@ sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) * grossly wrong, try to salvage. */ static u_char *tp = NULL; - static int tsize = 0; + static size_t tsize = 0; if (hdr->caplen > 65535) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "bogus savefile header"); return (-1); } + if (tsize < hdr->caplen) { tsize = ((hdr->caplen + 1023) / 1024) * 1024; if (tp != NULL) @@ -278,9 +864,17 @@ sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) return (-1); } } - if (fread((char *)tp, hdr->caplen, 1, fp) != 1) { - (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file"); + amt_read = fread((char *)tp, 1, hdr->caplen, fp); + if (amt_read != hdr->caplen) { + if (ferror(fp)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %lu", + hdr->caplen, (unsigned long)amt_read); + } return (-1); } /* @@ -295,9 +889,18 @@ sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen) } else { /* read the packet itself */ - if (fread((char *)buf, hdr->caplen, 1, fp) != 1) { - (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file"); + amt_read = fread((char *)buf, 1, hdr->caplen, fp); + if (amt_read != hdr->caplen) { + if (ferror(fp)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %lu", + hdr->caplen, (unsigned long)amt_read); + } + return (-1); } } return (0); @@ -317,6 +920,23 @@ pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) while (status == 0) { struct pcap_pkthdr h; + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else + return (n); + } + status = sf_next_packet(p, &h, p->buffer, p->bufsize); if (status) { if (status == 1) @@ -358,23 +978,57 @@ pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) * Initialize so that sf_write() will output to the file named 'fname'. */ pcap_dumper_t * -pcap_dump_open(pcap_t *p, char *fname) +pcap_dump_open(pcap_t *p, const char *fname) { FILE *f; - if (fname[0] == '-' && fname[1] == '\0') + int linktype; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, linktype); + return (NULL); + } + + if (fname[0] == '-' && fname[1] == '\0') { f = stdout; - else { +#ifdef WIN32 + _setmode(_fileno(f), _O_BINARY); +#endif + } else { +#ifndef WIN32 f = fopen(fname, "w"); +#else + f = fopen(fname, "wb"); + setbuf(f, NULL); /* XXX - why? */ +#endif if (f == NULL) { (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } } - (void)sf_write_header(f, p->linktype, p->tzoff, p->snapshot); + (void)sf_write_header(f, linktype, p->tzoff, p->snapshot); return ((pcap_dumper_t *)f); } +FILE * +pcap_dump_file(pcap_dumper_t *p) +{ + return ((FILE *)p); +} + +int +pcap_dump_flush(pcap_dumper_t *p) +{ + + if (fflush((FILE *)p) == EOF) + return (-1); + else + return (0); +} + void pcap_dump_close(pcap_dumper_t *p) { diff --git a/lib/libpcap/scanner.l b/lib/libpcap/scanner.l index 032e688e79c5..4cc788016ef0 100644 --- a/lib/libpcap/scanner.l +++ b/lib/libpcap/scanner.l @@ -1,5 +1,5 @@ %{ -/* $NetBSD: scanner.l,v 1.16 2004/06/25 12:22:23 itojun Exp $ */ +/* $NetBSD: scanner.l,v 1.17 2004/09/27 23:02:53 dyoung Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 @@ -26,21 +26,39 @@ #ifndef lint #if 0 static const char rcsid[] = - "@(#) Header: scanner.l,v 1.56 97/07/21 13:31:50 leres Exp (LBL)"; + "@(#) Header: /tcpdump/master/libpcap/scanner.l,v 1.95.2.3 2004/03/28 21:45:33 fenner Exp (LBL)"; #else -__RCSID("$NetBSD: scanner.l,v 1.16 2004/06/25 12:22:23 itojun Exp $"); +__RCSID("$NetBSD: scanner.l,v 1.17 2004/09/27 23:02:53 dyoung Exp $"); #endif #endif -#include -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include -#include +#include #include "pcap-int.h" #include "gencode.h" +#ifdef INET6 +#ifdef WIN32 +#include + +#ifdef __MINGW32__ +#include "IP6_misc.h" +#endif +#else /* WIN32 */ +#include /* for "struct sockaddr" in "struct addrinfo" */ +#include /* for "struct addrinfo" */ +#endif /* WIN32 */ + +/* Workaround for AIX 4.3 */ +#if !defined(AI_NUMERICHOST) +#define AI_NUMERICHOST 0x04 +#endif +#endif /*INET6*/ #include #ifdef INET6 #include @@ -49,7 +67,6 @@ __RCSID("$NetBSD: scanner.l,v 1.16 2004/06/25 12:22:23 itojun Exp $"); #endif /*INET6*/ #include "grammar.h" -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -59,22 +76,10 @@ static inline int xdtoi(int); #ifdef FLEX_SCANNER #define YY_NO_UNPUT -#undef YY_INPUT -#define YY_INPUT(buf, result, max)\ - {\ - char *src = in_buffer;\ - int i;\ -\ - if (*src == 0)\ - result = YY_NULL;\ - else {\ - for (i = 0; *src && i < max; ++i)\ - buf[i] = *src++;\ - in_buffer += i;\ - result = i;\ - }\ - } +static YY_BUFFER_STATE in_buffer; #else +static char *in_buffer; + #undef getc #define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) #endif @@ -84,15 +89,18 @@ static inline int xdtoi(int); extern YYSTYPE yylval; #endif -static char *in_buffer; - %} N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) B ([0-9A-Fa-f][0-9A-Fa-f]?) W ([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?) -%a 3000 +%a 16000 +%o 19000 +%e 6000 +%k 4000 +%p 25000 +%n 2000 V680 {W}:{W}:{W}:{W}:{W}:{W}:{W}:{W} @@ -177,10 +185,11 @@ dst return DST; src return SRC; link|ether|ppp|slip return LINK; -fddi return LINK; +fddi|tr|wlan return LINK; arp return ARP; rarp return RARP; ip return IP; +sctp return SCTP; tcp return TCP; udp return UDP; icmp return ICMP; @@ -189,21 +198,55 @@ igrp return IGRP; pim return PIM; vrrp return VRRP; -ip6 return IPV6; -icmp6 return ICMPV6; +ip6 { +#ifdef INET6 + return IPV6; +#else + bpf_error("%s not supported", yytext); +#endif + } +icmp6 { +#ifdef INET6 + return ICMPV6; +#else + bpf_error("%s not supported", yytext); +#endif + } ah return AH; esp return ESP; atalk return ATALK; +aarp return AARP; decnet return DECNET; lat return LAT; sca return SCA; moprc return MOPRC; mopdl return MOPDL; +iso return ISO; +esis return ESIS; +es-is return ESIS; +isis return ISIS; +is-is return ISIS; +l1 return L1; +l2 return L2; +iih return IIH; +lsp return LSP; +snp return SNP; +csnp return CSNP; +psnp return PSNP; + +clnp return CLNP; + +stp return STP; + +ipx return IPX; + +netbeui return NETBEUI; + host return HOST; net return NET; -mask return MASK; +mask return NETMASK; port return PORT; proto return PROTO; protochain { @@ -218,7 +261,7 @@ gateway return GATEWAY; less return LESS; greater return GREATER; -byte return BYTE; +byte return CBYTE; broadcast return TK_BROADCAST; multicast return TK_MULTICAST; @@ -229,8 +272,24 @@ not return '!'; len|length return LEN; inbound return INBOUND; outbound return OUTBOUND; + vlan return VLAN; +lane return LANE; +llc return LLC; +metac return METAC; +bcc return BCC; +oam return OAM; +oamf4 return OAMF4; +oamf4ec return OAMF4EC; +oamf4sc return OAMF4SC; +sc return SC; +ilmic return ILMIC; +vpi return VPI; +vci return VCI; +connectmsg return CONNECTMSG; +metaconnect return METACONNECT; + on|ifname return PF_IFNAME; rset|ruleset return PF_RSET; rnr|rulenum return PF_RNR; @@ -238,7 +297,7 @@ srnr|subrulenum return PF_SRNR; reason return PF_REASON; action return PF_ACTION; -[ \n\t] ; +[ \r\n\t] ; [+\-*/:\[\]!<>()&|=] return yytext[0]; ">=" return GEQ; "<=" return LEQ; @@ -262,7 +321,7 @@ ${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1); if (getaddrinfo(yytext, NULL, &hints, &res)) bpf_error("bogus IPv6 address %s", yytext); else { - yylval.e = sdup((char *)yytext); return HID6; + yylval.s = sdup((char *)yytext); return HID6; } #else bpf_error("IPv6 address %s not supported", yytext); @@ -293,18 +352,35 @@ tcp-rst { yylval.i = 0x04; return NUM; } tcp-push { yylval.i = 0x08; return NUM; } tcp-ack { yylval.i = 0x10; return NUM; } tcp-urg { yylval.i = 0x20; return NUM; } -[A-Za-z0-9][-_.A-Za-z0-9]*[.A-Za-z0-9] { +[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { yylval.s = sdup((char *)yytext); return ID; } "\\"[^ !()\n\t]+ { yylval.s = sdup((char *)yytext + 1); return ID; } -[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+i { - bpf_error("illegal token: %s\n", yytext); } +[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { + bpf_error("illegal token: %s", yytext); } . { bpf_error("illegal char '%c'", *yytext); } %% void lex_init(buf) char *buf; { +#ifdef FLEX_SCANNER + in_buffer = yy_scan_string(buf); +#else in_buffer = buf; +#endif +} + +/* + * Do any cleanup necessary after parsing. + */ +void +lex_cleanup() +{ +#ifdef FLEX_SCANNER + if (in_buffer != NULL) + yy_delete_buffer(in_buffer); + in_buffer = NULL; +#endif } /* @@ -356,4 +432,3 @@ stoi(s) return n; } - diff --git a/lib/libpcap/version.c b/lib/libpcap/version.c index 61bea7eb77c9..5a925771ddbf 100644 --- a/lib/libpcap/version.c +++ b/lib/libpcap/version.c @@ -1,2 +1,2 @@ -/* $NetBSD: version.c,v 1.3 2000/10/08 14:28:05 itojun Exp $ */ -char pcap_version[] = "0.4"; +/* $NetBSD: version.c,v 1.4 2004/09/27 23:02:53 dyoung Exp $ */ +char pcap_version[] = "0.8.3";