1 /* 2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 * 21 * packet filter subroutines for tcpdump 22 * Extraction/creation by Jeffrey Mogul, DECWRL 23 */ 24 25 #ifndef lint 26 static const char rcsid[] = 27 "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.65 2001/12/10 07:14:19 guy Exp $ (LBL)"; 28 #endif 29 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <sys/timeb.h> 37 #include <sys/socket.h> 38 #include <sys/file.h> 39 #include <sys/ioctl.h> 40 #include <net/pfilt.h> 41 42 struct mbuf; 43 struct rtentry; 44 #include <net/if.h> 45 46 #include <netinet/in.h> 47 #include <netinet/in_systm.h> 48 #include <netinet/ip.h> 49 #include <netinet/if_ether.h> 50 #include <netinet/ip_var.h> 51 #include <netinet/udp.h> 52 #include <netinet/udp_var.h> 53 #include <netinet/tcp.h> 54 #include <netinet/tcpip.h> 55 56 #include <ctype.h> 57 #include <errno.h> 58 #include <netdb.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include "pcap-int.h" 65 66 #ifdef HAVE_OS_PROTO_H 67 #include "os-proto.h" 68 #endif 69 70 /* 71 * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump 72 * applications aren't going to need more than 200 bytes of packet header 73 * and the read shouldn't return more packets than packetfilter's internal 74 * queue limit (bounded at 256). 75 */ 76 #define BUFSPACE (200 * 256) 77 78 int 79 pcap_read(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) 80 { 81 register u_char *p, *bp; 82 struct bpf_insn *fcode; 83 register int cc, n, buflen, inc; 84 register struct enstamp *sp; 85 #ifdef LBL_ALIGN 86 struct enstamp stamp; 87 #endif 88 #ifdef PCAP_FDDIPAD 89 register int pad; 90 #endif 91 92 fcode = pc->md.use_bpf ? NULL : pc->fcode.bf_insns; 93 again: 94 cc = pc->cc; 95 if (cc == 0) { 96 cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); 97 if (cc < 0) { 98 if (errno == EWOULDBLOCK) 99 return (0); 100 if (errno == EINVAL && 101 lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { 102 /* 103 * Due to a kernel bug, after 2^31 bytes, 104 * the kernel file offset overflows and 105 * read fails with EINVAL. The lseek() 106 * to 0 will fix things. 107 */ 108 (void)lseek(pc->fd, 0L, SEEK_SET); 109 goto again; 110 } 111 snprintf(pc->errbuf, sizeof(pc->errbuf), "pf read: %s", 112 pcap_strerror(errno)); 113 return (-1); 114 } 115 bp = pc->buffer + pc->offset; 116 } else 117 bp = pc->bp; 118 /* 119 * Loop through each packet. 120 */ 121 n = 0; 122 #ifdef PCAP_FDDIPAD 123 if (pc->linktype == DLT_FDDI) 124 pad = pcap_fddipad; 125 else 126 pad = 0; 127 #endif 128 while (cc > 0) { 129 if (cc < sizeof(*sp)) { 130 snprintf(pc->errbuf, sizeof(pc->errbuf), 131 "pf short read (%d)", cc); 132 return (-1); 133 } 134 #ifdef LBL_ALIGN 135 if ((long)bp & 3) { 136 sp = &stamp; 137 memcpy((char *)sp, (char *)bp, sizeof(*sp)); 138 } else 139 #endif 140 sp = (struct enstamp *)bp; 141 if (sp->ens_stamplen != sizeof(*sp)) { 142 snprintf(pc->errbuf, sizeof(pc->errbuf), 143 "pf short stamplen (%d)", 144 sp->ens_stamplen); 145 return (-1); 146 } 147 148 p = bp + sp->ens_stamplen; 149 buflen = sp->ens_count; 150 if (buflen > pc->snapshot) 151 buflen = pc->snapshot; 152 153 /* Calculate inc before possible pad update */ 154 inc = ENALIGN(buflen + sp->ens_stamplen); 155 cc -= inc; 156 bp += inc; 157 #ifdef PCAP_FDDIPAD 158 p += pad; 159 buflen -= pad; 160 #endif 161 pc->md.TotPkts++; 162 pc->md.TotDrops += sp->ens_dropped; 163 pc->md.TotMissed = sp->ens_ifoverflows; 164 if (pc->md.OrigMissed < 0) 165 pc->md.OrigMissed = pc->md.TotMissed; 166 167 /* 168 * Short-circuit evaluation: if using BPF filter 169 * in kernel, no need to do it now. 170 */ 171 if (fcode == NULL || 172 bpf_filter(fcode, p, sp->ens_count, buflen)) { 173 struct pcap_pkthdr h; 174 pc->md.TotAccepted++; 175 h.ts = sp->ens_tstamp; 176 #ifdef PCAP_FDDIPAD 177 h.len = sp->ens_count - pad; 178 #else 179 h.len = sp->ens_count; 180 #endif 181 h.caplen = buflen; 182 (*callback)(user, &h, p); 183 if (++n >= cnt && cnt > 0) { 184 pc->cc = cc; 185 pc->bp = bp; 186 return (n); 187 } 188 } 189 } 190 pc->cc = 0; 191 return (n); 192 } 193 194 int 195 pcap_stats(pcap_t *p, struct pcap_stat *ps) 196 { 197 198 /* 199 * If packet filtering is being done in the kernel: 200 * 201 * "ps_recv" counts only packets that passed the filter. 202 * This does not include packets dropped because we 203 * ran out of buffer space. (XXX - perhaps it should, 204 * by adding "ps_drop" to "ps_recv", for compatibility 205 * with some other platforms. On the other hand, on 206 * some platforms "ps_recv" counts only packets that 207 * passed the filter, and on others it counts packets 208 * that didn't pass the filter....) 209 * 210 * "ps_drop" counts packets that passed the kernel filter 211 * (if any) but were dropped because the input queue was 212 * full. 213 * 214 * "ps_ifdrop" counts packets dropped by the network 215 * inteface (regardless of whether they would have passed 216 * the input filter, of course). 217 * 218 * If packet filtering is not being done in the kernel: 219 * 220 * "ps_recv" counts only packets that passed the filter. 221 * 222 * "ps_drop" counts packets that were dropped because the 223 * input queue was full, regardless of whether they passed 224 * the userland filter. 225 * 226 * "ps_ifdrop" counts packets dropped by the network 227 * inteface (regardless of whether they would have passed 228 * the input filter, of course). 229 * 230 * These statistics don't include packets not yet read from 231 * the kernel by libpcap, but they may include packets not 232 * yet read from libpcap by the application. 233 */ 234 ps->ps_recv = p->md.TotAccepted; 235 ps->ps_drop = p->md.TotDrops; 236 ps->ps_ifdrop = p->md.TotMissed - p->md.OrigMissed; 237 return (0); 238 } 239 240 pcap_t * 241 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 242 { 243 pcap_t *p; 244 short enmode; 245 int backlog = -1; /* request the most */ 246 struct enfilter Filter; 247 struct endevp devparams; 248 249 p = (pcap_t *)malloc(sizeof(*p)); 250 if (p == NULL) { 251 snprintf(ebuf, PCAP_ERRBUF_SIZE, 252 "pcap_open_live: %s", pcap_strerror(errno)); 253 return (0); 254 } 255 memset(p, 0, sizeof(*p)); 256 p->fd = pfopen(device, O_RDONLY); 257 if (p->fd < 0) { 258 snprintf(ebuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\ 259 your system may not be properly configured; see \"man packetfilter(4)\"\n", 260 device, pcap_strerror(errno)); 261 goto bad; 262 } 263 p->md.OrigMissed = -1; 264 enmode = ENTSTAMP|ENBATCH|ENNONEXCL; 265 if (promisc) 266 enmode |= ENPROMISC; 267 if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { 268 snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s", 269 pcap_strerror(errno)); 270 goto bad; 271 } 272 #ifdef ENCOPYALL 273 /* Try to set COPYALL mode so that we see packets to ourself */ 274 enmode = ENCOPYALL; 275 (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ 276 #endif 277 /* set the backlog */ 278 if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { 279 snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s", 280 pcap_strerror(errno)); 281 goto bad; 282 } 283 /* discover interface type */ 284 if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { 285 snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s", 286 pcap_strerror(errno)); 287 goto bad; 288 } 289 /* HACK: to compile prior to Ultrix 4.2 */ 290 #ifndef ENDT_FDDI 291 #define ENDT_FDDI 4 292 #endif 293 switch (devparams.end_dev_type) { 294 295 case ENDT_10MB: 296 p->linktype = DLT_EN10MB; 297 p->offset = 2; 298 break; 299 300 case ENDT_FDDI: 301 p->linktype = DLT_FDDI; 302 break; 303 304 #ifdef ENDT_SLIP 305 case ENDT_SLIP: 306 p->linktype = DLT_SLIP; 307 break; 308 #endif 309 310 #ifdef ENDT_PPP 311 case ENDT_PPP: 312 p->linktype = DLT_PPP; 313 break; 314 #endif 315 316 #ifdef ENDT_LOOPBACK 317 case ENDT_LOOPBACK: 318 /* 319 * It appears to use Ethernet framing, at least on 320 * Digital UNIX 4.0. 321 */ 322 p->linktype = DLT_EN10MB; 323 p->offset = 2; 324 break; 325 #endif 326 327 #ifdef ENDT_TRN 328 case ENDT_TRN: 329 p->linktype = DLT_IEEE802; 330 break; 331 #endif 332 333 default: 334 /* 335 * XXX - what about ENDT_IEEE802? The pfilt.h header 336 * file calls this "IEEE 802 networks (non-Ethernet)", 337 * but that doesn't specify a specific link layer type; 338 * it could be 802.4, or 802.5 (except that 802.5 is 339 * ENDT_TRN), or 802.6, or 802.11, or.... That's why 340 * DLT_IEEE802 was hijacked to mean Token Ring in various 341 * BSDs, and why we went along with that hijacking. 342 * 343 * XXX - what about ENDT_HDLC and ENDT_NULL? 344 * Presumably, as ENDT_OTHER is just "Miscellaneous 345 * framing", there's not much we can do, as that 346 * doesn't specify a particular type of header. 347 */ 348 snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown data-link type %lu", 349 devparams.end_dev_type); 350 goto bad; 351 } 352 /* set truncation */ 353 #ifdef PCAP_FDDIPAD 354 if (p->linktype == DLT_FDDI) 355 /* packetfilter includes the padding in the snapshot */ 356 snaplen += pcap_fddipad; 357 #endif 358 if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&snaplen) < 0) { 359 snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s", 360 pcap_strerror(errno)); 361 goto bad; 362 } 363 p->snapshot = snaplen; 364 /* accept all packets */ 365 memset(&Filter, 0, sizeof(Filter)); 366 Filter.enf_Priority = 37; /* anything > 2 */ 367 Filter.enf_FilterLen = 0; /* means "always true" */ 368 if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { 369 snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s", 370 pcap_strerror(errno)); 371 goto bad; 372 } 373 374 if (to_ms != 0) { 375 struct timeval timeout; 376 timeout.tv_sec = to_ms / 1000; 377 timeout.tv_usec = (to_ms * 1000) % 1000000; 378 if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { 379 snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s", 380 pcap_strerror(errno)); 381 goto bad; 382 } 383 } 384 p->bufsize = BUFSPACE; 385 p->buffer = (u_char*)malloc(p->bufsize + p->offset); 386 387 return (p); 388 bad: 389 if (p->fd >= 0) 390 close(p->fd); 391 free(p); 392 return (NULL); 393 } 394 395 int 396 pcap_setfilter(pcap_t *p, struct bpf_program *fp) 397 { 398 /* 399 * See if BIOCSETF works. If it does, the kernel supports 400 * BPF-style filters, and we do not need to do post-filtering. 401 */ 402 p->md.use_bpf = (ioctl(p->fd, BIOCSETF, (caddr_t)fp) >= 0); 403 if (p->md.use_bpf) { 404 struct bpf_version bv; 405 406 if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) < 0) { 407 snprintf(p->errbuf, sizeof(p->errbuf), 408 "BIOCVERSION: %s", pcap_strerror(errno)); 409 return (-1); 410 } 411 else if (bv.bv_major != BPF_MAJOR_VERSION || 412 bv.bv_minor < BPF_MINOR_VERSION) { 413 fprintf(stderr, 414 "requires bpf language %d.%d or higher; kernel is %d.%d", 415 BPF_MAJOR_VERSION, BPF_MINOR_VERSION, 416 bv.bv_major, bv.bv_minor); 417 /* don't give up, just be inefficient */ 418 p->md.use_bpf = 0; 419 } 420 } else { 421 if (install_bpf_program(p, fp) < 0) 422 return (-1); 423 } 424 425 /*XXX this goes in tcpdump*/ 426 if (p->md.use_bpf) 427 fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); 428 else 429 fprintf(stderr, "tcpdump: Filtering in user process\n"); 430 return (0); 431 } 432