pcap-pf.c revision 98530
117683Spst/* 217683Spst * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 317683Spst * The Regents of the University of California. All rights reserved. 417683Spst * 517683Spst * Redistribution and use in source and binary forms, with or without 617683Spst * modification, are permitted provided that: (1) source code distributions 717683Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817683Spst * distributions including binary code include the above copyright notice and 917683Spst * this paragraph in its entirety in the documentation or other materials 1017683Spst * provided with the distribution, and (3) all advertising materials mentioning 1117683Spst * features or use of this software display the following acknowledgement: 1217683Spst * ``This product includes software developed by the University of California, 1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417683Spst * the University nor the names of its contributors may be used to endorse 1517683Spst * or promote products derived from this software without specific prior 1617683Spst * written permission. 1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2026175Sfenner * 2126175Sfenner * packet filter subroutines for tcpdump 2226175Sfenner * Extraction/creation by Jeffrey Mogul, DECWRL 2317683Spst */ 2426175Sfenner 2517683Spst#ifndef lint 2626175Sfennerstatic const char rcsid[] = 2798530Sfenner "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.65 2001/12/10 07:14:19 guy Exp $ (LBL)"; 2817683Spst#endif 2917683Spst 3075107Sfenner#ifdef HAVE_CONFIG_H 3175107Sfenner#include "config.h" 3275107Sfenner#endif 3375107Sfenner 3417683Spst#include <sys/types.h> 3517683Spst#include <sys/time.h> 3617683Spst#include <sys/timeb.h> 3717683Spst#include <sys/socket.h> 3817683Spst#include <sys/file.h> 3917683Spst#include <sys/ioctl.h> 4017683Spst#include <net/pfilt.h> 4117683Spst 4217683Spststruct mbuf; 4317683Spststruct rtentry; 4417683Spst#include <net/if.h> 4517683Spst 4617683Spst#include <netinet/in.h> 4717683Spst#include <netinet/in_systm.h> 4817683Spst#include <netinet/ip.h> 4917683Spst#include <netinet/if_ether.h> 5017683Spst#include <netinet/ip_var.h> 5117683Spst#include <netinet/udp.h> 5217683Spst#include <netinet/udp_var.h> 5317683Spst#include <netinet/tcp.h> 5417683Spst#include <netinet/tcpip.h> 5517683Spst 5617683Spst#include <ctype.h> 5717683Spst#include <errno.h> 5817683Spst#include <netdb.h> 5917683Spst#include <stdio.h> 6017683Spst#include <stdlib.h> 6117683Spst#include <string.h> 6217683Spst#include <unistd.h> 6317683Spst 6417683Spst#include "pcap-int.h" 6517683Spst 6617683Spst#ifdef HAVE_OS_PROTO_H 6717683Spst#include "os-proto.h" 6817683Spst#endif 6917683Spst 7017683Spst/* 7117683Spst * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump 7217683Spst * applications aren't going to need more than 200 bytes of packet header 7317683Spst * and the read shouldn't return more packets than packetfilter's internal 7417683Spst * queue limit (bounded at 256). 7517683Spst */ 7617683Spst#define BUFSPACE (200 * 256) 7717683Spst 7817683Spstint 7917683Spstpcap_read(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) 8017683Spst{ 8117683Spst register u_char *p, *bp; 8217683Spst struct bpf_insn *fcode; 8317683Spst register int cc, n, buflen, inc; 8417683Spst register struct enstamp *sp; 8517683Spst#ifdef LBL_ALIGN 8617683Spst struct enstamp stamp; 8717683Spst#endif 8817683Spst#ifdef PCAP_FDDIPAD 8917683Spst register int pad; 9017683Spst#endif 9117683Spst 9217683Spst fcode = pc->md.use_bpf ? NULL : pc->fcode.bf_insns; 9317683Spst again: 9417683Spst cc = pc->cc; 9517683Spst if (cc == 0) { 9617683Spst cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); 9717683Spst if (cc < 0) { 9817683Spst if (errno == EWOULDBLOCK) 9917683Spst return (0); 10017683Spst if (errno == EINVAL && 10117683Spst lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { 10217683Spst /* 10317683Spst * Due to a kernel bug, after 2^31 bytes, 10417683Spst * the kernel file offset overflows and 10517683Spst * read fails with EINVAL. The lseek() 10617683Spst * to 0 will fix things. 10717683Spst */ 10817683Spst (void)lseek(pc->fd, 0L, SEEK_SET); 10917683Spst goto again; 11017683Spst } 11175107Sfenner snprintf(pc->errbuf, sizeof(pc->errbuf), "pf read: %s", 11217683Spst pcap_strerror(errno)); 11317683Spst return (-1); 11417683Spst } 11517683Spst bp = pc->buffer + pc->offset; 11617683Spst } else 11717683Spst bp = pc->bp; 11817683Spst /* 11917683Spst * Loop through each packet. 12017683Spst */ 12117683Spst n = 0; 12217683Spst#ifdef PCAP_FDDIPAD 12317683Spst if (pc->linktype == DLT_FDDI) 12417683Spst pad = pcap_fddipad; 12517683Spst else 12617683Spst pad = 0; 12717683Spst#endif 12817683Spst while (cc > 0) { 12917683Spst if (cc < sizeof(*sp)) { 13075107Sfenner snprintf(pc->errbuf, sizeof(pc->errbuf), 13175107Sfenner "pf short read (%d)", cc); 13217683Spst return (-1); 13317683Spst } 13417683Spst#ifdef LBL_ALIGN 13517683Spst if ((long)bp & 3) { 13617683Spst sp = &stamp; 13717683Spst memcpy((char *)sp, (char *)bp, sizeof(*sp)); 13817683Spst } else 13917683Spst#endif 14017683Spst sp = (struct enstamp *)bp; 14117683Spst if (sp->ens_stamplen != sizeof(*sp)) { 14275107Sfenner snprintf(pc->errbuf, sizeof(pc->errbuf), 14375107Sfenner "pf short stamplen (%d)", 14417683Spst sp->ens_stamplen); 14517683Spst return (-1); 14617683Spst } 14717683Spst 14817683Spst p = bp + sp->ens_stamplen; 14917683Spst buflen = sp->ens_count; 15017683Spst if (buflen > pc->snapshot) 15117683Spst buflen = pc->snapshot; 15217683Spst 15317683Spst /* Calculate inc before possible pad update */ 15417683Spst inc = ENALIGN(buflen + sp->ens_stamplen); 15517683Spst cc -= inc; 15617683Spst bp += inc; 15717683Spst#ifdef PCAP_FDDIPAD 15817683Spst p += pad; 15917683Spst buflen -= pad; 16017683Spst#endif 16117683Spst pc->md.TotPkts++; 16217683Spst pc->md.TotDrops += sp->ens_dropped; 16317683Spst pc->md.TotMissed = sp->ens_ifoverflows; 16417683Spst if (pc->md.OrigMissed < 0) 16517683Spst pc->md.OrigMissed = pc->md.TotMissed; 16617683Spst 16717683Spst /* 16817683Spst * Short-circuit evaluation: if using BPF filter 16917683Spst * in kernel, no need to do it now. 17017683Spst */ 17117683Spst if (fcode == NULL || 17217683Spst bpf_filter(fcode, p, sp->ens_count, buflen)) { 17317683Spst struct pcap_pkthdr h; 17417683Spst pc->md.TotAccepted++; 17517683Spst h.ts = sp->ens_tstamp; 17617683Spst#ifdef PCAP_FDDIPAD 17717683Spst h.len = sp->ens_count - pad; 17817683Spst#else 17917683Spst h.len = sp->ens_count; 18017683Spst#endif 18117683Spst h.caplen = buflen; 18217683Spst (*callback)(user, &h, p); 18317683Spst if (++n >= cnt && cnt > 0) { 18417683Spst pc->cc = cc; 18517683Spst pc->bp = bp; 18617683Spst return (n); 18717683Spst } 18817683Spst } 18917683Spst } 19017683Spst pc->cc = 0; 19117683Spst return (n); 19217683Spst} 19317683Spst 19417683Spstint 19517683Spstpcap_stats(pcap_t *p, struct pcap_stat *ps) 19617683Spst{ 19717683Spst 19898530Sfenner /* 19998530Sfenner * If packet filtering is being done in the kernel: 20098530Sfenner * 20198530Sfenner * "ps_recv" counts only packets that passed the filter. 20298530Sfenner * This does not include packets dropped because we 20398530Sfenner * ran out of buffer space. (XXX - perhaps it should, 20498530Sfenner * by adding "ps_drop" to "ps_recv", for compatibility 20598530Sfenner * with some other platforms. On the other hand, on 20698530Sfenner * some platforms "ps_recv" counts only packets that 20798530Sfenner * passed the filter, and on others it counts packets 20898530Sfenner * that didn't pass the filter....) 20998530Sfenner * 21098530Sfenner * "ps_drop" counts packets that passed the kernel filter 21198530Sfenner * (if any) but were dropped because the input queue was 21298530Sfenner * full. 21398530Sfenner * 21498530Sfenner * "ps_ifdrop" counts packets dropped by the network 21598530Sfenner * inteface (regardless of whether they would have passed 21698530Sfenner * the input filter, of course). 21798530Sfenner * 21898530Sfenner * If packet filtering is not being done in the kernel: 21998530Sfenner * 22098530Sfenner * "ps_recv" counts only packets that passed the filter. 22198530Sfenner * 22298530Sfenner * "ps_drop" counts packets that were dropped because the 22398530Sfenner * input queue was full, regardless of whether they passed 22498530Sfenner * the userland filter. 22598530Sfenner * 22698530Sfenner * "ps_ifdrop" counts packets dropped by the network 22798530Sfenner * inteface (regardless of whether they would have passed 22898530Sfenner * the input filter, of course). 22998530Sfenner * 23098530Sfenner * These statistics don't include packets not yet read from 23198530Sfenner * the kernel by libpcap, but they may include packets not 23298530Sfenner * yet read from libpcap by the application. 23398530Sfenner */ 23417683Spst ps->ps_recv = p->md.TotAccepted; 23517683Spst ps->ps_drop = p->md.TotDrops; 23617683Spst ps->ps_ifdrop = p->md.TotMissed - p->md.OrigMissed; 23717683Spst return (0); 23817683Spst} 23917683Spst 24017683Spstpcap_t * 24117683Spstpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 24217683Spst{ 24317683Spst pcap_t *p; 24417683Spst short enmode; 24517683Spst int backlog = -1; /* request the most */ 24617683Spst struct enfilter Filter; 24717683Spst struct endevp devparams; 24817683Spst 24917683Spst p = (pcap_t *)malloc(sizeof(*p)); 25017683Spst if (p == NULL) { 25175107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, 25275107Sfenner "pcap_open_live: %s", pcap_strerror(errno)); 25317683Spst return (0); 25417683Spst } 25575107Sfenner memset(p, 0, sizeof(*p)); 25617683Spst p->fd = pfopen(device, O_RDONLY); 25717683Spst if (p->fd < 0) { 25875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\ 25917683Spstyour system may not be properly configured; see \"man packetfilter(4)\"\n", 26017683Spst device, pcap_strerror(errno)); 26117683Spst goto bad; 26217683Spst } 26317683Spst p->md.OrigMissed = -1; 26417683Spst enmode = ENTSTAMP|ENBATCH|ENNONEXCL; 26517683Spst if (promisc) 26617683Spst enmode |= ENPROMISC; 26717683Spst if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { 26875107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s", 26975107Sfenner pcap_strerror(errno)); 27017683Spst goto bad; 27117683Spst } 27217683Spst#ifdef ENCOPYALL 27317683Spst /* Try to set COPYALL mode so that we see packets to ourself */ 27417683Spst enmode = ENCOPYALL; 27517683Spst (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ 27617683Spst#endif 27717683Spst /* set the backlog */ 27817683Spst if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { 27975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s", 28075107Sfenner pcap_strerror(errno)); 28117683Spst goto bad; 28217683Spst } 28317683Spst /* discover interface type */ 28417683Spst if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { 28575107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s", 28675107Sfenner pcap_strerror(errno)); 28717683Spst goto bad; 28817683Spst } 28917683Spst /* HACK: to compile prior to Ultrix 4.2 */ 29017683Spst#ifndef ENDT_FDDI 29117683Spst#define ENDT_FDDI 4 29217683Spst#endif 29317683Spst switch (devparams.end_dev_type) { 29417683Spst 29517683Spst case ENDT_10MB: 29617683Spst p->linktype = DLT_EN10MB; 29717683Spst p->offset = 2; 29817683Spst break; 29917683Spst 30017683Spst case ENDT_FDDI: 30117683Spst p->linktype = DLT_FDDI; 30217683Spst break; 30317683Spst 30498530Sfenner#ifdef ENDT_SLIP 30598530Sfenner case ENDT_SLIP: 30698530Sfenner p->linktype = DLT_SLIP; 30798530Sfenner break; 30898530Sfenner#endif 30998530Sfenner 31098530Sfenner#ifdef ENDT_PPP 31198530Sfenner case ENDT_PPP: 31298530Sfenner p->linktype = DLT_PPP; 31398530Sfenner break; 31498530Sfenner#endif 31598530Sfenner 31698530Sfenner#ifdef ENDT_LOOPBACK 31798530Sfenner case ENDT_LOOPBACK: 31817683Spst /* 31998530Sfenner * It appears to use Ethernet framing, at least on 32098530Sfenner * Digital UNIX 4.0. 32117683Spst */ 32217683Spst p->linktype = DLT_EN10MB; 32317683Spst p->offset = 2; 32417683Spst break; 32598530Sfenner#endif 32698530Sfenner 32798530Sfenner#ifdef ENDT_TRN 32898530Sfenner case ENDT_TRN: 32998530Sfenner p->linktype = DLT_IEEE802; 33098530Sfenner break; 33198530Sfenner#endif 33298530Sfenner 33398530Sfenner default: 33498530Sfenner /* 33598530Sfenner * XXX - what about ENDT_IEEE802? The pfilt.h header 33698530Sfenner * file calls this "IEEE 802 networks (non-Ethernet)", 33798530Sfenner * but that doesn't specify a specific link layer type; 33898530Sfenner * it could be 802.4, or 802.5 (except that 802.5 is 33998530Sfenner * ENDT_TRN), or 802.6, or 802.11, or.... That's why 34098530Sfenner * DLT_IEEE802 was hijacked to mean Token Ring in various 34198530Sfenner * BSDs, and why we went along with that hijacking. 34298530Sfenner * 34398530Sfenner * XXX - what about ENDT_HDLC and ENDT_NULL? 34498530Sfenner * Presumably, as ENDT_OTHER is just "Miscellaneous 34598530Sfenner * framing", there's not much we can do, as that 34698530Sfenner * doesn't specify a particular type of header. 34798530Sfenner */ 34898530Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown data-link type %lu", 34998530Sfenner devparams.end_dev_type); 35098530Sfenner goto bad; 35117683Spst } 35217683Spst /* set truncation */ 35317683Spst#ifdef PCAP_FDDIPAD 35417683Spst if (p->linktype == DLT_FDDI) 35517683Spst /* packetfilter includes the padding in the snapshot */ 35617683Spst snaplen += pcap_fddipad; 35717683Spst#endif 35817683Spst if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&snaplen) < 0) { 35975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s", 36075107Sfenner pcap_strerror(errno)); 36117683Spst goto bad; 36217683Spst } 36317683Spst p->snapshot = snaplen; 36417683Spst /* accept all packets */ 36575107Sfenner memset(&Filter, 0, sizeof(Filter)); 36617683Spst Filter.enf_Priority = 37; /* anything > 2 */ 36717683Spst Filter.enf_FilterLen = 0; /* means "always true" */ 36817683Spst if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { 36975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s", 37075107Sfenner pcap_strerror(errno)); 37117683Spst goto bad; 37217683Spst } 37317683Spst 37417683Spst if (to_ms != 0) { 37517683Spst struct timeval timeout; 37617683Spst timeout.tv_sec = to_ms / 1000; 37717683Spst timeout.tv_usec = (to_ms * 1000) % 1000000; 37817683Spst if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { 37975107Sfenner snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s", 38017683Spst pcap_strerror(errno)); 38117683Spst goto bad; 38217683Spst } 38317683Spst } 38417683Spst p->bufsize = BUFSPACE; 38517683Spst p->buffer = (u_char*)malloc(p->bufsize + p->offset); 38617683Spst 38717683Spst return (p); 38817683Spst bad: 38998530Sfenner if (p->fd >= 0) 39098530Sfenner close(p->fd); 39117683Spst free(p); 39217683Spst return (NULL); 39317683Spst} 39417683Spst 39517683Spstint 39617683Spstpcap_setfilter(pcap_t *p, struct bpf_program *fp) 39717683Spst{ 39817683Spst /* 39917683Spst * See if BIOCSETF works. If it does, the kernel supports 40017683Spst * BPF-style filters, and we do not need to do post-filtering. 40117683Spst */ 40217683Spst p->md.use_bpf = (ioctl(p->fd, BIOCSETF, (caddr_t)fp) >= 0); 40317683Spst if (p->md.use_bpf) { 40417683Spst struct bpf_version bv; 40517683Spst 40617683Spst if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) < 0) { 40775107Sfenner snprintf(p->errbuf, sizeof(p->errbuf), 40875107Sfenner "BIOCVERSION: %s", pcap_strerror(errno)); 40917683Spst return (-1); 41017683Spst } 41117683Spst else if (bv.bv_major != BPF_MAJOR_VERSION || 41217683Spst bv.bv_minor < BPF_MINOR_VERSION) { 41317683Spst fprintf(stderr, 41417683Spst "requires bpf language %d.%d or higher; kernel is %d.%d", 41517683Spst BPF_MAJOR_VERSION, BPF_MINOR_VERSION, 41617683Spst bv.bv_major, bv.bv_minor); 41717683Spst /* don't give up, just be inefficient */ 41817683Spst p->md.use_bpf = 0; 41917683Spst } 42075107Sfenner } else { 42175107Sfenner if (install_bpf_program(p, fp) < 0) 42275107Sfenner return (-1); 42375107Sfenner } 42417683Spst 42517683Spst /*XXX this goes in tcpdump*/ 42617683Spst if (p->md.use_bpf) 42717683Spst fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); 42817683Spst else 42917683Spst fprintf(stderr, "tcpdump: Filtering in user process\n"); 43017683Spst return (0); 43117683Spst} 432