1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
#ifndef lint
|
2003-11-15 23:23:57 +00:00
|
|
|
static const char rcsid[] _U_ =
|
2006-01-22 05:28:34 +00:00
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.86.2.9 2006-01-22 05:28:34 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/param.h> /* optionally get BSD define */
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/timeb.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/ioctl.h>
|
2003-11-21 10:19:33 +00:00
|
|
|
#include <sys/utsname.h>
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#include <net/if.h>
|
2003-02-11 01:46:05 +00:00
|
|
|
|
2001-11-17 21:24:09 +00:00
|
|
|
#ifdef _AIX
|
2003-02-11 01:46:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 <sys/types.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 <net/bpf.h>
|
|
|
|
#define _AIX
|
|
|
|
|
2001-11-17 21:24:09 +00:00
|
|
|
#include <net/if_types.h> /* for IFT_ values */
|
2003-02-11 01:46:05 +00:00
|
|
|
#include <sys/sysconfig.h>
|
|
|
|
#include <sys/device.h>
|
2005-04-21 02:41:37 +00:00
|
|
|
#include <sys/cfgodm.h>
|
2003-02-11 01:46:05 +00:00
|
|
|
#include <cf.h>
|
|
|
|
|
|
|
|
#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 <net/bpf.h>
|
|
|
|
|
|
|
|
#endif /* _AIX */
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "pcap-int.h"
|
|
|
|
|
2003-07-23 05:29:19 +00:00
|
|
|
#ifdef HAVE_DAG_API
|
|
|
|
#include "pcap-dag.h"
|
|
|
|
#endif /* HAVE_DAG_API */
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
#ifdef HAVE_OS_PROTO_H
|
|
|
|
#include "os-proto.h"
|
|
|
|
#endif
|
|
|
|
|
2003-07-25 04:42:02 +00:00
|
|
|
#include "gencode.h" /* for "no_optimize" */
|
|
|
|
|
|
|
|
static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp);
|
2005-07-07 02:04:33 +00:00
|
|
|
static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t);
|
2003-07-25 05:07:01 +00:00
|
|
|
static int pcap_set_datalink_bpf(pcap_t *p, int dlt);
|
1999-10-19 15:18:28 +00:00
|
|
|
|
2003-07-25 04:04:56 +00:00
|
|
|
static int
|
|
|
|
pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
|
|
|
struct bpf_stat s;
|
|
|
|
|
2001-07-29 01:22:40 +00:00
|
|
|
/*
|
|
|
|
* "ps_recv" counts packets handed to the filter, not packets
|
2001-12-10 07:14:14 +00:00
|
|
|
* that passed the filter. This includes packets later dropped
|
|
|
|
* because we ran out of buffer space.
|
2001-07-29 01:22:40 +00:00
|
|
|
*
|
|
|
|
* "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.
|
2001-12-10 07:14:14 +00:00
|
|
|
*
|
|
|
|
* Both statistics include packets not yet read from the kernel
|
|
|
|
* by libpcap, and thus not yet seen by the application.
|
2001-07-29 01:22:40 +00:00
|
|
|
*/
|
1999-10-07 23:46:40 +00:00
|
|
|
if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->ps_recv = s.bs_recv;
|
|
|
|
ps->ps_drop = s.bs_drop;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-07-25 05:32:02 +00:00
|
|
|
static int
|
|
|
|
pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
|
|
|
int cc;
|
|
|
|
int n = 0;
|
|
|
|
register u_char *bp, *ep;
|
2004-12-14 23:55:30 +00:00
|
|
|
u_char *datap;
|
2003-11-22 00:06:05 +00:00
|
|
|
struct bpf_insn *fcode;
|
2004-12-14 23:33:57 +00:00
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
register int pad;
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
|
2003-11-22 00:06:05 +00:00
|
|
|
fcode = p->md.use_bpf ? NULL : p->fcode.bf_insns;
|
1999-10-07 23:46:40 +00:00
|
|
|
again:
|
2003-11-04 07:05:32 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
cc = p->cc;
|
|
|
|
if (p->cc == 0) {
|
|
|
|
cc = read(p->fd, (char *)p->buffer, p->bufsize);
|
|
|
|
if (cc < 0) {
|
|
|
|
/* Don't choke when we get ptraced */
|
|
|
|
switch (errno) {
|
|
|
|
|
|
|
|
case EINTR:
|
|
|
|
goto again;
|
|
|
|
|
2002-10-08 07:18:07 +00:00
|
|
|
#ifdef _AIX
|
|
|
|
case EFAULT:
|
|
|
|
/*
|
|
|
|
* Sigh. More AIX wonderfulness.
|
|
|
|
*
|
2003-04-17 06:35:34 +00:00
|
|
|
* 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
|
2002-10-08 07:18:07 +00:00
|
|
|
*
|
2003-04-17 06:35:34 +00:00
|
|
|
* In any case this means that we shouldn't
|
|
|
|
* treat EFAULT as a fatal error; as we
|
2002-10-08 07:18:07 +00:00
|
|
|
* 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
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
case EWOULDBLOCK:
|
|
|
|
return (0);
|
|
|
|
#if defined(sun) && !defined(BSD)
|
|
|
|
/*
|
|
|
|
* Due to a SunOS bug, after 2^31 bytes, the kernel
|
|
|
|
* file offset overflows and read fails with EINVAL.
|
|
|
|
* The lseek() to 0 will fix things.
|
|
|
|
*/
|
|
|
|
case EINVAL:
|
|
|
|
if (lseek(p->fd, 0L, SEEK_CUR) +
|
|
|
|
p->bufsize < 0) {
|
|
|
|
(void)lseek(p->fd, 0L, SEEK_SET);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
#endif
|
|
|
|
}
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
bp = p->buffer;
|
|
|
|
} else
|
|
|
|
bp = p->bp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through each packet.
|
|
|
|
*/
|
|
|
|
#define bhp ((struct bpf_hdr *)bp)
|
|
|
|
ep = bp + cc;
|
2004-12-14 23:33:57 +00:00
|
|
|
#ifdef PCAP_FDDIPAD
|
2004-12-15 00:25:08 +00:00
|
|
|
pad = p->fddipad;
|
2004-12-14 23:33:57 +00:00
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
while (bp < ep) {
|
2004-12-14 23:55:30 +00:00
|
|
|
register int caplen, hdrlen;
|
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 (p->break_loop) {
|
|
|
|
if (n == 0) {
|
|
|
|
p->break_loop = 0;
|
|
|
|
return (-2);
|
|
|
|
} else {
|
|
|
|
p->bp = bp;
|
|
|
|
p->cc = ep - bp;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
caplen = bhp->bh_caplen;
|
|
|
|
hdrlen = bhp->bh_hdrlen;
|
2004-12-14 23:55:30 +00:00
|
|
|
datap = bp + hdrlen;
|
1999-10-07 23:46:40 +00:00
|
|
|
/*
|
2003-11-22 00:06:05 +00:00
|
|
|
* Short-circuit evaluation: if using BPF filter
|
|
|
|
* in kernel, no need to do it now.
|
2004-12-14 23:55:30 +00:00
|
|
|
*
|
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
* Note: the filter code was generated assuming
|
2004-12-15 00:25:08 +00:00
|
|
|
* that p->fddipad was the amount of padding
|
2004-12-14 23:55:30 +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
|
|
|
*/
|
2003-11-22 00:06:05 +00:00
|
|
|
if (fcode == NULL ||
|
2004-12-14 23:55:30 +00:00
|
|
|
bpf_filter(fcode, datap, bhp->bh_datalen, caplen)) {
|
2004-12-14 23:33:57 +00:00
|
|
|
struct pcap_pkthdr pkthdr;
|
|
|
|
|
|
|
|
pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec;
|
2001-11-17 21:24:09 +00:00
|
|
|
#ifdef _AIX
|
2003-11-22 00:06:05 +00:00
|
|
|
/*
|
|
|
|
* AIX's BPF returns seconds/nanoseconds time
|
|
|
|
* stamps, not seconds/microseconds time stamps.
|
|
|
|
*/
|
2004-12-14 23:33:57 +00:00
|
|
|
pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec/1000;
|
|
|
|
#else
|
|
|
|
pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec;
|
2001-11-17 21:24:09 +00:00
|
|
|
#endif
|
2004-12-14 23:55:30 +00:00
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
if (caplen > pad)
|
|
|
|
pkthdr.caplen = caplen - pad;
|
|
|
|
else
|
|
|
|
pkthdr.caplen = 0;
|
|
|
|
if (bhp->bh_datalen > pad)
|
|
|
|
pkthdr.len = bhp->bh_datalen - pad;
|
|
|
|
else
|
|
|
|
pkthdr.len = 0;
|
|
|
|
datap += pad;
|
|
|
|
#else
|
2004-12-14 23:33:57 +00:00
|
|
|
pkthdr.caplen = caplen;
|
2004-12-14 23:55:30 +00:00
|
|
|
pkthdr.len = bhp->bh_datalen;
|
|
|
|
#endif
|
|
|
|
(*callback)(user, &pkthdr, datap);
|
|
|
|
bp += BPF_WORDALIGN(caplen + hdrlen);
|
2003-11-22 00:06:05 +00:00
|
|
|
if (++n >= cnt && cnt > 0) {
|
|
|
|
p->bp = bp;
|
|
|
|
p->cc = ep - bp;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Skip this packet.
|
|
|
|
*/
|
2004-12-14 23:55:30 +00:00
|
|
|
bp += BPF_WORDALIGN(caplen + hdrlen);
|
1999-10-07 23:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef bhp
|
|
|
|
p->cc = 0;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
|
2004-03-23 19:18:04 +00:00
|
|
|
static int
|
|
|
|
pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = write(p->fd, buf, size);
|
2004-10-05 07:23:39 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
if (ret == -1 && errno == EAFNOSUPPORT) {
|
|
|
|
/*
|
|
|
|
* In Mac OS X, there's a bug wherein setting the
|
|
|
|
* BIOCSHDRCMPLT flag causes writes to fail; see,
|
|
|
|
* for example:
|
|
|
|
*
|
|
|
|
* http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/BIOCSHDRCMPLT-10.3.3.patch
|
|
|
|
*
|
|
|
|
* So, if, on OS X, we get EAFNOSUPPORT from the write, we
|
|
|
|
* assume it's due to that bug, and turn off that flag
|
|
|
|
* and try again. If we succeed, it either means that
|
|
|
|
* somebody applied the fix from that URL, or other patches
|
|
|
|
* for that bug from
|
|
|
|
*
|
|
|
|
* http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/
|
|
|
|
*
|
|
|
|
* and are running a Darwin kernel with those fixes, or
|
|
|
|
* that Apple fixed the problem in some OS X release.
|
|
|
|
*/
|
|
|
|
u_int spoof_eth_src = 0;
|
|
|
|
|
|
|
|
if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) {
|
|
|
|
(void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"send: can't turn off BIOCSHDRCMPLT: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now try the write again.
|
|
|
|
*/
|
|
|
|
ret = write(p->fd, buf, size);
|
|
|
|
}
|
|
|
|
#endif /* __APPLE__ */
|
2004-03-23 19:18:04 +00:00
|
|
|
if (ret == -1) {
|
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
2003-02-11 01:46:05 +00:00
|
|
|
#ifdef _AIX
|
|
|
|
static int
|
|
|
|
bpf_odminit(char *errbuf)
|
|
|
|
{
|
2003-02-11 06:19:26 +00:00
|
|
|
char *errstr;
|
|
|
|
|
2003-02-11 01:46:05 +00:00
|
|
|
if (odm_initialize() == -1) {
|
2003-02-11 06:19:26 +00:00
|
|
|
if (odm_err_msg(odmerrno, &errstr) == -1)
|
|
|
|
errstr = "Unknown error";
|
2003-02-11 01:46:05 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"bpf_load: odm_initialize failed: %s",
|
2003-02-11 06:19:26 +00:00
|
|
|
errstr);
|
2003-02-11 01:46:05 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) {
|
2003-02-11 06:19:26 +00:00
|
|
|
if (odm_err_msg(odmerrno, &errstr) == -1)
|
|
|
|
errstr = "Unknown error";
|
2003-02-11 01:46:05 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s",
|
2003-02-11 06:19:26 +00:00
|
|
|
errstr);
|
2003-02-11 01:46:05 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bpf_odmcleanup(char *errbuf)
|
|
|
|
{
|
2003-02-11 06:19:26 +00:00
|
|
|
char *errstr;
|
|
|
|
|
2003-02-11 01:46:05 +00:00
|
|
|
if (odm_unlock(odmlockid) == -1) {
|
2003-02-11 06:19:26 +00:00
|
|
|
if (odm_err_msg(odmerrno, &errstr) == -1)
|
|
|
|
errstr = "Unknown error";
|
2003-02-11 01:46:05 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"bpf_load: odm_unlock failed: %s",
|
2003-02-11 06:19:26 +00:00
|
|
|
errstr);
|
2003-02-11 01:46:05 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2003-02-11 06:19:26 +00:00
|
|
|
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);
|
|
|
|
}
|
2003-02-11 01:46:05 +00:00
|
|
|
|
|
|
|
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",
|
2003-02-11 06:19:26 +00:00
|
|
|
buf, pcap_strerror(errno));
|
2003-02-11 01:46:05 +00:00
|
|
|
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);
|
2003-04-17 06:35:34 +00:00
|
|
|
if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) ||
|
2003-02-11 01:46:05 +00:00
|
|
|
(cfg_ld.kmid == 0)) {
|
|
|
|
/* Driver isn't loaded, load it now */
|
2003-02-11 06:19:26 +00:00
|
|
|
if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) {
|
2003-02-11 01:46:05 +00:00
|
|
|
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);
|
2003-02-11 06:19:26 +00:00
|
|
|
cfg_km.mdiptr = (void *)&cfg_bpf;
|
2003-02-11 01:46:05 +00:00
|
|
|
for (i = 0; i < BPF_MINORS; i++) {
|
|
|
|
cfg_bpf.devno = domakedev(major, i);
|
2003-02-11 06:19:26 +00:00
|
|
|
if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) {
|
2003-02-11 01:46:05 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"bpf_load: could not configure driver: %s",
|
|
|
|
strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bpfloadedflag = 1;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
static inline int
|
|
|
|
bpf_open(pcap_t *p, char *errbuf)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int n = 0;
|
2000-04-27 09:11:11 +00:00
|
|
|
char device[sizeof "/dev/bpf0000000000"];
|
1999-10-07 23:46:40 +00:00
|
|
|
|
2003-02-11 01:46:05 +00:00
|
|
|
#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
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Go through all the minors and find one that isn't in use.
|
|
|
|
*/
|
|
|
|
do {
|
2000-04-27 09:11:11 +00:00
|
|
|
(void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
|
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.
|
|
|
|
*/
|
|
|
|
fd = open(device, O_RDWR);
|
|
|
|
if (fd == -1 && errno == EACCES)
|
|
|
|
fd = open(device, O_RDONLY);
|
1999-10-07 23:46:40 +00:00
|
|
|
} while (fd < 0 && errno == EBUSY);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX better message for all minors used
|
|
|
|
*/
|
|
|
|
if (fd < 0)
|
2000-07-10 04:50:05 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
device, pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
return (fd);
|
|
|
|
}
|
|
|
|
|
2003-12-18 23:32:31 +00:00
|
|
|
/*
|
|
|
|
* We include the OS's <net/bpf.h>, not our "pcap-bpf.h", so we probably
|
|
|
|
* 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
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct bpf_version bv;
|
2002-12-19 09:05:45 +00:00
|
|
|
#ifdef BIOCGDLTLIST
|
|
|
|
struct bpf_dltlist bdl;
|
2004-03-24 07:00:41 +00:00
|
|
|
#endif
|
2004-10-05 07:23:39 +00:00
|
|
|
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
|
2004-03-24 07:00:41 +00:00
|
|
|
u_int spoof_eth_src = 1;
|
2002-12-19 09:05:45 +00:00
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
u_int v;
|
|
|
|
pcap_t *p;
|
2005-02-24 08:59:38 +00:00
|
|
|
struct bpf_insn total_insn;
|
|
|
|
struct bpf_program total_prog;
|
2003-11-21 10:19:33 +00:00
|
|
|
struct utsname osinfo;
|
1999-10-07 23:46:40 +00:00
|
|
|
|
2003-07-23 05:29:19 +00:00
|
|
|
#ifdef HAVE_DAG_API
|
|
|
|
if (strstr(device, "dag")) {
|
|
|
|
return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_DAG_API */
|
|
|
|
|
2002-12-19 09:05:45 +00:00
|
|
|
#ifdef BIOCGDLTLIST
|
2003-11-04 07:05:32 +00:00
|
|
|
memset(&bdl, 0, sizeof(bdl));
|
2002-12-19 09:05:45 +00:00
|
|
|
#endif
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
p = (pcap_t *)malloc(sizeof(*p));
|
|
|
|
if (p == NULL) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
2000-07-29 08:03:56 +00:00
|
|
|
memset(p, 0, sizeof(*p));
|
1999-10-07 23:46:40 +00:00
|
|
|
fd = bpf_open(p, ebuf);
|
|
|
|
if (fd < 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
p->fd = fd;
|
|
|
|
p->snapshot = snaplen;
|
|
|
|
|
|
|
|
if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (bv.bv_major != BPF_MAJOR_VERSION ||
|
|
|
|
bv.bv_minor < BPF_MINOR_VERSION) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"kernel bpf filter out of date");
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2000-07-11 23:00:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try finding a good size for the buffer; 32768 may be too
|
|
|
|
* big, so keep cutting it in half until we find a size
|
2003-02-25 21:58:48 +00:00
|
|
|
* that works, or run out of sizes to try. If the default
|
|
|
|
* is larger, don't make it smaller.
|
2000-07-11 23:02:51 +00:00
|
|
|
*
|
|
|
|
* XXX - there should be a user-accessible hook to set the
|
|
|
|
* initial buffer size.
|
2000-07-11 23:00:05 +00:00
|
|
|
*/
|
2003-02-25 21:58:48 +00:00
|
|
|
if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
|
|
|
|
v = 32768;
|
|
|
|
for ( ; v != 0; v >>= 1) {
|
2000-07-11 23:00:05 +00:00
|
|
|
/* Ignore the return value - this is because the call fails
|
|
|
|
* on BPF systems that don't have kernel malloc. And if
|
|
|
|
* the call fails, it's no big deal, we just continue to
|
|
|
|
* use the standard buffer size.
|
|
|
|
*/
|
|
|
|
(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
|
|
|
|
|
|
|
|
(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
|
|
|
|
if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
|
|
|
|
break; /* that size worked; we're done */
|
|
|
|
|
|
|
|
if (errno != ENOBUFS) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
|
|
|
|
device, pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
2000-07-11 23:02:51 +00:00
|
|
|
}
|
2000-07-11 23:00:05 +00:00
|
|
|
|
|
|
|
if (v == 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"BIOCSBLEN: %s: No buffer size worked", device);
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2000-07-11 23:00:05 +00:00
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/* Get the data link layer type. */
|
|
|
|
if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2001-11-17 21:24:09 +00:00
|
|
|
#ifdef _AIX
|
|
|
|
/*
|
|
|
|
* AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT.
|
|
|
|
*/
|
1999-10-19 15:18:28 +00:00
|
|
|
switch (v) {
|
2001-11-17 21:24:09 +00:00
|
|
|
|
|
|
|
case IFT_ETHER:
|
|
|
|
case IFT_ISO88023:
|
|
|
|
v = DLT_EN10MB;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IFT_FDDI:
|
|
|
|
v = DLT_FDDI;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IFT_ISO88025:
|
|
|
|
v = DLT_IEEE802;
|
|
|
|
break;
|
|
|
|
|
2003-03-28 08:08:11 +00:00
|
|
|
case IFT_LOOP:
|
|
|
|
v = DLT_NULL;
|
|
|
|
break;
|
|
|
|
|
2001-11-17 21:24:09 +00:00
|
|
|
default:
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
/*
|
2001-11-17 21:24:09 +00:00
|
|
|
* We don't know what to map this to yet.
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
*/
|
2002-05-31 10:59:43 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
|
2001-11-17 21:24:09 +00:00
|
|
|
v);
|
|
|
|
goto bad;
|
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
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _BSDI_VERSION - 0 >= 199510
|
|
|
|
/* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
|
|
|
|
switch (v) {
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
case DLT_SLIP:
|
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
|
|
|
v = DLT_SLIP_BSDOS;
|
1999-10-07 23:46:40 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DLT_PPP:
|
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
|
|
|
v = DLT_PPP_BSDOS;
|
1999-10-07 23:46:40 +00:00
|
|
|
break;
|
1999-10-19 15:18:28 +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
|
|
|
case 11: /*DLT_FR*/
|
2002-06-07 04:17:15 +00:00
|
|
|
v = DLT_FRELAY;
|
1999-10-19 15:18:28 +00:00
|
|
|
break;
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +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
|
|
|
case 12: /*DLT_C_HDLC*/
|
|
|
|
v = DLT_CHDLC;
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-12-15 00:25:08 +00:00
|
|
|
#endif
|
|
|
|
#ifdef PCAP_FDDIPAD
|
|
|
|
if (v == DLT_FDDI)
|
2005-04-12 20:47:43 +00:00
|
|
|
p->fddipad = PCAP_FDDIPAD;
|
2004-12-15 00:25:08 +00:00
|
|
|
else
|
|
|
|
p->fddipad = 0;
|
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
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
p->linktype = v;
|
|
|
|
|
2002-12-19 09:05:45 +00:00
|
|
|
#ifdef BIOCGDLTLIST
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2003-02-11 06:19:26 +00:00
|
|
|
if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) {
|
2003-12-18 23:32:31 +00:00
|
|
|
u_int i;
|
|
|
|
int is_ethernet;
|
|
|
|
|
2006-01-22 05:28:34 +00:00
|
|
|
bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * (bdl.bfl_len + 1));
|
2002-12-19 09:05:45 +00:00
|
|
|
if (bdl.bfl_list == NULL) {
|
|
|
|
(void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2003-02-11 06:19:26 +00:00
|
|
|
if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) {
|
2002-12-19 09:05:45 +00:00
|
|
|
(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"BIOCGDLTLIST: %s", pcap_strerror(errno));
|
2003-12-18 23:32:31 +00:00
|
|
|
free(bdl.bfl_list);
|
2002-12-19 09:05:45 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2003-12-18 23:32:31 +00:00
|
|
|
/*
|
|
|
|
* OK, for real Ethernet devices, add DLT_DOCSIS to the
|
|
|
|
* list, 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).
|
|
|
|
*
|
|
|
|
* A "real Ethernet device" is defined here as a device
|
|
|
|
* that has a link-layer type of DLT_EN10MB and that has
|
|
|
|
* no alternate link-layer types; that's done to exclude
|
|
|
|
* 802.11 interfaces (which might or might not be the
|
|
|
|
* right thing to do, but I suspect it is - Ethernet <->
|
|
|
|
* 802.11 bridges would probably badly mishandle frames
|
|
|
|
* that don't have Ethernet headers).
|
|
|
|
*/
|
|
|
|
if (p->linktype == DLT_EN10MB) {
|
2003-12-24 08:26:24 +00:00
|
|
|
is_ethernet = 1;
|
2003-12-18 23:32:31 +00:00
|
|
|
for (i = 0; i < bdl.bfl_len; i++) {
|
2004-06-05 00:42:13 +00:00
|
|
|
if (bdl.bfl_list[i] != DLT_EN10MB) {
|
2003-12-24 08:26:24 +00:00
|
|
|
is_ethernet = 0;
|
2003-12-18 23:32:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_ethernet) {
|
|
|
|
/*
|
|
|
|
* We reserved one more slot at the end of
|
|
|
|
* the list.
|
|
|
|
*/
|
|
|
|
bdl.bfl_list[bdl.bfl_len] = DLT_DOCSIS;
|
|
|
|
bdl.bfl_len++;
|
|
|
|
}
|
|
|
|
}
|
2002-12-19 09:05:45 +00:00
|
|
|
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
|
|
|
|
|
2003-12-18 23:32:31 +00:00
|
|
|
/*
|
|
|
|
* If this is an Ethernet device, and we don't have a DLT_ list,
|
|
|
|
* give it a list with DLT_EN10MB and DLT_DOCSIS. (That'd give
|
|
|
|
* 802.11 interfaces DLT_DOCSIS, which isn't the right thing to
|
|
|
|
* do, but there's not much we can do about that without finding
|
|
|
|
* some other way of determining whether it's an Ethernet or 802.11
|
|
|
|
* device.)
|
|
|
|
*/
|
|
|
|
if (p->linktype == DLT_EN10MB && p->dlt_count == 0) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-05 07:23:39 +00:00
|
|
|
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
|
2004-03-24 07:00:41 +00:00
|
|
|
/*
|
|
|
|
* Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so
|
|
|
|
* the link-layer source address isn't forcibly overwritten.
|
|
|
|
* (Should we ignore errors? Should we do this only if
|
|
|
|
* we're open for writing?)
|
|
|
|
*
|
|
|
|
* XXX - I seem to remember some packet-sending bug in some
|
|
|
|
* BSDs - check CVS log for "bpf.c"?
|
|
|
|
*/
|
|
|
|
if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) {
|
|
|
|
(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"BIOCSHDRCMPLT: %s", pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
/* set timeout */
|
|
|
|
if (to_ms != 0) {
|
2002-08-03 20:26:14 +00:00
|
|
|
/*
|
|
|
|
* XXX - is this seconds/nanoseconds in AIX?
|
|
|
|
* (Treating it as such doesn't fix the timeout
|
|
|
|
* problem described below.)
|
|
|
|
*/
|
1999-10-07 23:46:40 +00:00
|
|
|
struct timeval to;
|
|
|
|
to.tv_sec = to_ms / 1000;
|
|
|
|
to.tv_usec = (to_ms * 1000) % 1000000;
|
|
|
|
if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
2000-07-10 04:50:05 +00:00
|
|
|
|
2000-07-14 06:25:49 +00:00
|
|
|
#ifdef _AIX
|
2000-07-10 04:50:05 +00:00
|
|
|
#ifdef BIOCIMMEDIATE
|
2000-07-14 06:25:49 +00:00
|
|
|
/*
|
|
|
|
* 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.)
|
|
|
|
*/
|
2000-07-10 04:50:05 +00:00
|
|
|
v = 1;
|
|
|
|
if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
#endif /* BIOCIMMEDIATE */
|
2000-07-14 06:25:49 +00:00
|
|
|
#endif /* _AIX */
|
2000-07-10 04:50:05 +00:00
|
|
|
|
2001-04-30 16:10:51 +00:00
|
|
|
if (promisc) {
|
1999-10-07 23:46:40 +00:00
|
|
|
/* set promiscuous mode, okay if it fails */
|
2001-04-30 16:10:51 +00:00
|
|
|
if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
p->bufsize = v;
|
|
|
|
p->buffer = (u_char *)malloc(p->bufsize);
|
|
|
|
if (p->buffer == NULL) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2003-04-17 06:35:34 +00:00
|
|
|
#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
|
1999-10-07 23:46:40 +00:00
|
|
|
|
2005-02-24 08:59:38 +00:00
|
|
|
/*
|
|
|
|
* If there's no filter program installed, there's
|
|
|
|
* no indication to the kernel of what the snapshot
|
|
|
|
* length should be, so no snapshotting is done.
|
|
|
|
*
|
|
|
|
* Therefore, when we open the device, we install
|
|
|
|
* an "accept everything" filter with the specified
|
|
|
|
* snapshot length.
|
|
|
|
*/
|
|
|
|
total_insn.code = (u_short)(BPF_RET | BPF_K);
|
|
|
|
total_insn.jt = 0;
|
|
|
|
total_insn.jf = 0;
|
|
|
|
total_insn.k = snaplen;
|
|
|
|
|
|
|
|
total_prog.bf_len = 1;
|
|
|
|
total_prog.bf_insns = &total_insn;
|
|
|
|
if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2003-11-21 10:19:33 +00:00
|
|
|
/*
|
|
|
|
* 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?
|
|
|
|
*/
|
2005-06-04 02:53:16 +00:00
|
|
|
p->selectable_fd = p->fd; /* assume select() works until we know otherwise */
|
2003-11-21 10:19:33 +00:00
|
|
|
if (uname(&osinfo) == 0) {
|
|
|
|
/*
|
|
|
|
* We can check what OS this is.
|
|
|
|
*/
|
2005-06-04 02:53:16 +00:00
|
|
|
if (strcmp(osinfo.sysname, "FreeBSD") == 0) {
|
|
|
|
if (strncmp(osinfo.release, "4.3-", 4) == 0 ||
|
|
|
|
strncmp(osinfo.release, "4.4-", 4) == 0)
|
|
|
|
p->selectable_fd = -1;
|
|
|
|
}
|
2003-11-21 10:19:33 +00:00
|
|
|
}
|
|
|
|
|
2003-07-25 05:32:02 +00:00
|
|
|
p->read_op = pcap_read_bpf;
|
2004-03-23 19:18:04 +00:00
|
|
|
p->inject_op = pcap_inject_bpf;
|
2003-07-25 04:42:02 +00:00
|
|
|
p->setfilter_op = pcap_setfilter_bpf;
|
2005-05-03 18:54:33 +00:00
|
|
|
p->setdirection_op = pcap_setdirection_bpf;
|
2003-07-25 05:07:01 +00:00
|
|
|
p->set_datalink_op = pcap_set_datalink_bpf;
|
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_bpf;
|
2004-10-19 07:06:11 +00:00
|
|
|
p->close_op = pcap_close_common;
|
2003-07-25 03:25:45 +00:00
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
return (p);
|
|
|
|
bad:
|
|
|
|
(void)close(fd);
|
2003-12-18 23:32:31 +00:00
|
|
|
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)
|
|
|
|
{
|
2003-07-23 05:29:19 +00:00
|
|
|
#ifdef HAVE_DAG_API
|
|
|
|
if (dag_platform_finddevs(alldevsp, errbuf) < 0)
|
|
|
|
return (-1);
|
|
|
|
#endif /* HAVE_DAG_API */
|
|
|
|
|
2002-07-11 09:06:30 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-07-25 04:42:02 +00:00
|
|
|
static int
|
|
|
|
pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp)
|
1999-10-07 23:46:40 +00:00
|
|
|
{
|
1999-10-19 15:18:28 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2000-10-28 00:01:26 +00:00
|
|
|
if (no_optimize) {
|
2003-11-22 00:06:05 +00:00
|
|
|
/*
|
|
|
|
* XXX - what if we already have a filter in the kernel?
|
|
|
|
*/
|
2000-10-28 00:01:26 +00:00
|
|
|
if (install_bpf_program(p, fp) < 0)
|
|
|
|
return (-1);
|
2003-11-22 00:06:05 +00:00
|
|
|
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) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
2003-11-22 00:06:05 +00:00
|
|
|
p->md.use_bpf = 1; /* filtering in the kernel */
|
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;
|
1999-10-07 23:46:40 +00:00
|
|
|
return (0);
|
|
|
|
}
|
2002-12-19 09:05:45 +00:00
|
|
|
|
2005-05-03 18:54:33 +00:00
|
|
|
/*
|
|
|
|
* Set direction flag: Which packets do we accept on a forwarding
|
|
|
|
* single device? IN, OUT or both?
|
|
|
|
*/
|
|
|
|
static int
|
2005-07-07 02:04:33 +00:00
|
|
|
pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
|
2005-05-03 18:54:33 +00:00
|
|
|
{
|
|
|
|
#ifdef BIOCSSEESENT
|
|
|
|
u_int seesent;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
2005-07-07 02:04:33 +00:00
|
|
|
* We don't support PCAP_D_OUT.
|
2005-05-03 18:54:33 +00:00
|
|
|
*/
|
2005-07-07 02:04:33 +00:00
|
|
|
if (d == PCAP_D_OUT) {
|
2005-05-03 18:54:33 +00:00
|
|
|
snprintf(p->errbuf, sizeof(p->errbuf),
|
2005-07-07 02:04:33 +00:00
|
|
|
"Setting direction to PCAP_D_OUT is not supported on BPF");
|
2005-05-03 18:54:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#ifdef BIOCSSEESENT
|
2005-07-07 02:04:33 +00:00
|
|
|
seesent = (d == PCAP_D_INOUT);
|
2005-05-03 18:54:33 +00:00
|
|
|
if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) {
|
|
|
|
(void) snprintf(p->errbuf, sizeof(p->errbuf),
|
|
|
|
"Cannot set direction to %s: %s",
|
2005-07-07 02:04:33 +00:00
|
|
|
(d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN",
|
2005-05-03 18:54:33 +00:00
|
|
|
strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
#else
|
|
|
|
(void) snprintf(p->errbuf, sizeof(p->errbuf),
|
|
|
|
"This system doesn't support BIOCSSEESENT, so the direction can't be set");
|
|
|
|
return (-1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-07-25 05:07:01 +00:00
|
|
|
static int
|
|
|
|
pcap_set_datalink_bpf(pcap_t *p, int dlt)
|
2002-12-19 09:05:45 +00:00
|
|
|
{
|
|
|
|
#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);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return (0);
|
|
|
|
}
|