1 /* $NetBSD: pcap-pf.c,v 1.1.1.4 2013/12/31 16:57:24 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 * 23 * packet filter subroutines for tcpdump 24 * Extraction/creation by Jeffrey Mogul, DECWRL 25 */ 26 27 #ifndef lint 28 static const char rcsid[] _U_ = 29 "@(#) Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.97 2008-04-14 20:40:58 guy Exp (LBL)"; 30 #endif 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #include <sys/types.h> 37 #include <sys/time.h> 38 #include <sys/timeb.h> 39 #include <sys/socket.h> 40 #include <sys/file.h> 41 #include <sys/ioctl.h> 42 #include <net/pfilt.h> 43 44 struct mbuf; 45 struct rtentry; 46 #include <net/if.h> 47 48 #include <netinet/in.h> 49 #include <netinet/in_systm.h> 50 #include <netinet/ip.h> 51 #include <netinet/if_ether.h> 52 #include <netinet/ip_var.h> 53 #include <netinet/udp.h> 54 #include <netinet/udp_var.h> 55 #include <netinet/tcp.h> 56 #include <netinet/tcpip.h> 57 58 #include <ctype.h> 59 #include <errno.h> 60 #include <netdb.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <unistd.h> 65 66 /* 67 * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the 68 * native OS version, as we need various BPF ioctls from it. 69 */ 70 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 71 #include <net/bpf.h> 72 73 #include "pcap-int.h" 74 75 #ifdef HAVE_OS_PROTO_H 76 #include "os-proto.h" 77 #endif 78 79 /* 80 * FDDI packets are padded to make everything line up on a nice boundary. 81 */ 82 #define PCAP_FDDIPAD 3 83 84 /* 85 * Private data for capturing on Ultrix and DEC OSF/1^WDigital UNIX^W^W 86 * Tru64 UNIX packetfilter devices. 87 */ 88 struct pcap_pf { 89 int filtering_in_kernel; /* using kernel filter */ 90 u_long TotPkts; /* can't oflow for 79 hrs on ether */ 91 u_long TotAccepted; /* count accepted by filter */ 92 u_long TotDrops; /* count of dropped packets */ 93 long TotMissed; /* missed by i/f during this run */ 94 long OrigMissed; /* missed by i/f before this run */ 95 }; 96 97 static int pcap_setfilter_pf(pcap_t *, struct bpf_program *); 98 99 /* 100 * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump 101 * applications aren't going to need more than 200 bytes of packet header 102 * and the read shouldn't return more packets than packetfilter's internal 103 * queue limit (bounded at 256). 104 */ 105 #define BUFSPACE (200 * 256) 106 107 static int 108 pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) 109 { 110 struct pcap_pf *pf = pc->priv; 111 register u_char *p, *bp; 112 register int cc, n, buflen, inc; 113 register struct enstamp *sp; 114 #ifdef LBL_ALIGN 115 struct enstamp stamp; 116 #endif 117 register int pad; 118 119 again: 120 cc = pc->cc; 121 if (cc == 0) { 122 cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); 123 if (cc < 0) { 124 if (errno == EWOULDBLOCK) 125 return (0); 126 if (errno == EINVAL && 127 lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { 128 /* 129 * Due to a kernel bug, after 2^31 bytes, 130 * the kernel file offset overflows and 131 * read fails with EINVAL. The lseek() 132 * to 0 will fix things. 133 */ 134 (void)lseek(pc->fd, 0L, SEEK_SET); 135 goto again; 136 } 137 snprintf(pc->errbuf, sizeof(pc->errbuf), "pf read: %s", 138 pcap_strerror(errno)); 139 return (-1); 140 } 141 bp = pc->buffer + pc->offset; 142 } else 143 bp = pc->bp; 144 /* 145 * Loop through each packet. 146 */ 147 n = 0; 148 pad = pc->fddipad; 149 while (cc > 0) { 150 /* 151 * Has "pcap_breakloop()" been called? 152 * If so, return immediately - if we haven't read any 153 * packets, clear the flag and return -2 to indicate 154 * that we were told to break out of the loop, otherwise 155 * leave the flag set, so that the *next* call will break 156 * out of the loop without having read any packets, and 157 * return the number of packets we've processed so far. 158 */ 159 if (pc->break_loop) { 160 if (n == 0) { 161 pc->break_loop = 0; 162 return (-2); 163 } else { 164 pc->cc = cc; 165 pc->bp = bp; 166 return (n); 167 } 168 } 169 if (cc < sizeof(*sp)) { 170 snprintf(pc->errbuf, sizeof(pc->errbuf), 171 "pf short read (%d)", cc); 172 return (-1); 173 } 174 #ifdef LBL_ALIGN 175 if ((long)bp & 3) { 176 sp = &stamp; 177 memcpy((char *)sp, (char *)bp, sizeof(*sp)); 178 } else 179 #endif 180 sp = (struct enstamp *)bp; 181 if (sp->ens_stamplen != sizeof(*sp)) { 182 snprintf(pc->errbuf, sizeof(pc->errbuf), 183 "pf short stamplen (%d)", 184 sp->ens_stamplen); 185 return (-1); 186 } 187 188 p = bp + sp->ens_stamplen; 189 buflen = sp->ens_count; 190 if (buflen > pc->snapshot) 191 buflen = pc->snapshot; 192 193 /* Calculate inc before possible pad update */ 194 inc = ENALIGN(buflen + sp->ens_stamplen); 195 cc -= inc; 196 bp += inc; 197 pf->TotPkts++; 198 pf->TotDrops += sp->ens_dropped; 199 pf->TotMissed = sp->ens_ifoverflows; 200 if (pf->OrigMissed < 0) 201 pf->OrigMissed = pf->TotMissed; 202 203 /* 204 * Short-circuit evaluation: if using BPF filter 205 * in kernel, no need to do it now - we already know 206 * the packet passed the filter. 207 * 208 * Note: the filter code was generated assuming 209 * that pc->fddipad was the amount of padding 210 * before the header, as that's what's required 211 * in the kernel, so we run the filter before 212 * skipping that padding. 213 */ 214 if (pf->filtering_in_kernel || 215 bpf_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) { 216 struct pcap_pkthdr h; 217 pf->TotAccepted++; 218 h.ts = sp->ens_tstamp; 219 h.len = sp->ens_count - pad; 220 p += pad; 221 buflen -= pad; 222 h.caplen = buflen; 223 (*callback)(user, &h, p); 224 if (++n >= cnt && cnt > 0) { 225 pc->cc = cc; 226 pc->bp = bp; 227 return (n); 228 } 229 } 230 } 231 pc->cc = 0; 232 return (n); 233 } 234 235 static int 236 pcap_inject_pf(pcap_t *p, const void *buf, size_t size) 237 { 238 int ret; 239 240 ret = write(p->fd, buf, size); 241 if (ret == -1) { 242 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", 243 pcap_strerror(errno)); 244 return (-1); 245 } 246 return (ret); 247 } 248 249 static int 250 pcap_stats_pf(pcap_t *p, struct pcap_stat *ps) 251 { 252 struct pcap_pf *pf = p->priv; 253 254 /* 255 * If packet filtering is being done in the kernel: 256 * 257 * "ps_recv" counts only packets that passed the filter. 258 * This does not include packets dropped because we 259 * ran out of buffer space. (XXX - perhaps it should, 260 * by adding "ps_drop" to "ps_recv", for compatibility 261 * with some other platforms. On the other hand, on 262 * some platforms "ps_recv" counts only packets that 263 * passed the filter, and on others it counts packets 264 * that didn't pass the filter....) 265 * 266 * "ps_drop" counts packets that passed the kernel filter 267 * (if any) but were dropped because the input queue was 268 * full. 269 * 270 * "ps_ifdrop" counts packets dropped by the network 271 * inteface (regardless of whether they would have passed 272 * the input filter, of course). 273 * 274 * If packet filtering is not being done in the kernel: 275 * 276 * "ps_recv" counts only packets that passed the filter. 277 * 278 * "ps_drop" counts packets that were dropped because the 279 * input queue was full, regardless of whether they passed 280 * the userland filter. 281 * 282 * "ps_ifdrop" counts packets dropped by the network 283 * inteface (regardless of whether they would have passed 284 * the input filter, of course). 285 * 286 * These statistics don't include packets not yet read from 287 * the kernel by libpcap, but they may include packets not 288 * yet read from libpcap by the application. 289 */ 290 ps->ps_recv = pf->TotAccepted; 291 ps->ps_drop = pf->TotDrops; 292 ps->ps_ifdrop = pf->TotMissed - pf->OrigMissed; 293 return (0); 294 } 295 296 /* 297 * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably 298 * don't get DLT_DOCSIS defined. 299 */ 300 #ifndef DLT_DOCSIS 301 #define DLT_DOCSIS 143 302 #endif 303 304 static int 305 pcap_activate_pf(pcap_t *p) 306 { 307 struct pcap_pf *pf = p->priv; 308 short enmode; 309 int backlog = -1; /* request the most */ 310 struct enfilter Filter; 311 struct endevp devparams; 312 313 /* 314 * Initially try a read/write open (to allow the inject 315 * method to work). If that fails due to permission 316 * issues, fall back to read-only. This allows a 317 * non-root user to be granted specific access to pcap 318 * capabilities via file permissions. 319 * 320 * XXX - we should have an API that has a flag that 321 * controls whether to open read-only or read-write, 322 * so that denial of permission to send (or inability 323 * to send, if sending packets isn't supported on 324 * the device in question) can be indicated at open 325 * time. 326 * 327 * XXX - we assume here that "pfopen()" does not, in fact, modify 328 * its argument, even though it takes a "char *" rather than a 329 * "const char *" as its first argument. That appears to be 330 * the case, at least on Digital UNIX 4.0. 331 */ 332 p->fd = pfopen(p->opt.source, O_RDWR); 333 if (p->fd == -1 && errno == EACCES) 334 p->fd = pfopen(p->opt.source, O_RDONLY); 335 if (p->fd < 0) { 336 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\ 337 your system may not be properly configured; see the packetfilter(4) man page\n", 338 p->opt.source, pcap_strerror(errno)); 339 goto bad; 340 } 341 pf->OrigMissed = -1; 342 enmode = ENTSTAMP|ENNONEXCL; 343 if (!p->opt.immediate) 344 enmode |= ENBATCH; 345 if (p->opt.promisc) 346 enmode |= ENPROMISC; 347 if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { 348 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s", 349 pcap_strerror(errno)); 350 goto bad; 351 } 352 #ifdef ENCOPYALL 353 /* Try to set COPYALL mode so that we see packets to ourself */ 354 enmode = ENCOPYALL; 355 (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ 356 #endif 357 /* set the backlog */ 358 if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { 359 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s", 360 pcap_strerror(errno)); 361 goto bad; 362 } 363 /* discover interface type */ 364 if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { 365 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s", 366 pcap_strerror(errno)); 367 goto bad; 368 } 369 /* HACK: to compile prior to Ultrix 4.2 */ 370 #ifndef ENDT_FDDI 371 #define ENDT_FDDI 4 372 #endif 373 switch (devparams.end_dev_type) { 374 375 case ENDT_10MB: 376 p->linktype = DLT_EN10MB; 377 p->offset = 2; 378 /* 379 * This is (presumably) a real Ethernet capture; give it a 380 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 381 * that an application can let you choose it, in case you're 382 * capturing DOCSIS traffic that a Cisco Cable Modem 383 * Termination System is putting out onto an Ethernet (it 384 * doesn't put an Ethernet header onto the wire, it puts raw 385 * DOCSIS frames out on the wire inside the low-level 386 * Ethernet framing). 387 */ 388 p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 389 /* 390 * If that fails, just leave the list empty. 391 */ 392 if (p->dlt_list != NULL) { 393 p->dlt_list[0] = DLT_EN10MB; 394 p->dlt_list[1] = DLT_DOCSIS; 395 p->dlt_count = 2; 396 } 397 break; 398 399 case ENDT_FDDI: 400 p->linktype = DLT_FDDI; 401 break; 402 403 #ifdef ENDT_SLIP 404 case ENDT_SLIP: 405 p->linktype = DLT_SLIP; 406 break; 407 #endif 408 409 #ifdef ENDT_PPP 410 case ENDT_PPP: 411 p->linktype = DLT_PPP; 412 break; 413 #endif 414 415 #ifdef ENDT_LOOPBACK 416 case ENDT_LOOPBACK: 417 /* 418 * It appears to use Ethernet framing, at least on 419 * Digital UNIX 4.0. 420 */ 421 p->linktype = DLT_EN10MB; 422 p->offset = 2; 423 break; 424 #endif 425 426 #ifdef ENDT_TRN 427 case ENDT_TRN: 428 p->linktype = DLT_IEEE802; 429 break; 430 #endif 431 432 default: 433 /* 434 * XXX - what about ENDT_IEEE802? The pfilt.h header 435 * file calls this "IEEE 802 networks (non-Ethernet)", 436 * but that doesn't specify a specific link layer type; 437 * it could be 802.4, or 802.5 (except that 802.5 is 438 * ENDT_TRN), or 802.6, or 802.11, or.... That's why 439 * DLT_IEEE802 was hijacked to mean Token Ring in various 440 * BSDs, and why we went along with that hijacking. 441 * 442 * XXX - what about ENDT_HDLC and ENDT_NULL? 443 * Presumably, as ENDT_OTHER is just "Miscellaneous 444 * framing", there's not much we can do, as that 445 * doesn't specify a particular type of header. 446 */ 447 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 448 "unknown data-link type %u", devparams.end_dev_type); 449 goto bad; 450 } 451 /* set truncation */ 452 if (p->linktype == DLT_FDDI) { 453 p->fddipad = PCAP_FDDIPAD; 454 455 /* packetfilter includes the padding in the snapshot */ 456 p->snapshot += PCAP_FDDIPAD; 457 } else 458 p->fddipad = 0; 459 if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&p->snapshot) < 0) { 460 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s", 461 pcap_strerror(errno)); 462 goto bad; 463 } 464 /* accept all packets */ 465 memset(&Filter, 0, sizeof(Filter)); 466 Filter.enf_Priority = 37; /* anything > 2 */ 467 Filter.enf_FilterLen = 0; /* means "always true" */ 468 if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { 469 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s", 470 pcap_strerror(errno)); 471 goto bad; 472 } 473 474 if (p->opt.timeout != 0) { 475 struct timeval timeout; 476 timeout.tv_sec = p->opt.timeout / 1000; 477 timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; 478 if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { 479 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s", 480 pcap_strerror(errno)); 481 goto bad; 482 } 483 } 484 485 p->bufsize = BUFSPACE; 486 p->buffer = (u_char*)malloc(p->bufsize + p->offset); 487 if (p->buffer == NULL) { 488 strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 489 goto bad; 490 } 491 492 /* 493 * "select()" and "poll()" work on packetfilter devices. 494 */ 495 p->selectable_fd = p->fd; 496 497 p->read_op = pcap_read_pf; 498 p->inject_op = pcap_inject_pf; 499 p->setfilter_op = pcap_setfilter_pf; 500 p->setdirection_op = NULL; /* Not implemented. */ 501 p->set_datalink_op = NULL; /* can't change data link type */ 502 p->getnonblock_op = pcap_getnonblock_fd; 503 p->setnonblock_op = pcap_setnonblock_fd; 504 p->stats_op = pcap_stats_pf; 505 506 return (0); 507 bad: 508 pcap_cleanup_live_common(p); 509 return (PCAP_ERROR); 510 } 511 512 pcap_t * 513 pcap_create_interface(const char *device, char *ebuf) 514 { 515 pcap_t *p; 516 517 p = pcap_create_common(device, ebuf, sizeof (struct pcap_pf)); 518 if (p == NULL) 519 return (NULL); 520 521 p->activate_op = pcap_activate_pf; 522 return (p); 523 } 524 525 int 526 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) 527 { 528 return (0); 529 } 530 531 static int 532 pcap_setfilter_pf(pcap_t *p, struct bpf_program *fp) 533 { 534 struct pcap_pf *pf = p->priv; 535 struct bpf_version bv; 536 537 /* 538 * See if BIOCVERSION works. If not, we assume the kernel doesn't 539 * support BPF-style filters (it's not documented in the bpf(7) 540 * or packetfiler(7) man pages, but the code used to fail if 541 * BIOCSETF worked but BIOCVERSION didn't, and I've seen it do 542 * kernel filtering in DU 4.0, so presumably BIOCVERSION works 543 * there, at least). 544 */ 545 if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) >= 0) { 546 /* 547 * OK, we have the version of the BPF interpreter; 548 * is it the same major version as us, and the same 549 * or better minor version? 550 */ 551 if (bv.bv_major == BPF_MAJOR_VERSION && 552 bv.bv_minor >= BPF_MINOR_VERSION) { 553 /* 554 * Yes. Try to install the filter. 555 */ 556 if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { 557 snprintf(p->errbuf, sizeof(p->errbuf), 558 "BIOCSETF: %s", pcap_strerror(errno)); 559 return (-1); 560 } 561 562 /* 563 * OK, that succeeded. We're doing filtering in 564 * the kernel. (We assume we don't have a 565 * userland filter installed - that'd require 566 * a previous version check to have failed but 567 * this one to succeed.) 568 * 569 * XXX - this message should be supplied to the 570 * application as a warning of some sort, 571 * except that if it's a GUI application, it's 572 * not clear that it should be displayed in 573 * a window to annoy the user. 574 */ 575 fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); 576 pf->filtering_in_kernel = 1; 577 578 /* 579 * Discard any previously-received packets, 580 * as they might have passed whatever filter 581 * was formerly in effect, but might not pass 582 * this filter (BIOCSETF discards packets buffered 583 * in the kernel, so you can lose packets in any 584 * case). 585 */ 586 p->cc = 0; 587 return (0); 588 } 589 590 /* 591 * We can't use the kernel's BPF interpreter; don't give 592 * up, just log a message and be inefficient. 593 * 594 * XXX - this should really be supplied to the application 595 * as a warning of some sort. 596 */ 597 fprintf(stderr, 598 "tcpdump: Requires BPF language %d.%d or higher; kernel is %d.%d\n", 599 BPF_MAJOR_VERSION, BPF_MINOR_VERSION, 600 bv.bv_major, bv.bv_minor); 601 } 602 603 /* 604 * We couldn't do filtering in the kernel; do it in userland. 605 */ 606 if (install_bpf_program(p, fp) < 0) 607 return (-1); 608 609 /* 610 * XXX - this message should be supplied by the application as 611 * a warning of some sort. 612 */ 613 fprintf(stderr, "tcpdump: Filtering in user process\n"); 614 pf->filtering_in_kernel = 0; 615 return (0); 616 } 617