1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that: (1) source code distributions
|
|
|
|
* retain the above copyright notice and this paragraph in its entirety, (2)
|
|
|
|
* distributions including binary code include the above copyright notice and
|
|
|
|
* this paragraph in its entirety in the documentation or other materials
|
|
|
|
* provided with the distribution, and (3) all advertising materials mentioning
|
|
|
|
* features or use of this software display the following acknowledgement:
|
|
|
|
* ``This product includes software developed by the University of California,
|
|
|
|
* Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*
|
|
|
|
* packet filter subroutines for tcpdump
|
|
|
|
* Extraction/creation by Jeffrey Mogul, DECWRL
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
2003-11-15 23:23:57 +00:00
|
|
|
static const char rcsid[] _U_ =
|
2006-10-04 18:09:21 +00:00
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.94 2006-10-04 18:09:22 guy Exp $ (LBL)";
|
2000-07-11 00:37:04 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/timeb.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <net/pfilt.h>
|
|
|
|
|
|
|
|
struct mbuf;
|
|
|
|
struct rtentry;
|
|
|
|
#include <net/if.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/if_ether.h>
|
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/udp_var.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netinet/tcpip.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2003-05-02 08:35:42 +00:00
|
|
|
/*
|
2006-10-04 18:09:21 +00:00
|
|
|
* Make "pcap.h" not include "pcap/bpf.h"; we are going to include the
|
2003-05-02 08:35:42 +00:00
|
|
|
* native OS version, as we need various BPF ioctls from it.
|
|
|
|
*/
|
|
|
|
#define PCAP_DONT_INCLUDE_PCAP_BPF_H
|
|
|
|
#include <net/bpf.h>
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
#include "pcap-int.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_OS_PROTO_H
|
|
|
|
#include "os-proto.h"
|
|
|
|
#endif
|
|
|
|
|
2003-07-25 04:42:02 +00:00
|
|
|
static int pcap_setfilter_pf(pcap_t *, struct bpf_program *);
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump
|
|
|
|
* applications aren't going to need more than 200 bytes of packet header
|
|
|
|
* and the read shouldn't return more packets than packetfilter's internal
|
|
|
|
* queue limit (bounded at 256).
|
|
|
|
*/
|
|
|
|
#define BUFSPACE (200 * 256)
|
|
|
|
|
2003-07-25 05:32:02 +00:00
|
|
|
static int
|
|
|
|
pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
|
|
|
register u_char *p, *bp;
|
|
|
|
struct bpf_insn *fcode;
|
|
|
|
register int cc, n, buflen, inc;
|
|
|
|
register struct enstamp *sp;
|
|
|
|
#ifdef LBL_ALIGN
|
|
|
|
struct enstamp stamp;
|
|
|
|
#endif
|
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
register int pad;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fcode = pc->md.use_bpf ? NULL : pc->fcode.bf_insns;
|
|
|
|
again:
|
|
|
|
cc = pc->cc;
|
|
|
|
if (cc == 0) {
|
|
|
|
cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize);
|
|
|
|
if (cc < 0) {
|
|
|
|
if (errno == EWOULDBLOCK)
|
|
|
|
return (0);
|
|
|
|
if (errno == EINVAL &&
|
|
|
|
lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) {
|
|
|
|
/*
|
|
|
|
* Due to a kernel bug, after 2^31 bytes,
|
|
|
|
* the kernel file offset overflows and
|
|
|
|
* read fails with EINVAL. The lseek()
|
|
|
|
* to 0 will fix things.
|
|
|
|
*/
|
|
|
|
(void)lseek(pc->fd, 0L, SEEK_SET);
|
|
|
|
goto again;
|
|
|
|
}
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(pc->errbuf, sizeof(pc->errbuf), "pf read: %s",
|
1999-10-07 23:46:40 +00:00
|
|
|
pcap_strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
bp = pc->buffer + pc->offset;
|
|
|
|
} else
|
|
|
|
bp = pc->bp;
|
|
|
|
/*
|
|
|
|
* Loop through each packet.
|
|
|
|
*/
|
|
|
|
n = 0;
|
|
|
|
#ifdef PCAP_FDDIPAD
|
2005-04-19 00:55:48 +00:00
|
|
|
pad = pc->fddipad;
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
while (cc > 0) {
|
2003-11-04 07:05:32 +00:00
|
|
|
/*
|
|
|
|
* 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 (pc->break_loop) {
|
|
|
|
if (n == 0) {
|
|
|
|
pc->break_loop = 0;
|
|
|
|
return (-2);
|
|
|
|
} else {
|
|
|
|
pc->cc = cc;
|
|
|
|
pc->bp = bp;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
if (cc < sizeof(*sp)) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(pc->errbuf, sizeof(pc->errbuf),
|
|
|
|
"pf short read (%d)", cc);
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
#ifdef LBL_ALIGN
|
|
|
|
if ((long)bp & 3) {
|
|
|
|
sp = &stamp;
|
|
|
|
memcpy((char *)sp, (char *)bp, sizeof(*sp));
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
sp = (struct enstamp *)bp;
|
|
|
|
if (sp->ens_stamplen != sizeof(*sp)) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(pc->errbuf, sizeof(pc->errbuf),
|
|
|
|
"pf short stamplen (%d)",
|
1999-10-07 23:46:40 +00:00
|
|
|
sp->ens_stamplen);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
p = bp + sp->ens_stamplen;
|
|
|
|
buflen = sp->ens_count;
|
|
|
|
if (buflen > pc->snapshot)
|
|
|
|
buflen = pc->snapshot;
|
|
|
|
|
|
|
|
/* Calculate inc before possible pad update */
|
|
|
|
inc = ENALIGN(buflen + sp->ens_stamplen);
|
|
|
|
cc -= inc;
|
|
|
|
bp += inc;
|
|
|
|
pc->md.TotPkts++;
|
|
|
|
pc->md.TotDrops += sp->ens_dropped;
|
|
|
|
pc->md.TotMissed = sp->ens_ifoverflows;
|
|
|
|
if (pc->md.OrigMissed < 0)
|
|
|
|
pc->md.OrigMissed = pc->md.TotMissed;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Short-circuit evaluation: if using BPF filter
|
|
|
|
* in kernel, no need to do it now.
|
2004-12-15 00:05:48 +00:00
|
|
|
*
|
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
* Note: the filter code was generated assuming
|
2005-04-19 00:55:48 +00:00
|
|
|
* that pc->fddipad was the amount of padding
|
2004-12-15 00:05:48 +00:00
|
|
|
* before the header, as that's what's required
|
|
|
|
* in the kernel, so we run the filter before
|
|
|
|
* skipping that padding.
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
*/
|
|
|
|
if (fcode == NULL ||
|
|
|
|
bpf_filter(fcode, p, sp->ens_count, buflen)) {
|
|
|
|
struct pcap_pkthdr h;
|
|
|
|
pc->md.TotAccepted++;
|
|
|
|
h.ts = sp->ens_tstamp;
|
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
h.len = sp->ens_count - pad;
|
|
|
|
#else
|
|
|
|
h.len = sp->ens_count;
|
2004-12-15 00:05:48 +00:00
|
|
|
#endif
|
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
p += pad;
|
|
|
|
buflen -= pad;
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
h.caplen = buflen;
|
|
|
|
(*callback)(user, &h, p);
|
|
|
|
if (++n >= cnt && cnt > 0) {
|
|
|
|
pc->cc = cc;
|
|
|
|
pc->bp = bp;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pc->cc = 0;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
|
2004-03-23 19:18:04 +00:00
|
|
|
static int
|
|
|
|
pcap_inject_pf(pcap_t *p, const void *buf, size_t size)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = write(p->fd, buf, size);
|
|
|
|
if (ret == -1) {
|
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
2003-07-25 04:04:56 +00:00
|
|
|
static int
|
|
|
|
pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
|
|
|
|
2001-07-29 01:22:40 +00:00
|
|
|
/*
|
2001-12-10 07:14:14 +00:00
|
|
|
* If packet filtering is being done in the kernel:
|
2001-07-29 01:22:40 +00:00
|
|
|
*
|
2001-12-10 07:14:14 +00:00
|
|
|
* "ps_recv" counts only packets that passed the filter.
|
|
|
|
* This does not include packets dropped because we
|
|
|
|
* ran out of buffer space. (XXX - perhaps it should,
|
|
|
|
* by adding "ps_drop" to "ps_recv", for compatibility
|
|
|
|
* with some other platforms. On the other hand, on
|
|
|
|
* some platforms "ps_recv" counts only packets that
|
|
|
|
* passed the filter, and on others it counts packets
|
|
|
|
* that didn't pass the filter....)
|
2001-07-29 01:22:40 +00:00
|
|
|
*
|
2001-12-10 07:14:14 +00:00
|
|
|
* "ps_drop" counts packets that passed the kernel filter
|
|
|
|
* (if any) but were dropped because the input queue was
|
|
|
|
* full.
|
|
|
|
*
|
|
|
|
* "ps_ifdrop" counts packets dropped by the network
|
|
|
|
* inteface (regardless of whether they would have passed
|
|
|
|
* the input filter, of course).
|
|
|
|
*
|
|
|
|
* If packet filtering is not being done in the kernel:
|
|
|
|
*
|
|
|
|
* "ps_recv" counts only packets that passed the filter.
|
|
|
|
*
|
|
|
|
* "ps_drop" counts packets that were dropped because the
|
|
|
|
* input queue was full, regardless of whether they passed
|
|
|
|
* the userland filter.
|
|
|
|
*
|
|
|
|
* "ps_ifdrop" counts packets dropped by the network
|
|
|
|
* inteface (regardless of whether they would have passed
|
|
|
|
* the input filter, of course).
|
|
|
|
*
|
|
|
|
* These statistics don't include packets not yet read from
|
|
|
|
* the kernel by libpcap, but they may include packets not
|
|
|
|
* yet read from libpcap by the application.
|
2001-07-29 01:22:40 +00:00
|
|
|
*/
|
1999-10-07 23:46:40 +00:00
|
|
|
ps->ps_recv = p->md.TotAccepted;
|
|
|
|
ps->ps_drop = p->md.TotDrops;
|
|
|
|
ps->ps_ifdrop = p->md.TotMissed - p->md.OrigMissed;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2004-02-09 06:24:42 +00:00
|
|
|
/*
|
2006-10-04 18:09:21 +00:00
|
|
|
* We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably
|
2004-02-09 06:24:42 +00:00
|
|
|
* don't get DLT_DOCSIS defined.
|
|
|
|
*/
|
|
|
|
#ifndef DLT_DOCSIS
|
|
|
|
#define DLT_DOCSIS 143
|
|
|
|
#endif
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
pcap_t *
|
2002-12-22 02:36:48 +00:00
|
|
|
pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|
|
|
char *ebuf)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
|
|
|
pcap_t *p;
|
|
|
|
short enmode;
|
|
|
|
int backlog = -1; /* request the most */
|
|
|
|
struct enfilter Filter;
|
|
|
|
struct endevp devparams;
|
|
|
|
|
|
|
|
p = (pcap_t *)malloc(sizeof(*p));
|
|
|
|
if (p == NULL) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
2000-04-27 09:11:11 +00:00
|
|
|
"pcap_open_live: %s", pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (0);
|
|
|
|
}
|
2000-07-29 08:03:56 +00:00
|
|
|
memset(p, 0, sizeof(*p));
|
2003-01-03 08:33:24 +00:00
|
|
|
/*
|
2004-03-23 19:18:04 +00:00
|
|
|
* Initially try a read/write open (to allow the inject
|
|
|
|
* method to work). If that fails due to permission
|
|
|
|
* issues, fall back to read-only. This allows a
|
|
|
|
* non-root user to be granted specific access to pcap
|
|
|
|
* capabilities via file permissions.
|
|
|
|
*
|
|
|
|
* XXX - we should have an API that has a flag that
|
|
|
|
* controls whether to open read-only or read-write,
|
|
|
|
* so that denial of permission to send (or inability
|
|
|
|
* to send, if sending packets isn't supported on
|
|
|
|
* the device in question) can be indicated at open
|
|
|
|
* time.
|
|
|
|
*
|
2003-01-03 08:33:24 +00:00
|
|
|
* XXX - we assume here that "pfopen()" does not, in fact, modify
|
|
|
|
* its argument, even though it takes a "char *" rather than a
|
|
|
|
* "const char *" as its first argument. That appears to be
|
|
|
|
* the case, at least on Digital UNIX 4.0.
|
|
|
|
*/
|
2004-03-23 19:18:04 +00:00
|
|
|
p->fd = pfopen(device, O_RDWR);
|
|
|
|
if (p->fd == -1 && errno == EACCES)
|
|
|
|
p->fd = pfopen(device, O_RDONLY);
|
1999-10-07 23:46:40 +00:00
|
|
|
if (p->fd < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\
|
2002-08-03 20:22:27 +00:00
|
|
|
your system may not be properly configured; see the packetfilter(4) man page\n",
|
1999-10-07 23:46:40 +00:00
|
|
|
device, pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
p->md.OrigMissed = -1;
|
|
|
|
enmode = ENTSTAMP|ENBATCH|ENNONEXCL;
|
|
|
|
if (promisc)
|
|
|
|
enmode |= ENPROMISC;
|
|
|
|
if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
#ifdef ENCOPYALL
|
|
|
|
/* Try to set COPYALL mode so that we see packets to ourself */
|
|
|
|
enmode = ENCOPYALL;
|
|
|
|
(void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */
|
|
|
|
#endif
|
|
|
|
/* set the backlog */
|
|
|
|
if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
/* discover interface type */
|
|
|
|
if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
/* HACK: to compile prior to Ultrix 4.2 */
|
|
|
|
#ifndef ENDT_FDDI
|
|
|
|
#define ENDT_FDDI 4
|
|
|
|
#endif
|
|
|
|
switch (devparams.end_dev_type) {
|
|
|
|
|
|
|
|
case ENDT_10MB:
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
p->linktype = DLT_EN10MB;
|
1999-10-07 23:46:40 +00:00
|
|
|
p->offset = 2;
|
2003-12-18 23:32:31 +00:00
|
|
|
/*
|
|
|
|
* This is (presumably) a real Ethernet capture; give it a
|
|
|
|
* link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
|
|
|
|
* that an application can let you choose it, in case you're
|
|
|
|
* capturing DOCSIS traffic that a Cisco Cable Modem
|
|
|
|
* Termination System is putting out onto an Ethernet (it
|
|
|
|
* doesn't put an Ethernet header onto the wire, it puts raw
|
|
|
|
* DOCSIS frames out on the wire inside the low-level
|
|
|
|
* Ethernet framing).
|
|
|
|
*/
|
|
|
|
p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
|
|
|
|
/*
|
|
|
|
* If that fails, just leave the list empty.
|
|
|
|
*/
|
|
|
|
if (p->dlt_list != NULL) {
|
|
|
|
p->dlt_list[0] = DLT_EN10MB;
|
|
|
|
p->dlt_list[1] = DLT_DOCSIS;
|
|
|
|
p->dlt_count = 2;
|
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ENDT_FDDI:
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
p->linktype = DLT_FDDI;
|
1999-10-07 23:46:40 +00:00
|
|
|
break;
|
|
|
|
|
2001-07-28 22:53:07 +00:00
|
|
|
#ifdef ENDT_SLIP
|
|
|
|
case ENDT_SLIP:
|
|
|
|
p->linktype = DLT_SLIP;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENDT_PPP
|
|
|
|
case ENDT_PPP:
|
|
|
|
p->linktype = DLT_PPP;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENDT_LOOPBACK
|
|
|
|
case ENDT_LOOPBACK:
|
1999-10-07 23:46:40 +00:00
|
|
|
/*
|
2001-07-28 22:53:07 +00:00
|
|
|
* It appears to use Ethernet framing, at least on
|
|
|
|
* Digital UNIX 4.0.
|
1999-10-07 23:46:40 +00:00
|
|
|
*/
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
p->linktype = DLT_EN10MB;
|
1999-10-07 23:46:40 +00:00
|
|
|
p->offset = 2;
|
|
|
|
break;
|
2001-07-28 22:53:07 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENDT_TRN
|
|
|
|
case ENDT_TRN:
|
|
|
|
p->linktype = DLT_IEEE802;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* XXX - what about ENDT_IEEE802? The pfilt.h header
|
|
|
|
* file calls this "IEEE 802 networks (non-Ethernet)",
|
|
|
|
* but that doesn't specify a specific link layer type;
|
|
|
|
* it could be 802.4, or 802.5 (except that 802.5 is
|
|
|
|
* ENDT_TRN), or 802.6, or 802.11, or.... That's why
|
|
|
|
* DLT_IEEE802 was hijacked to mean Token Ring in various
|
|
|
|
* BSDs, and why we went along with that hijacking.
|
|
|
|
*
|
|
|
|
* XXX - what about ENDT_HDLC and ENDT_NULL?
|
|
|
|
* Presumably, as ENDT_OTHER is just "Miscellaneous
|
|
|
|
* framing", there's not much we can do, as that
|
|
|
|
* doesn't specify a particular type of header.
|
|
|
|
*/
|
2002-08-02 03:28:05 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown data-link type %u",
|
2001-07-28 22:53:07 +00:00
|
|
|
devparams.end_dev_type);
|
|
|
|
goto bad;
|
1999-10-07 23:46:40 +00:00
|
|
|
}
|
|
|
|
/* set truncation */
|
|
|
|
#ifdef PCAP_FDDIPAD
|
2004-12-15 00:25:08 +00:00
|
|
|
if (p->linktype == DLT_FDDI) {
|
2005-04-19 00:55:48 +00:00
|
|
|
p->fddipad = PCAP_FDDIPAD;
|
2004-12-15 00:25:08 +00:00
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/* packetfilter includes the padding in the snapshot */
|
2004-12-15 00:25:08 +00:00
|
|
|
snaplen += PCAP_FDDIPAD;
|
|
|
|
} else
|
|
|
|
p->fddipad = 0;
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&snaplen) < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
p->snapshot = snaplen;
|
|
|
|
/* accept all packets */
|
2000-07-29 08:03:56 +00:00
|
|
|
memset(&Filter, 0, sizeof(Filter));
|
1999-10-07 23:46:40 +00:00
|
|
|
Filter.enf_Priority = 37; /* anything > 2 */
|
|
|
|
Filter.enf_FilterLen = 0; /* means "always true" */
|
|
|
|
if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (to_ms != 0) {
|
|
|
|
struct timeval timeout;
|
|
|
|
timeout.tv_sec = to_ms / 1000;
|
|
|
|
timeout.tv_usec = (to_ms * 1000) % 1000000;
|
|
|
|
if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) {
|
2000-04-27 14:24:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s",
|
1999-10-07 23:46:40 +00:00
|
|
|
pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
2003-07-25 03:25:45 +00:00
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
p->bufsize = BUFSPACE;
|
|
|
|
p->buffer = (u_char*)malloc(p->bufsize + p->offset);
|
2003-07-25 03:25:45 +00:00
|
|
|
if (p->buffer == NULL) {
|
|
|
|
strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2003-11-21 10:19:33 +00:00
|
|
|
/*
|
|
|
|
* "select()" and "poll()" work on packetfilter devices.
|
|
|
|
*/
|
|
|
|
p->selectable_fd = p->fd;
|
|
|
|
|
2003-07-25 05:32:02 +00:00
|
|
|
p->read_op = pcap_read_pf;
|
2004-03-23 19:18:04 +00:00
|
|
|
p->inject_op = pcap_inject_pf;
|
2003-07-25 04:42:02 +00:00
|
|
|
p->setfilter_op = pcap_setfilter_pf;
|
2005-05-03 18:53:58 +00:00
|
|
|
p->setdirection_op = NULL; /* Not implemented. */
|
2003-07-25 05:07:01 +00:00
|
|
|
p->set_datalink_op = NULL; /* can't change data link type */
|
2003-11-20 02:02:38 +00:00
|
|
|
p->getnonblock_op = pcap_getnonblock_fd;
|
|
|
|
p->setnonblock_op = pcap_setnonblock_fd;
|
2003-07-25 04:04:56 +00:00
|
|
|
p->stats_op = pcap_stats_pf;
|
2004-10-19 07:06:11 +00:00
|
|
|
p->close_op = pcap_close_common;
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
return (p);
|
|
|
|
bad:
|
2002-06-11 17:04:44 +00:00
|
|
|
if (p->fd >= 0)
|
|
|
|
close(p->fd);
|
2003-12-18 23:32:31 +00:00
|
|
|
/*
|
|
|
|
* Get rid of any link-layer type list we allocated.
|
|
|
|
*/
|
|
|
|
if (p->dlt_list != NULL)
|
|
|
|
free(p->dlt_list);
|
1999-10-07 23:46:40 +00:00
|
|
|
free(p);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2002-07-11 09:06:30 +00:00
|
|
|
int
|
|
|
|
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
|
|
|
|
{
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-07-25 04:42:02 +00:00
|
|
|
static int
|
|
|
|
pcap_setfilter_pf(pcap_t *p, struct bpf_program *fp)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
struct bpf_version bv;
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/*
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
* See if BIOCVERSION works. If not, we assume the kernel doesn't
|
|
|
|
* support BPF-style filters (it's not documented in the bpf(7)
|
|
|
|
* or packetfiler(7) man pages, but the code used to fail if
|
|
|
|
* BIOCSETF worked but BIOCVERSION didn't, and I've seen it do
|
|
|
|
* kernel filtering in DU 4.0, so presumably BIOCVERSION works
|
|
|
|
* there, at least).
|
1999-10-07 23:46:40 +00:00
|
|
|
*/
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) >= 0) {
|
|
|
|
/*
|
|
|
|
* OK, we have the version of the BPF interpreter;
|
|
|
|
* is it the same major version as us, and the same
|
|
|
|
* or better minor version?
|
|
|
|
*/
|
|
|
|
if (bv.bv_major == BPF_MAJOR_VERSION &&
|
|
|
|
bv.bv_minor >= BPF_MINOR_VERSION) {
|
2003-11-21 23:28:27 +00:00
|
|
|
/*
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
* Yes. Try to install the filter.
|
2003-11-21 23:28:27 +00:00
|
|
|
*/
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
|
|
|
|
snprintf(p->errbuf, sizeof(p->errbuf),
|
|
|
|
"BIOCSETF: %s", pcap_strerror(errno));
|
2003-11-21 23:28:27 +00:00
|
|
|
return (-1);
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OK, that succeeded. We're doing filtering in
|
|
|
|
* the kernel. (We assume we don't have a
|
|
|
|
* userland filter installed - that'd require
|
|
|
|
* a previous version check to have failed but
|
|
|
|
* this one to succeed.)
|
|
|
|
*
|
|
|
|
* XXX - this message should be supplied to the
|
|
|
|
* application as a warning of some sort,
|
|
|
|
* except that if it's a GUI application, it's
|
|
|
|
* not clear that it should be displayed in
|
|
|
|
* a window to annoy the user.
|
|
|
|
*/
|
|
|
|
fprintf(stderr, "tcpdump: Using kernel BPF filter\n");
|
|
|
|
p->md.use_bpf = 1;
|
2005-02-26 21:58:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Discard any previously-received packets,
|
|
|
|
* as they might have passed whatever filter
|
|
|
|
* was formerly in effect, but might not pass
|
|
|
|
* this filter (BIOCSETF discards packets buffered
|
|
|
|
* in the kernel, so you can lose packets in any
|
|
|
|
* case).
|
|
|
|
*/
|
|
|
|
p->cc = 0;
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
return (0);
|
1999-10-07 23:46:40 +00:00
|
|
|
}
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't use the kernel's BPF interpreter; don't give
|
|
|
|
* up, just log a message and be inefficient.
|
|
|
|
*
|
|
|
|
* XXX - this should really be supplied to the application
|
|
|
|
* as a warning of some sort.
|
|
|
|
*/
|
|
|
|
fprintf(stderr,
|
|
|
|
"tcpdump: Requires BPF language %d.%d or higher; kernel is %d.%d\n",
|
|
|
|
BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
|
|
|
|
bv.bv_major, bv.bv_minor);
|
2000-10-28 00:01:26 +00:00
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
|
When installing a filter:
first check whether BIOCVERSION works;
then, if so, check whether the version is OK for us;
then, if so, try to install the filter - if that succeeds, free
up any userland filter we had installed, if any, and filter in
the kernel, otherwise fail;
otherwise, if we couldn't get the version or the version check
failed, install a userland filter.
That way, we don't install kernel filters unless we know the kernel's
BPF interpreter is OK for us (rather than checking the version *after*
we've already installed the filter), and don't have to worry about that
filter being in the kernel (possibly with an inappropriate interpreter)
if we're filtering in userland.
Clean up the "version isn't OK" message (put in a newline at the end,
and put in "tcpdump:" at the beginning).
2003-11-22 00:32:25 +00:00
|
|
|
/*
|
|
|
|
* We couldn't do filtering in the kernel; do it in userland.
|
|
|
|
*/
|
|
|
|
if (install_bpf_program(p, fp) < 0)
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX - this message should be supplied by the application as
|
|
|
|
* a warning of some sort.
|
|
|
|
*/
|
|
|
|
fprintf(stderr, "tcpdump: Filtering in user process\n");
|
|
|
|
p->md.use_bpf = 0;
|
1999-10-07 23:46:40 +00:00
|
|
|
return (0);
|
|
|
|
}
|