1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS */ 28 29 #include <stdio.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <sys/isa_defs.h> 37 38 #include <sys/socket.h> 39 #include <sys/sockio.h> 40 #include <sys/dlpi.h> 41 #include <net/if.h> 42 #include <netinet/in_systm.h> 43 #include <netinet/in.h> 44 #include <netinet/ip.h> 45 #include <netinet/if_ether.h> 46 #include <netinet/tcp.h> 47 #include <netinet/udp.h> 48 #include <netdb.h> 49 #include <rpc/rpc.h> 50 #include <setjmp.h> 51 52 #include <sys/pfmod.h> 53 #include "snoop.h" 54 55 /* 56 * This module generates code for the kernel packet filter. 57 * The kernel packet filter is more efficient since it 58 * operates without context switching or moving data into 59 * the capture buffer. On the other hand, it is limited 60 * in its filtering ability i.e. can't cope with variable 61 * length headers, can't compare the packet size, 1 and 4 octet 62 * comparisons are awkward, code space is limited to ENMAXFILTERS 63 * halfwords, etc. 64 * The parser is the same for the user-level packet filter though 65 * more limited in the variety of expressions it can generate 66 * code for. If the pf compiler finds an expression it can't 67 * handle, it tries to set up a split filter in kernel and do the 68 * remaining filtering in userland. If that also fails, it resorts 69 * to userland filter. (See additional comment in pf_compile) 70 */ 71 72 extern struct Pf_ext_packetfilt pf; 73 static ushort_t *pfp; 74 jmp_buf env; 75 76 int eaddr; /* need ethernet addr */ 77 78 int opstack; /* operand stack depth */ 79 80 #define EQ(val) (strcmp(token, val) == 0) 81 #define IPV4_ONLY 0 82 #define IPV6_ONLY 1 83 #define IPV4_AND_IPV6 2 84 85 /* 86 * The following constants represent the offsets in bytes from the beginning 87 * of the packet of the link and IP(v6) layer source/destination/type fields, 88 * initialized for Ethernet. Media specific code can set any unavailable 89 * link layer property's offset to -1 to indicate that the property's value 90 * is not available from the frame. 91 */ 92 static int link_header_len = 14, link_type_offset = 12; 93 static int link_dest_offset = 0, link_src_offset = 6; 94 static int link_addr_len = 6; 95 96 #define IPV4_SRCADDR_OFFSET (link_header_len + 12) 97 #define IPV4_DSTADDR_OFFSET (link_header_len + 16) 98 #define IPV6_SRCADDR_OFFSET (link_header_len + 8) 99 #define IPV6_DSTADDR_OFFSET (link_header_len + 24) 100 #define IPV4_TYPE_OFFSET (link_header_len + 9) 101 #define IPV6_TYPE_OFFSET (link_header_len + 6) 102 103 static int inBrace = 0, inBraceOR = 0; 104 static int foundOR = 0; 105 char *tkp, *sav_tkp; 106 char *token; 107 enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL, 108 ADDR_IP6 } tokentype; 109 uint_t tokenval; 110 111 enum direction { ANY, TO, FROM }; 112 enum direction dir; 113 114 extern void next(); 115 116 static void pf_expression(); 117 118 static void 119 pf_emit(x) 120 ushort_t x; 121 { 122 if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1]) 123 longjmp(env, 1); 124 *pfp++ = x; 125 } 126 127 static void 128 pf_codeprint(code, len) 129 ushort_t *code; 130 int len; 131 { 132 ushort_t *pc; 133 ushort_t *plast = code + len; 134 int op, action; 135 136 if (len > 0) { 137 printf("Kernel Filter:\n"); 138 } 139 140 for (pc = code; pc < plast; pc++) { 141 printf("\t%3d: ", pc - code); 142 143 op = *pc & 0xfc00; /* high 10 bits */ 144 action = *pc & 0x3ff; /* low 6 bits */ 145 146 switch (action) { 147 case ENF_PUSHLIT: 148 printf("PUSHLIT "); 149 break; 150 case ENF_PUSHZERO: 151 printf("PUSHZERO "); 152 break; 153 #ifdef ENF_PUSHONE 154 case ENF_PUSHONE: 155 printf("PUSHONE "); 156 break; 157 #endif 158 #ifdef ENF_PUSHFFFF 159 case ENF_PUSHFFFF: 160 printf("PUSHFFFF "); 161 break; 162 #endif 163 #ifdef ENF_PUSHFF00 164 case ENF_PUSHFF00: 165 printf("PUSHFF00 "); 166 break; 167 #endif 168 #ifdef ENF_PUSH00FF 169 case ENF_PUSH00FF: 170 printf("PUSH00FF "); 171 break; 172 #endif 173 } 174 175 if (action >= ENF_PUSHWORD) 176 printf("PUSHWORD %d ", action - ENF_PUSHWORD); 177 178 switch (op) { 179 case ENF_EQ: 180 printf("EQ "); 181 break; 182 case ENF_LT: 183 printf("LT "); 184 break; 185 case ENF_LE: 186 printf("LE "); 187 break; 188 case ENF_GT: 189 printf("GT "); 190 break; 191 case ENF_GE: 192 printf("GE "); 193 break; 194 case ENF_AND: 195 printf("AND "); 196 break; 197 case ENF_OR: 198 printf("OR "); 199 break; 200 case ENF_XOR: 201 printf("XOR "); 202 break; 203 case ENF_COR: 204 printf("COR "); 205 break; 206 case ENF_CAND: 207 printf("CAND "); 208 break; 209 case ENF_CNOR: 210 printf("CNOR "); 211 break; 212 case ENF_CNAND: 213 printf("CNAND "); 214 break; 215 case ENF_NEQ: 216 printf("NEQ "); 217 break; 218 } 219 220 if (action == ENF_PUSHLIT) { 221 pc++; 222 printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc); 223 } 224 225 printf("\n"); 226 } 227 } 228 229 /* 230 * Emit packet filter code to check a 231 * field in the packet for a particular value. 232 * Need different code for each field size. 233 * Since the pf can only compare 16 bit quantities 234 * we have to use masking to compare byte values. 235 * Long word (32 bit) quantities have to be done 236 * as two 16 bit comparisons. 237 */ 238 static void 239 pf_compare_value(int offset, uint_t len, uint_t val) 240 { 241 /* 242 * If the property being filtered on is absent in the media 243 * packet, error out. 244 */ 245 if (offset == -1) 246 pr_err("filter option unsupported on media"); 247 248 switch (len) { 249 case 1: 250 pf_emit(ENF_PUSHWORD + offset / 2); 251 #if defined(_BIG_ENDIAN) 252 if (offset % 2) 253 #else 254 if (!(offset % 2)) 255 #endif 256 { 257 #ifdef ENF_PUSH00FF 258 pf_emit(ENF_PUSH00FF | ENF_AND); 259 #else 260 pf_emit(ENF_PUSHLIT | ENF_AND); 261 pf_emit(0x00FF); 262 #endif 263 pf_emit(ENF_PUSHLIT | ENF_EQ); 264 pf_emit(val); 265 } else { 266 #ifdef ENF_PUSHFF00 267 pf_emit(ENF_PUSHFF00 | ENF_AND); 268 #else 269 pf_emit(ENF_PUSHLIT | ENF_AND); 270 pf_emit(0xFF00); 271 #endif 272 pf_emit(ENF_PUSHLIT | ENF_EQ); 273 pf_emit(val << 8); 274 } 275 break; 276 277 case 2: 278 pf_emit(ENF_PUSHWORD + offset / 2); 279 pf_emit(ENF_PUSHLIT | ENF_EQ); 280 pf_emit((ushort_t)val); 281 break; 282 283 case 4: 284 pf_emit(ENF_PUSHWORD + offset / 2); 285 pf_emit(ENF_PUSHLIT | ENF_EQ); 286 #if defined(_BIG_ENDIAN) 287 pf_emit(val >> 16); 288 #elif defined(_LITTLE_ENDIAN) 289 pf_emit(val & 0xffff); 290 #else 291 #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined 292 #endif 293 pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 294 pf_emit(ENF_PUSHLIT | ENF_EQ); 295 #if defined(_BIG_ENDIAN) 296 pf_emit(val & 0xffff); 297 #else 298 pf_emit(val >> 16); 299 #endif 300 pf_emit(ENF_AND); 301 break; 302 } 303 } 304 305 /* 306 * same as pf_compare_value, but only for emiting code to 307 * compare ipv6 addresses. 308 */ 309 static void 310 pf_compare_value_v6(int offset, uint_t len, struct in6_addr val) 311 { 312 int i; 313 314 for (i = 0; i < len; i += 2) { 315 pf_emit(ENF_PUSHWORD + offset / 2 + i / 2); 316 pf_emit(ENF_PUSHLIT | ENF_EQ); 317 pf_emit(*(uint16_t *)&val.s6_addr[i]); 318 if (i != 0) 319 pf_emit(ENF_AND); 320 } 321 } 322 323 324 /* 325 * Same as above except mask the field value 326 * before doing the comparison. 327 */ 328 static void 329 pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) 330 { 331 /* 332 * If the property being filtered on is absent in the media 333 * packet, error out. 334 */ 335 if (offset == -1) 336 pr_err("filter option unsupported on media"); 337 338 switch (len) { 339 case 1: 340 pf_emit(ENF_PUSHWORD + offset / 2); 341 #if defined(_BIG_ENDIAN) 342 if (offset % 2) 343 #else 344 if (!offset % 2) 345 #endif 346 { 347 pf_emit(ENF_PUSHLIT | ENF_AND); 348 pf_emit(mask & 0x00ff); 349 pf_emit(ENF_PUSHLIT | ENF_EQ); 350 pf_emit(val); 351 } else { 352 pf_emit(ENF_PUSHLIT | ENF_AND); 353 pf_emit((mask << 8) & 0xff00); 354 pf_emit(ENF_PUSHLIT | ENF_EQ); 355 pf_emit(val << 8); 356 } 357 break; 358 359 case 2: 360 pf_emit(ENF_PUSHWORD + offset / 2); 361 pf_emit(ENF_PUSHLIT | ENF_AND); 362 pf_emit(htons((ushort_t)mask)); 363 pf_emit(ENF_PUSHLIT | ENF_EQ); 364 pf_emit(htons((ushort_t)val)); 365 break; 366 367 case 4: 368 pf_emit(ENF_PUSHWORD + offset / 2); 369 pf_emit(ENF_PUSHLIT | ENF_AND); 370 pf_emit(htons((ushort_t)((mask >> 16) & 0xffff))); 371 pf_emit(ENF_PUSHLIT | ENF_EQ); 372 pf_emit(htons((ushort_t)((val >> 16) & 0xffff))); 373 374 pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 375 pf_emit(ENF_PUSHLIT | ENF_AND); 376 pf_emit(htons((ushort_t)(mask & 0xffff))); 377 pf_emit(ENF_PUSHLIT | ENF_EQ); 378 pf_emit(htons((ushort_t)(val & 0xffff))); 379 380 pf_emit(ENF_AND); 381 break; 382 } 383 } 384 385 /* 386 * Generate pf code to match an IPv4 or IPv6 address. 387 */ 388 static void 389 pf_ipaddr_match(which, hostname, inet_type) 390 enum direction which; 391 char *hostname; 392 int inet_type; 393 { 394 bool_t found_host; 395 uint_t *addr4ptr; 396 uint_t addr4; 397 struct in6_addr *addr6ptr; 398 int h_addr_index; 399 struct hostent *hp = NULL; 400 int error_num = 0; 401 boolean_t first = B_TRUE; 402 int pass = 0; 403 404 /* 405 * The addr4offset and addr6offset variables simplify the code which 406 * generates the address comparison filter. With these two variables, 407 * duplicate code need not exist for the TO and FROM case. 408 * A value of -1 describes the ANY case (TO and FROM). 409 */ 410 int addr4offset; 411 int addr6offset; 412 413 found_host = 0; 414 415 if (tokentype == ADDR_IP) { 416 hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 417 if (hp == NULL) { 418 if (error_num == TRY_AGAIN) { 419 pr_err("could not resolve %s (try again later)", 420 hostname); 421 } else { 422 pr_err("could not resolve %s", hostname); 423 } 424 } 425 inet_type = IPV4_ONLY; 426 } else if (tokentype == ADDR_IP6) { 427 hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 428 if (hp == NULL) { 429 if (error_num == TRY_AGAIN) { 430 pr_err("could not resolve %s (try again later)", 431 hostname); 432 } else { 433 pr_err("could not resolve %s", hostname); 434 } 435 } 436 inet_type = IPV6_ONLY; 437 } else if (tokentype == ALPHA) { 438 /* Some hostname i.e. tokentype is ALPHA */ 439 switch (inet_type) { 440 case IPV4_ONLY: 441 /* Only IPv4 address is needed */ 442 hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 443 if (hp != NULL) { 444 found_host = 1; 445 } 446 break; 447 case IPV6_ONLY: 448 /* Only IPv6 address is needed */ 449 hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 450 if (hp != NULL) { 451 found_host = 1; 452 } 453 break; 454 case IPV4_AND_IPV6: 455 /* Both IPv4 and IPv6 are needed */ 456 hp = getipnodebyname(hostname, AF_INET6, 457 AI_ALL | AI_V4MAPPED, &error_num); 458 if (hp != NULL) { 459 found_host = 1; 460 } 461 break; 462 default: 463 found_host = 0; 464 } 465 466 if (!found_host) { 467 if (error_num == TRY_AGAIN) { 468 pr_err("could not resolve %s (try again later)", 469 hostname); 470 } else { 471 pr_err("could not resolve %s", hostname); 472 } 473 } 474 } else { 475 pr_err("unknown token type: %s", hostname); 476 } 477 478 switch (which) { 479 case TO: 480 addr4offset = IPV4_DSTADDR_OFFSET; 481 addr6offset = IPV6_DSTADDR_OFFSET; 482 break; 483 case FROM: 484 addr4offset = IPV4_SRCADDR_OFFSET; 485 addr6offset = IPV6_SRCADDR_OFFSET; 486 break; 487 case ANY: 488 addr4offset = -1; 489 addr6offset = -1; 490 break; 491 } 492 493 if (hp != NULL && hp->h_addrtype == AF_INET) { 494 pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_IP)); 495 h_addr_index = 0; 496 addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index]; 497 while (addr4ptr != NULL) { 498 if (addr4offset == -1) { 499 pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 500 *addr4ptr); 501 if (h_addr_index != 0) 502 pf_emit(ENF_OR); 503 pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 504 *addr4ptr); 505 pf_emit(ENF_OR); 506 } else { 507 pf_compare_value(addr4offset, 4, 508 *addr4ptr); 509 if (h_addr_index != 0) 510 pf_emit(ENF_OR); 511 } 512 addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index]; 513 } 514 pf_emit(ENF_AND); 515 } else { 516 /* first pass: IPv4 addresses */ 517 h_addr_index = 0; 518 addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 519 first = B_TRUE; 520 while (addr6ptr != NULL) { 521 if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 522 if (first) { 523 pf_compare_value(link_type_offset, 2, 524 htons(ETHERTYPE_IP)); 525 pass++; 526 } 527 IN6_V4MAPPED_TO_INADDR(addr6ptr, 528 (struct in_addr *)&addr4); 529 if (addr4offset == -1) { 530 pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 531 addr4); 532 if (!first) 533 pf_emit(ENF_OR); 534 pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 535 addr4); 536 pf_emit(ENF_OR); 537 } else { 538 pf_compare_value(addr4offset, 4, 539 addr4); 540 if (!first) 541 pf_emit(ENF_OR); 542 } 543 if (first) 544 first = B_FALSE; 545 } 546 addr6ptr = (struct in6_addr *) 547 hp->h_addr_list[++h_addr_index]; 548 } 549 if (!first) { 550 pf_emit(ENF_AND); 551 } 552 /* second pass: IPv6 addresses */ 553 h_addr_index = 0; 554 addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 555 first = B_TRUE; 556 while (addr6ptr != NULL) { 557 if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 558 if (first) { 559 pf_compare_value(link_type_offset, 2, 560 htons(ETHERTYPE_IPV6)); 561 pass++; 562 } 563 if (addr6offset == -1) { 564 pf_compare_value_v6(IPV6_SRCADDR_OFFSET, 565 16, *addr6ptr); 566 if (!first) 567 pf_emit(ENF_OR); 568 pf_compare_value_v6(IPV6_DSTADDR_OFFSET, 569 16, *addr6ptr); 570 pf_emit(ENF_OR); 571 } else { 572 pf_compare_value_v6(addr6offset, 16, 573 *addr6ptr); 574 if (!first) 575 pf_emit(ENF_OR); 576 } 577 if (first) 578 first = B_FALSE; 579 } 580 addr6ptr = (struct in6_addr *) 581 hp->h_addr_list[++h_addr_index]; 582 } 583 if (!first) { 584 pf_emit(ENF_AND); 585 } 586 if (pass == 2) { 587 pf_emit(ENF_OR); 588 } 589 } 590 591 if (hp != NULL) { 592 freehostent(hp); 593 } 594 } 595 596 597 static void 598 pf_compare_address(int offset, uint_t len, uchar_t *addr) 599 { 600 uint32_t val; 601 uint16_t sval; 602 boolean_t didone = B_FALSE; 603 604 /* 605 * If the property being filtered on is absent in the media 606 * packet, error out. 607 */ 608 if (offset == -1) 609 pr_err("filter option unsupported on media"); 610 611 while (len > 0) { 612 if (len >= 4) { 613 (void) memcpy(&val, addr, 4); 614 pf_compare_value(offset, 4, val); 615 addr += 4; 616 offset += 4; 617 len -= 4; 618 } else if (len >= 2) { 619 (void) memcpy(&sval, addr, 2); 620 pf_compare_value(offset, 2, sval); 621 addr += 2; 622 offset += 2; 623 len -= 2; 624 } else { 625 pf_compare_value(offset++, 1, *addr++); 626 len--; 627 } 628 if (didone) 629 pf_emit(ENF_AND); 630 didone = B_TRUE; 631 } 632 } 633 634 /* 635 * Compare ethernet addresses. 636 */ 637 static void 638 pf_etheraddr_match(which, hostname) 639 enum direction which; 640 char *hostname; 641 { 642 struct ether_addr e, *ep = NULL; 643 644 if (isxdigit(*hostname)) 645 ep = ether_aton(hostname); 646 if (ep == NULL) { 647 if (ether_hostton(hostname, &e)) 648 if (!arp_for_ether(hostname, &e)) 649 pr_err("cannot obtain ether addr for %s", 650 hostname); 651 ep = &e; 652 } 653 654 switch (which) { 655 case TO: 656 pf_compare_address(link_dest_offset, link_addr_len, 657 (uchar_t *)ep); 658 break; 659 case FROM: 660 pf_compare_address(link_src_offset, link_addr_len, 661 (uchar_t *)ep); 662 break; 663 case ANY: 664 pf_compare_address(link_dest_offset, link_addr_len, 665 (uchar_t *)ep); 666 pf_compare_address(link_src_offset, link_addr_len, 667 (uchar_t *)ep); 668 pf_emit(ENF_OR); 669 break; 670 } 671 } 672 673 /* 674 * Emit code to compare the network part of 675 * an IP address. 676 */ 677 static void 678 pf_netaddr_match(which, netname) 679 enum direction which; 680 char *netname; 681 { 682 uint_t addr; 683 uint_t mask = 0xff000000; 684 struct netent *np; 685 686 if (isdigit(*netname)) { 687 addr = inet_network(netname); 688 } else { 689 np = getnetbyname(netname); 690 if (np == NULL) 691 pr_err("net %s not known", netname); 692 addr = np->n_net; 693 } 694 695 /* 696 * Left justify the address and figure 697 * out a mask based on the supplied address. 698 * Set the mask according to the number of zero 699 * low-order bytes. 700 * Note: this works only for whole octet masks. 701 */ 702 if (addr) { 703 while ((addr & ~mask) != 0) { 704 mask |= (mask >> 8); 705 } 706 } 707 708 switch (which) { 709 case TO: 710 pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 711 break; 712 case FROM: 713 pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 714 break; 715 case ANY: 716 pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 717 pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 718 pf_emit(ENF_OR); 719 break; 720 } 721 } 722 723 static void 724 pf_primary() 725 { 726 for (;;) { 727 if (tokentype == FIELD) 728 break; 729 730 if (EQ("ip")) { 731 pf_compare_value(link_type_offset, 2, 732 htons(ETHERTYPE_IP)); 733 opstack++; 734 next(); 735 break; 736 } 737 738 if (EQ("ip6")) { 739 pf_compare_value(link_type_offset, 2, 740 htons(ETHERTYPE_IPV6)); 741 opstack++; 742 next(); 743 break; 744 } 745 746 if (EQ("pppoe")) { 747 pf_compare_value(link_type_offset, 2, 748 htons(ETHERTYPE_PPPOED)); 749 pf_compare_value(link_type_offset, 2, 750 htons(ETHERTYPE_PPPOES)); 751 pf_emit(ENF_OR); 752 opstack++; 753 next(); 754 break; 755 } 756 757 if (EQ("pppoed")) { 758 pf_compare_value(link_type_offset, 2, 759 htons(ETHERTYPE_PPPOED)); 760 opstack++; 761 next(); 762 break; 763 } 764 765 if (EQ("pppoes")) { 766 pf_compare_value(link_type_offset, 2, 767 htons(ETHERTYPE_PPPOES)); 768 opstack++; 769 next(); 770 break; 771 } 772 773 if (EQ("arp")) { 774 pf_compare_value(link_type_offset, 2, 775 htons(ETHERTYPE_ARP)); 776 opstack++; 777 next(); 778 break; 779 } 780 781 if (EQ("rarp")) { 782 pf_compare_value(link_type_offset, 2, 783 htons(ETHERTYPE_REVARP)); 784 opstack++; 785 next(); 786 break; 787 } 788 789 if (EQ("tcp")) { 790 pf_compare_value(link_type_offset, 2, 791 htons(ETHERTYPE_IP)); 792 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_TCP); 793 pf_emit(ENF_AND); 794 pf_compare_value(link_type_offset, 2, 795 htons(ETHERTYPE_IPV6)); 796 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_TCP); 797 pf_emit(ENF_AND); 798 pf_emit(ENF_OR); 799 opstack++; 800 next(); 801 break; 802 } 803 804 if (EQ("udp")) { 805 pf_compare_value(link_type_offset, 2, 806 htons(ETHERTYPE_IP)); 807 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_UDP); 808 pf_emit(ENF_AND); 809 pf_compare_value(link_type_offset, 2, 810 htons(ETHERTYPE_IPV6)); 811 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_UDP); 812 pf_emit(ENF_AND); 813 pf_emit(ENF_OR); 814 opstack++; 815 next(); 816 break; 817 } 818 819 if (EQ("ospf")) { 820 pf_compare_value(link_type_offset, 2, 821 htons(ETHERTYPE_IP)); 822 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_OSPF); 823 pf_emit(ENF_AND); 824 pf_compare_value(link_type_offset, 2, 825 htons(ETHERTYPE_IPV6)); 826 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_OSPF); 827 pf_emit(ENF_AND); 828 pf_emit(ENF_OR); 829 opstack++; 830 next(); 831 break; 832 } 833 834 835 if (EQ("sctp")) { 836 pf_compare_value(link_type_offset, 2, 837 htons(ETHERTYPE_IP)); 838 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_SCTP); 839 pf_emit(ENF_AND); 840 pf_compare_value(link_type_offset, 2, 841 htons(ETHERTYPE_IPV6)); 842 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_SCTP); 843 pf_emit(ENF_AND); 844 pf_emit(ENF_OR); 845 opstack++; 846 next(); 847 break; 848 } 849 850 if (EQ("icmp")) { 851 pf_compare_value(link_type_offset, 2, 852 htons(ETHERTYPE_IP)); 853 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ICMP); 854 pf_emit(ENF_AND); 855 opstack++; 856 next(); 857 break; 858 } 859 860 if (EQ("icmp6")) { 861 pf_compare_value(link_type_offset, 2, 862 htons(ETHERTYPE_IPV6)); 863 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ICMPV6); 864 pf_emit(ENF_AND); 865 opstack++; 866 next(); 867 break; 868 } 869 870 if (EQ("ip-in-ip")) { 871 pf_compare_value(link_type_offset, 2, 872 htons(ETHERTYPE_IP)); 873 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ENCAP); 874 pf_emit(ENF_AND); 875 opstack++; 876 next(); 877 break; 878 } 879 880 if (EQ("esp")) { 881 pf_compare_value(link_type_offset, 2, 882 htons(ETHERTYPE_IP)); 883 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ESP); 884 pf_emit(ENF_AND); 885 pf_compare_value(link_type_offset, 2, 886 htons(ETHERTYPE_IPV6)); 887 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ESP); 888 pf_emit(ENF_AND); 889 pf_emit(ENF_OR); 890 opstack++; 891 next(); 892 break; 893 } 894 895 if (EQ("ah")) { 896 pf_compare_value(link_type_offset, 2, 897 htons(ETHERTYPE_IP)); 898 pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_AH); 899 pf_emit(ENF_AND); 900 pf_compare_value(link_type_offset, 2, 901 htons(ETHERTYPE_IPV6)); 902 pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_AH); 903 pf_emit(ENF_AND); 904 pf_emit(ENF_OR); 905 opstack++; 906 next(); 907 break; 908 } 909 910 if (EQ("(")) { 911 inBrace++; 912 next(); 913 pf_expression(); 914 if (EQ(")")) { 915 if (inBrace) 916 inBraceOR--; 917 inBrace--; 918 next(); 919 } 920 break; 921 } 922 923 if (EQ("to") || EQ("dst")) { 924 dir = TO; 925 next(); 926 continue; 927 } 928 929 if (EQ("from") || EQ("src")) { 930 dir = FROM; 931 next(); 932 continue; 933 } 934 935 if (EQ("ether")) { 936 eaddr = 1; 937 next(); 938 continue; 939 } 940 941 if (EQ("inet")) { 942 next(); 943 if (EQ("host")) 944 next(); 945 if (tokentype != ALPHA && tokentype != ADDR_IP) 946 pr_err("host/IPv4 addr expected after inet"); 947 pf_ipaddr_match(dir, token, IPV4_ONLY); 948 opstack++; 949 next(); 950 break; 951 } 952 953 if (EQ("inet6")) { 954 next(); 955 if (EQ("host")) 956 next(); 957 if (tokentype != ALPHA && tokentype != ADDR_IP6) 958 pr_err("host/IPv6 addr expected after inet6"); 959 pf_ipaddr_match(dir, token, IPV6_ONLY); 960 opstack++; 961 next(); 962 break; 963 } 964 965 if (EQ("proto")) { 966 next(); 967 if (tokentype != NUMBER) 968 pr_err("IP proto type expected"); 969 pf_compare_value(IPV4_TYPE_OFFSET, 1, tokenval); 970 opstack++; 971 next(); 972 break; 973 } 974 975 if (EQ("broadcast")) { 976 pf_compare_value(link_dest_offset, 4, 0xffffffff); 977 opstack++; 978 next(); 979 break; 980 } 981 982 if (EQ("multicast")) { 983 pf_compare_value_mask(link_dest_offset, 1, 0x01, 0x01); 984 opstack++; 985 next(); 986 break; 987 } 988 989 if (EQ("ethertype")) { 990 next(); 991 if (tokentype != NUMBER) 992 pr_err("ether type expected"); 993 pf_compare_value(link_type_offset, 2, htons(tokenval)); 994 opstack++; 995 next(); 996 break; 997 } 998 999 if (EQ("net") || EQ("dstnet") || EQ("srcnet")) { 1000 if (EQ("dstnet")) 1001 dir = TO; 1002 else if (EQ("srcnet")) 1003 dir = FROM; 1004 next(); 1005 pf_netaddr_match(dir, token); 1006 dir = ANY; 1007 opstack++; 1008 next(); 1009 break; 1010 } 1011 1012 /* 1013 * Give up on anything that's obviously 1014 * not a primary. 1015 */ 1016 if (EQ("and") || EQ("or") || 1017 EQ("not") || EQ("decnet") || EQ("apple") || 1018 EQ("length") || EQ("less") || EQ("greater") || 1019 EQ("port") || EQ("srcport") || EQ("dstport") || 1020 EQ("rpc") || EQ("gateway") || EQ("nofrag") || 1021 EQ("bootp") || EQ("dhcp") || EQ("slp") || EQ("ldap")) { 1022 break; 1023 } 1024 1025 if (EQ("host") || EQ("between") || 1026 tokentype == ALPHA || /* assume its a hostname */ 1027 tokentype == ADDR_IP || 1028 tokentype == ADDR_IP6 || 1029 tokentype == ADDR_ETHER) { 1030 if (EQ("host") || EQ("between")) 1031 next(); 1032 if (eaddr || tokentype == ADDR_ETHER) { 1033 pf_etheraddr_match(dir, token); 1034 } else if (tokentype == ALPHA) { 1035 pf_ipaddr_match(dir, token, IPV4_AND_IPV6); 1036 } else if (tokentype == ADDR_IP) { 1037 pf_ipaddr_match(dir, token, IPV4_ONLY); 1038 } else { 1039 pf_ipaddr_match(dir, token, IPV6_ONLY); 1040 } 1041 dir = ANY; 1042 eaddr = 0; 1043 opstack++; 1044 next(); 1045 break; 1046 } 1047 1048 break; /* unknown token */ 1049 } 1050 } 1051 1052 static void 1053 pf_alternation() 1054 { 1055 int s = opstack; 1056 1057 pf_primary(); 1058 for (;;) { 1059 if (EQ("and")) 1060 next(); 1061 pf_primary(); 1062 if (opstack != s + 2) 1063 break; 1064 pf_emit(ENF_AND); 1065 opstack--; 1066 } 1067 } 1068 1069 static void 1070 pf_expression() 1071 { 1072 pf_alternation(); 1073 while (EQ("or") || EQ(",")) { 1074 if (inBrace) 1075 inBraceOR++; 1076 else 1077 foundOR++; 1078 next(); 1079 pf_alternation(); 1080 pf_emit(ENF_OR); 1081 opstack--; 1082 } 1083 } 1084 1085 /* 1086 * Attempt to compile the expression 1087 * in the string "e". If we can generate 1088 * pf code for it then return 1 - otherwise 1089 * return 0 and leave it up to the user-level 1090 * filter. 1091 */ 1092 int 1093 pf_compile(e, print) 1094 char *e; 1095 int print; 1096 { 1097 char *argstr; 1098 char *sav_str, *ptr, *sav_ptr; 1099 int inBr = 0, aheadOR = 0; 1100 1101 argstr = strdup(e); 1102 sav_str = e; 1103 tkp = argstr; 1104 dir = ANY; 1105 1106 pfp = &pf.Pf_Filter[0]; 1107 if (setjmp(env)) { 1108 return (0); 1109 } 1110 1111 /* 1112 * Set media specific packet offsets that this code uses. 1113 */ 1114 if (interface->mac_type == DL_IB) { 1115 link_header_len = 4; 1116 link_type_offset = 0; 1117 link_dest_offset = link_src_offset = -1; 1118 link_addr_len = 20; 1119 } 1120 1121 next(); 1122 pf_expression(); 1123 1124 if (tokentype != EOL) { 1125 /* 1126 * The idea here is to do as much filtering as possible in 1127 * the kernel. So even if we find a token we don't understand, 1128 * we try to see if we can still set up a portion of the filter 1129 * in the kernel and use the userland filter to filter the 1130 * remaining stuff. Obviously, if our filter expression is of 1131 * type A AND B, we can filter A in kernel and then apply B 1132 * to the packets that got through. The same is not true for 1133 * a filter of type A OR B. We can't apply A first and then B 1134 * on the packets filtered through A. 1135 * 1136 * (We need to keep track of the fact when we find an OR, 1137 * and the fact that we are inside brackets when we find OR. 1138 * The variable 'foundOR' tells us if there was an OR behind, 1139 * 'inBraceOR' tells us if we found an OR before we could find 1140 * the end brace i.e. ')', and variable 'aheadOR' checks if 1141 * there is an OR in the expression ahead. if either of these 1142 * cases become true, we can't split the filtering) 1143 */ 1144 1145 if (foundOR || inBraceOR) { 1146 /* FORGET IN KERNEL FILTERING */ 1147 return (0); 1148 } else { 1149 1150 /* CHECK IF NO OR AHEAD */ 1151 sav_ptr = (char *)((uintptr_t)sav_str + 1152 (uintptr_t)sav_tkp - 1153 (uintptr_t)argstr); 1154 ptr = sav_ptr; 1155 while (*ptr != '\0') { 1156 switch (*ptr) { 1157 case '(': 1158 inBr++; 1159 break; 1160 case ')': 1161 inBr--; 1162 break; 1163 case 'o': 1164 case 'O': 1165 if ((*(ptr + 1) == 'R' || 1166 *(ptr + 1) == 'r') && !inBr) 1167 aheadOR = 1; 1168 break; 1169 case ',': 1170 if (!inBr) 1171 aheadOR = 1; 1172 break; 1173 } 1174 ptr++; 1175 } 1176 if (!aheadOR) { 1177 /* NO OR AHEAD, SPLIT UP THE FILTERING */ 1178 pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 1179 pf.Pf_Priority = 5; 1180 if (print) { 1181 pf_codeprint(&pf.Pf_Filter[0], 1182 pf.Pf_FilterLen); 1183 } 1184 compile(sav_ptr, print); 1185 return (2); 1186 } else 1187 return (0); 1188 } 1189 } 1190 1191 pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 1192 pf.Pf_Priority = 5; /* unimportant, so long as > 2 */ 1193 if (print) { 1194 pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen); 1195 } 1196 return (1); 1197 } 1198