📄 pcap-bpf.c
字号:
/* * 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 lintstatic const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.86.2.9 2006/01/22 05:28:34 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#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>#include <sys/utsname.h>#include <net/if.h>#ifdef _AIX/* * Make "pcap.h" not include "pcap-bpf.h"; we are going to include the * native OS version, as we need "struct bpf_config" from it. */#define PCAP_DONT_INCLUDE_PCAP_BPF_H#include <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#include <net/if_types.h> /* for IFT_ values */#include <sys/sysconfig.h>#include <sys/device.h>#include <sys/cfgodm.h>#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 */#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"#ifdef HAVE_DAG_API#include "pcap-dag.h"#endif /* HAVE_DAG_API */#ifdef HAVE_OS_PROTO_H#include "os-proto.h"#endif#ifdef HAVE_REMOTE#include <pcap-remote.h>#endif /* HAVE_REMOTE */#include "gencode.h" /* for "no_optimize" */static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp);static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t);static int pcap_set_datalink_bpf(pcap_t *p, int dlt);static intpcap_stats_bpf(pcap_t *p, struct pcap_stat *ps){ struct bpf_stat s; /* * "ps_recv" counts packets handed to the filter, not packets * that passed the filter. This includes packets later dropped * because we ran out of buffer space. * * "ps_drop" counts packets dropped inside the BPF device * because we ran out of buffer space. It doesn't count * packets dropped by the interface driver. It counts * only packets that passed the filter. * * Both statistics include packets not yet read from the kernel * by libpcap, and thus not yet seen by the application. */ if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", pcap_strerror(errno)); return (-1); } ps->ps_recv = s.bs_recv; ps->ps_drop = s.bs_drop; return (0);}static intpcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user){ int cc; int n = 0; register u_char *bp, *ep; u_char *datap; struct bpf_insn *fcode;#ifdef PCAP_FDDIPAD register int pad;#endif fcode = p->md.use_bpf ? NULL : p->fcode.bf_insns; again: /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that it * has, and return -2 to indicate that we were * told to break out of the loop. */ p->break_loop = 0; return (-2); } cc = p->cc; if (p->cc == 0) { cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { case EINTR: goto again;#ifdef _AIX case EFAULT: /* * Sigh. More AIX wonderfulness. * * For some unknown reason the uiomove() * operation in the bpf kernel extension * used to copy the buffer into user * space sometimes returns EFAULT. I have * no idea why this is the case given that * a kernel debugger shows the user buffer * is correct. This problem appears to * be mostly mitigated by the memset of * the buffer before it is first used. * Very strange.... Shaun Clowes * * In any case this means that we shouldn't * treat EFAULT as a fatal error; as we * don't have an API for returning * a "some packets were dropped since * the last packet you saw" indication, * we just ignore EFAULT and keep reading. */ goto again;#endif case EWOULDBLOCK: return (0);#if defined(sun) && !defined(BSD) /* * 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 } snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", pcap_strerror(errno)); return (-1); } bp = p->buffer; } else bp = p->bp; /* * Loop through each packet. */#define bhp ((struct bpf_hdr *)bp) ep = bp + cc;#ifdef PCAP_FDDIPAD pad = p->fddipad;#endif while (bp < ep) { register int caplen, hdrlen; /* * Has "pcap_breakloop()" been called? * If so, return immediately - if we haven't read any * packets, clear the flag and return -2 to indicate * that we were told to break out of the loop, otherwise * leave the flag set, so that the *next* call will break * out of the loop without having read any packets, and * return the number of packets we've processed so far. */ if (p->break_loop) { if (n == 0) { p->break_loop = 0; return (-2); } else { p->bp = bp; p->cc = ep - bp; return (n); } } caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; datap = bp + hdrlen; /* * Short-circuit evaluation: if using BPF filter * in kernel, no need to do it now. *#ifdef PCAP_FDDIPAD * Note: the filter code was generated assuming * that p->fddipad was the amount of padding * before the header, as that's what's required * in the kernel, so we run the filter before * skipping that padding.#endif */ if (fcode == NULL || bpf_filter(fcode, datap, bhp->bh_datalen, caplen)) { struct pcap_pkthdr pkthdr; pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec;#ifdef _AIX /* * AIX's BPF returns seconds/nanoseconds time * stamps, not seconds/microseconds time stamps. */ pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec/1000;#else pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec;#endif#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 pkthdr.caplen = caplen; pkthdr.len = bhp->bh_datalen;#endif (*callback)(user, &pkthdr, datap); bp += BPF_WORDALIGN(caplen + hdrlen); if (++n >= cnt && cnt > 0) { p->bp = bp; p->cc = ep - bp; return (n); } } else { /* * Skip this packet. */ bp += BPF_WORDALIGN(caplen + hdrlen); } }#undef bhp p->cc = 0; return (n);}static intpcap_inject_bpf(pcap_t *p, const void *buf, size_t size){ int ret; ret = write(p->fd, buf, size);#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__ */ if (ret == -1) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", pcap_strerror(errno)); return (-1); } return (ret);}#ifdef _AIXstatic int bpf_odminit(char *errbuf){ char *errstr; if (odm_initialize() == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error"; snprintf(errbuf, PCAP_ERRBUF_SIZE, "bpf_load: odm_initialize failed: %s", errstr); return (-1); } if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { if (odm_err_msg(odmerrno, &errstr) == -1) errstr = "Unknown error";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -