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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stddef.h> 28 #include <ctype.h> 29 #include <string.h> 30 #include <fcntl.h> 31 #include <string.h> 32 #include <sys/types.h> 33 #include <sys/time.h> 34 #include <sys/isa_defs.h> 35 36 #include <sys/socket.h> 37 #include <sys/vlan.h> 38 #include <net/if.h> 39 #include <netinet/in_systm.h> 40 #include <netinet/in.h> 41 #include <netinet/ip.h> 42 #include <netinet/if_ether.h> 43 #include <netinet/tcp.h> 44 #include <netinet/udp.h> 45 #include <inet/ip.h> 46 #include <inet/ip6.h> 47 #include <netdb.h> 48 #include <rpc/rpc.h> 49 #include <setjmp.h> 50 51 #include <sys/pfmod.h> 52 #include "snoop.h" 53 #include "snoop_vlan.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 typedef struct { 86 int transport_protocol; 87 int network_protocol; 88 /* 89 * offset is the offset in bytes from the beginning 90 * of the network protocol header to where the transport 91 * protocol type is. 92 */ 93 int offset; 94 } transport_table_t; 95 96 typedef struct network_table { 97 char *nmt_name; 98 int nmt_val; 99 } network_table_t; 100 101 static network_table_t ether_network_mapping_table[] = { 102 { "pup", ETHERTYPE_PUP }, 103 { "ip", ETHERTYPE_IP }, 104 { "arp", ETHERTYPE_ARP }, 105 { "revarp", ETHERTYPE_REVARP }, 106 { "at", ETHERTYPE_AT }, 107 { "aarp", ETHERTYPE_AARP }, 108 { "vlan", ETHERTYPE_VLAN }, 109 { "ip6", ETHERTYPE_IPV6 }, 110 { "slow", ETHERTYPE_SLOW }, 111 { "ppoed", ETHERTYPE_PPPOED }, 112 { "ppoes", ETHERTYPE_PPPOES }, 113 { "NULL", -1 } 114 115 }; 116 117 static network_table_t ib_network_mapping_table[] = { 118 { "pup", ETHERTYPE_PUP }, 119 { "ip", ETHERTYPE_IP }, 120 { "arp", ETHERTYPE_ARP }, 121 { "revarp", ETHERTYPE_REVARP }, 122 { "at", ETHERTYPE_AT }, 123 { "aarp", ETHERTYPE_AARP }, 124 { "vlan", ETHERTYPE_VLAN }, 125 { "ip6", ETHERTYPE_IPV6 }, 126 { "slow", ETHERTYPE_SLOW }, 127 { "ppoed", ETHERTYPE_PPPOED }, 128 { "ppoes", ETHERTYPE_PPPOES }, 129 { "NULL", -1 } 130 131 }; 132 133 static network_table_t ipnet_network_mapping_table[] = { 134 { "ip", (DL_IPNETINFO_VERSION << 8 | AF_INET) }, 135 { "ip6", (DL_IPNETINFO_VERSION << 8 | AF_INET6) }, 136 { "NULL", -1 } 137 138 }; 139 140 static transport_table_t ether_transport_mapping_table[] = { 141 {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 142 {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 143 {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 144 {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 145 {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 146 {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 147 {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 148 {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 149 {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 150 {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 151 {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 152 {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 153 {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 154 {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 155 {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 156 {IPPROTO_DCCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 157 {IPPROTO_DCCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 158 {-1, 0, 0} /* must be the final entry */ 159 }; 160 161 static transport_table_t ipnet_transport_mapping_table[] = { 162 {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 163 IPV4_TYPE_HEADER_OFFSET}, 164 {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 165 IPV6_TYPE_HEADER_OFFSET}, 166 {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 167 IPV4_TYPE_HEADER_OFFSET}, 168 {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 169 IPV6_TYPE_HEADER_OFFSET}, 170 {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET), 171 IPV4_TYPE_HEADER_OFFSET}, 172 {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 173 IPV6_TYPE_HEADER_OFFSET}, 174 {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 175 IPV4_TYPE_HEADER_OFFSET}, 176 {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 177 IPV6_TYPE_HEADER_OFFSET}, 178 {IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 179 IPV4_TYPE_HEADER_OFFSET}, 180 {IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 181 IPV6_TYPE_HEADER_OFFSET}, 182 {IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 183 IPV4_TYPE_HEADER_OFFSET}, 184 {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 185 IPV4_TYPE_HEADER_OFFSET}, 186 {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 187 IPV6_TYPE_HEADER_OFFSET}, 188 {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET), 189 IPV4_TYPE_HEADER_OFFSET}, 190 {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 191 IPV6_TYPE_HEADER_OFFSET}, 192 {IPPROTO_DCCP, (DL_IPNETINFO_VERSION << 8 | AF_INET), 193 IPV4_TYPE_HEADER_OFFSET}, 194 {IPPROTO_DCCP, (DL_IPNETINFO_VERSION << 8 | AF_INET6), 195 IPV6_TYPE_HEADER_OFFSET}, 196 {-1, 0, 0} /* must be the final entry */ 197 }; 198 199 static transport_table_t ib_transport_mapping_table[] = { 200 {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 201 {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 202 {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 203 {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 204 {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 205 {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 206 {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 207 {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 208 {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 209 {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 210 {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 211 {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 212 {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 213 {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 214 {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 215 {IPPROTO_DCCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, 216 {IPPROTO_DCCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, 217 {-1, 0, 0} /* must be the final entry */ 218 }; 219 220 typedef struct datalink { 221 uint_t dl_type; 222 void (*dl_match_fn)(uint_t datatype); 223 transport_table_t *dl_trans_map_tbl; 224 network_table_t *dl_net_map_tbl; 225 int dl_link_header_len; 226 int dl_link_type_offset; 227 int dl_link_dest_offset; 228 int dl_link_src_offset; 229 int dl_link_addr_len; 230 } datalink_t; 231 232 datalink_t dl; 233 234 #define IPV4_SRCADDR_OFFSET (dl.dl_link_header_len + 12) 235 #define IPV4_DSTADDR_OFFSET (dl.dl_link_header_len + 16) 236 #define IPV6_SRCADDR_OFFSET (dl.dl_link_header_len + 8) 237 #define IPV6_DSTADDR_OFFSET (dl.dl_link_header_len + 24) 238 239 #define IPNET_SRCZONE_OFFSET 16 240 #define IPNET_DSTZONE_OFFSET 20 241 242 static int inBrace = 0, inBraceOR = 0; 243 static int foundOR = 0; 244 char *tkp, *sav_tkp; 245 char *token; 246 enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL, 247 ADDR_IP6 } tokentype; 248 uint_t tokenval; 249 250 enum direction { ANY, TO, FROM }; 251 enum direction dir; 252 253 extern void next(); 254 255 static void pf_expression(); 256 static void pf_check_vlan_tag(uint_t offset); 257 static void pf_clear_offset_register(); 258 static void pf_emit_load_offset(uint_t offset); 259 static void pf_match_ethertype(uint_t ethertype); 260 static void pf_match_ipnettype(uint_t type); 261 static void pf_match_ibtype(uint_t type); 262 static void pf_check_transport_protocol(uint_t transport_protocol); 263 static void pf_compare_value_mask_generic(int offset, uint_t len, 264 uint_t val, int mask, uint_t op); 265 static void pf_matchfn(const char *name); 266 267 /* 268 * This pointer points to the function that last generated 269 * instructions to change the offset register. It's used 270 * for comparisons to see if we need to issue more instructions 271 * to change the register. 272 * 273 * It's initialized to pf_clear_offset_register because the offset 274 * register in pfmod is initialized to zero, similar to the state 275 * it would be in after executing the instructions issued by 276 * pf_clear_offset_register. 277 */ 278 static void *last_offset_operation = (void*)pf_clear_offset_register; 279 280 static void 281 pf_emit(x) 282 ushort_t x; 283 { 284 if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1]) 285 longjmp(env, 1); 286 *pfp++ = x; 287 } 288 289 static void 290 pf_codeprint(code, len) 291 ushort_t *code; 292 int len; 293 { 294 ushort_t *pc; 295 ushort_t *plast = code + len; 296 int op, action; 297 298 if (len > 0) { 299 printf("Kernel Filter:\n"); 300 } 301 302 for (pc = code; pc < plast; pc++) { 303 printf("\t%3d: ", pc - code); 304 305 op = *pc & 0xfc00; /* high 10 bits */ 306 action = *pc & 0x3ff; /* low 6 bits */ 307 308 switch (action) { 309 case ENF_PUSHLIT: 310 printf("PUSHLIT "); 311 break; 312 case ENF_PUSHZERO: 313 printf("PUSHZERO "); 314 break; 315 #ifdef ENF_PUSHONE 316 case ENF_PUSHONE: 317 printf("PUSHONE "); 318 break; 319 #endif 320 #ifdef ENF_PUSHFFFF 321 case ENF_PUSHFFFF: 322 printf("PUSHFFFF "); 323 break; 324 #endif 325 #ifdef ENF_PUSHFF00 326 case ENF_PUSHFF00: 327 printf("PUSHFF00 "); 328 break; 329 #endif 330 #ifdef ENF_PUSH00FF 331 case ENF_PUSH00FF: 332 printf("PUSH00FF "); 333 break; 334 #endif 335 case ENF_LOAD_OFFSET: 336 printf("LOAD_OFFSET "); 337 break; 338 case ENF_BRTR: 339 printf("BRTR "); 340 break; 341 case ENF_BRFL: 342 printf("BRFL "); 343 break; 344 case ENF_POP: 345 printf("POP "); 346 break; 347 } 348 349 if (action >= ENF_PUSHWORD) 350 printf("PUSHWORD %d ", action - ENF_PUSHWORD); 351 352 switch (op) { 353 case ENF_EQ: 354 printf("EQ "); 355 break; 356 case ENF_LT: 357 printf("LT "); 358 break; 359 case ENF_LE: 360 printf("LE "); 361 break; 362 case ENF_GT: 363 printf("GT "); 364 break; 365 case ENF_GE: 366 printf("GE "); 367 break; 368 case ENF_AND: 369 printf("AND "); 370 break; 371 case ENF_OR: 372 printf("OR "); 373 break; 374 case ENF_XOR: 375 printf("XOR "); 376 break; 377 case ENF_COR: 378 printf("COR "); 379 break; 380 case ENF_CAND: 381 printf("CAND "); 382 break; 383 case ENF_CNOR: 384 printf("CNOR "); 385 break; 386 case ENF_CNAND: 387 printf("CNAND "); 388 break; 389 case ENF_NEQ: 390 printf("NEQ "); 391 break; 392 } 393 394 if (action == ENF_PUSHLIT || 395 action == ENF_LOAD_OFFSET || 396 action == ENF_BRTR || 397 action == ENF_BRFL) { 398 pc++; 399 printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc); 400 } 401 402 printf("\n"); 403 } 404 } 405 406 /* 407 * Emit packet filter code to check a 408 * field in the packet for a particular value. 409 * Need different code for each field size. 410 * Since the pf can only compare 16 bit quantities 411 * we have to use masking to compare byte values. 412 * Long word (32 bit) quantities have to be done 413 * as two 16 bit comparisons. 414 */ 415 static void 416 pf_compare_value(int offset, uint_t len, uint_t val) 417 { 418 /* 419 * If the property being filtered on is absent in the media 420 * packet, error out. 421 */ 422 if (offset == -1) 423 pr_err("filter option unsupported on media"); 424 425 switch (len) { 426 case 1: 427 pf_emit(ENF_PUSHWORD + offset / 2); 428 #if defined(_BIG_ENDIAN) 429 if (offset % 2) 430 #else 431 if (!(offset % 2)) 432 #endif 433 { 434 #ifdef ENF_PUSH00FF 435 pf_emit(ENF_PUSH00FF | ENF_AND); 436 #else 437 pf_emit(ENF_PUSHLIT | ENF_AND); 438 pf_emit(0x00FF); 439 #endif 440 pf_emit(ENF_PUSHLIT | ENF_EQ); 441 pf_emit(val); 442 } else { 443 #ifdef ENF_PUSHFF00 444 pf_emit(ENF_PUSHFF00 | ENF_AND); 445 #else 446 pf_emit(ENF_PUSHLIT | ENF_AND); 447 pf_emit(0xFF00); 448 #endif 449 pf_emit(ENF_PUSHLIT | ENF_EQ); 450 pf_emit(val << 8); 451 } 452 break; 453 454 case 2: 455 pf_emit(ENF_PUSHWORD + offset / 2); 456 pf_emit(ENF_PUSHLIT | ENF_EQ); 457 pf_emit((ushort_t)val); 458 break; 459 460 case 4: 461 pf_emit(ENF_PUSHWORD + offset / 2); 462 pf_emit(ENF_PUSHLIT | ENF_EQ); 463 #if defined(_BIG_ENDIAN) 464 pf_emit(val >> 16); 465 #elif defined(_LITTLE_ENDIAN) 466 pf_emit(val & 0xffff); 467 #else 468 #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined 469 #endif 470 pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 471 pf_emit(ENF_PUSHLIT | ENF_EQ); 472 #if defined(_BIG_ENDIAN) 473 pf_emit(val & 0xffff); 474 #else 475 pf_emit(val >> 16); 476 #endif 477 pf_emit(ENF_AND); 478 break; 479 } 480 } 481 482 /* 483 * same as pf_compare_value, but only for emiting code to 484 * compare ipv6 addresses. 485 */ 486 static void 487 pf_compare_value_v6(int offset, uint_t len, struct in6_addr val) 488 { 489 int i; 490 491 for (i = 0; i < len; i += 2) { 492 pf_emit(ENF_PUSHWORD + offset / 2 + i / 2); 493 pf_emit(ENF_PUSHLIT | ENF_EQ); 494 pf_emit(*(uint16_t *)&val.s6_addr[i]); 495 if (i != 0) 496 pf_emit(ENF_AND); 497 } 498 } 499 500 501 /* 502 * Same as above except mask the field value 503 * before doing the comparison. The comparison checks 504 * to make sure the values are equal. 505 */ 506 static void 507 pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) 508 { 509 pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ); 510 } 511 512 /* 513 * Same as above except the values are compared to see if they are not 514 * equal. 515 */ 516 static void 517 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask) 518 { 519 pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ); 520 } 521 522 /* 523 * Similar to pf_compare_value. 524 * 525 * This is the utility function that does the actual work to compare 526 * two values using a mask. The comparison operation is passed into 527 * the function. 528 */ 529 static void 530 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask, 531 uint_t op) 532 { 533 /* 534 * If the property being filtered on is absent in the media 535 * packet, error out. 536 */ 537 if (offset == -1) 538 pr_err("filter option unsupported on media"); 539 540 switch (len) { 541 case 1: 542 pf_emit(ENF_PUSHWORD + offset / 2); 543 #if defined(_BIG_ENDIAN) 544 if (offset % 2) 545 #else 546 if (!offset % 2) 547 #endif 548 { 549 pf_emit(ENF_PUSHLIT | ENF_AND); 550 pf_emit(mask & 0x00ff); 551 pf_emit(ENF_PUSHLIT | op); 552 pf_emit(val); 553 } else { 554 pf_emit(ENF_PUSHLIT | ENF_AND); 555 pf_emit((mask << 8) & 0xff00); 556 pf_emit(ENF_PUSHLIT | op); 557 pf_emit(val << 8); 558 } 559 break; 560 561 case 2: 562 pf_emit(ENF_PUSHWORD + offset / 2); 563 pf_emit(ENF_PUSHLIT | ENF_AND); 564 pf_emit(htons((ushort_t)mask)); 565 pf_emit(ENF_PUSHLIT | op); 566 pf_emit(htons((ushort_t)val)); 567 break; 568 569 case 4: 570 pf_emit(ENF_PUSHWORD + offset / 2); 571 pf_emit(ENF_PUSHLIT | ENF_AND); 572 pf_emit(htons((ushort_t)((mask >> 16) & 0xffff))); 573 pf_emit(ENF_PUSHLIT | op); 574 pf_emit(htons((ushort_t)((val >> 16) & 0xffff))); 575 576 pf_emit(ENF_PUSHWORD + (offset / 2) + 1); 577 pf_emit(ENF_PUSHLIT | ENF_AND); 578 pf_emit(htons((ushort_t)(mask & 0xffff))); 579 pf_emit(ENF_PUSHLIT | op); 580 pf_emit(htons((ushort_t)(val & 0xffff))); 581 582 pf_emit(ENF_AND); 583 break; 584 } 585 } 586 587 /* 588 * Like pf_compare_value() but compare on a 32-bit zoneid value. 589 * The argument val passed in is in network byte order. 590 */ 591 static void 592 pf_compare_zoneid(int offset, uint32_t val) 593 { 594 int i; 595 596 for (i = 0; i < sizeof (uint32_t) / 2; i ++) { 597 pf_emit(ENF_PUSHWORD + offset / 2 + i); 598 pf_emit(ENF_PUSHLIT | ENF_EQ); 599 pf_emit(((uint16_t *)&val)[i]); 600 if (i != 0) 601 pf_emit(ENF_AND); 602 } 603 } 604 605 /* 606 * Generate pf code to match an IPv4 or IPv6 address. 607 */ 608 static void 609 pf_ipaddr_match(which, hostname, inet_type) 610 enum direction which; 611 char *hostname; 612 int inet_type; 613 { 614 bool_t found_host; 615 uint_t *addr4ptr; 616 uint_t addr4; 617 struct in6_addr *addr6ptr; 618 int h_addr_index; 619 struct hostent *hp = NULL; 620 int error_num = 0; 621 boolean_t first = B_TRUE; 622 int pass = 0; 623 int i; 624 625 /* 626 * The addr4offset and addr6offset variables simplify the code which 627 * generates the address comparison filter. With these two variables, 628 * duplicate code need not exist for the TO and FROM case. 629 * A value of -1 describes the ANY case (TO and FROM). 630 */ 631 int addr4offset; 632 int addr6offset; 633 634 found_host = 0; 635 636 if (tokentype == ADDR_IP) { 637 hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 638 if (hp == NULL) { 639 if (error_num == TRY_AGAIN) { 640 pr_err("could not resolve %s (try again later)", 641 hostname); 642 } else { 643 pr_err("could not resolve %s", hostname); 644 } 645 } 646 inet_type = IPV4_ONLY; 647 } else if (tokentype == ADDR_IP6) { 648 hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 649 if (hp == NULL) { 650 if (error_num == TRY_AGAIN) { 651 pr_err("could not resolve %s (try again later)", 652 hostname); 653 } else { 654 pr_err("could not resolve %s", hostname); 655 } 656 } 657 inet_type = IPV6_ONLY; 658 } else if (tokentype == ALPHA) { 659 /* Some hostname i.e. tokentype is ALPHA */ 660 switch (inet_type) { 661 case IPV4_ONLY: 662 /* Only IPv4 address is needed */ 663 hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 664 if (hp != NULL) { 665 found_host = 1; 666 } 667 break; 668 case IPV6_ONLY: 669 /* Only IPv6 address is needed */ 670 hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 671 if (hp != NULL) { 672 found_host = 1; 673 } 674 break; 675 case IPV4_AND_IPV6: 676 /* Both IPv4 and IPv6 are needed */ 677 hp = getipnodebyname(hostname, AF_INET6, 678 AI_ALL | AI_V4MAPPED, &error_num); 679 if (hp != NULL) { 680 found_host = 1; 681 } 682 break; 683 default: 684 found_host = 0; 685 } 686 687 if (!found_host) { 688 if (error_num == TRY_AGAIN) { 689 pr_err("could not resolve %s (try again later)", 690 hostname); 691 } else { 692 pr_err("could not resolve %s", hostname); 693 } 694 } 695 } else { 696 pr_err("unknown token type: %s", hostname); 697 } 698 699 switch (which) { 700 case TO: 701 addr4offset = IPV4_DSTADDR_OFFSET; 702 addr6offset = IPV6_DSTADDR_OFFSET; 703 break; 704 case FROM: 705 addr4offset = IPV4_SRCADDR_OFFSET; 706 addr6offset = IPV6_SRCADDR_OFFSET; 707 break; 708 case ANY: 709 addr4offset = -1; 710 addr6offset = -1; 711 break; 712 } 713 714 if (hp != NULL && hp->h_addrtype == AF_INET) { 715 pf_matchfn("ip"); 716 if (dl.dl_type == DL_ETHER) 717 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 718 h_addr_index = 0; 719 addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index]; 720 while (addr4ptr != NULL) { 721 if (addr4offset == -1) { 722 pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 723 *addr4ptr); 724 if (h_addr_index != 0) 725 pf_emit(ENF_OR); 726 pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 727 *addr4ptr); 728 pf_emit(ENF_OR); 729 } else { 730 pf_compare_value(addr4offset, 4, 731 *addr4ptr); 732 if (h_addr_index != 0) 733 pf_emit(ENF_OR); 734 } 735 addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index]; 736 } 737 pf_emit(ENF_AND); 738 } else { 739 /* first pass: IPv4 addresses */ 740 h_addr_index = 0; 741 addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 742 first = B_TRUE; 743 while (addr6ptr != NULL) { 744 if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 745 if (first) { 746 pf_matchfn("ip"); 747 if (dl.dl_type == DL_ETHER) { 748 pf_check_vlan_tag( 749 ENCAP_ETHERTYPE_OFF/2); 750 } 751 pass++; 752 } 753 IN6_V4MAPPED_TO_INADDR(addr6ptr, 754 (struct in_addr *)&addr4); 755 if (addr4offset == -1) { 756 pf_compare_value(IPV4_SRCADDR_OFFSET, 4, 757 addr4); 758 if (!first) 759 pf_emit(ENF_OR); 760 pf_compare_value(IPV4_DSTADDR_OFFSET, 4, 761 addr4); 762 pf_emit(ENF_OR); 763 } else { 764 pf_compare_value(addr4offset, 4, 765 addr4); 766 if (!first) 767 pf_emit(ENF_OR); 768 } 769 if (first) 770 first = B_FALSE; 771 } 772 addr6ptr = (struct in6_addr *) 773 hp->h_addr_list[++h_addr_index]; 774 } 775 if (!first) { 776 pf_emit(ENF_AND); 777 } 778 /* second pass: IPv6 addresses */ 779 h_addr_index = 0; 780 addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 781 first = B_TRUE; 782 while (addr6ptr != NULL) { 783 if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 784 if (first) { 785 pf_matchfn("ip6"); 786 if (dl.dl_type == DL_ETHER) { 787 pf_check_vlan_tag( 788 ENCAP_ETHERTYPE_OFF/2); 789 } 790 pass++; 791 } 792 if (addr6offset == -1) { 793 pf_compare_value_v6(IPV6_SRCADDR_OFFSET, 794 16, *addr6ptr); 795 if (!first) 796 pf_emit(ENF_OR); 797 pf_compare_value_v6(IPV6_DSTADDR_OFFSET, 798 16, *addr6ptr); 799 pf_emit(ENF_OR); 800 } else { 801 pf_compare_value_v6(addr6offset, 16, 802 *addr6ptr); 803 if (!first) 804 pf_emit(ENF_OR); 805 } 806 if (first) 807 first = B_FALSE; 808 } 809 addr6ptr = (struct in6_addr *) 810 hp->h_addr_list[++h_addr_index]; 811 } 812 if (!first) { 813 pf_emit(ENF_AND); 814 } 815 if (pass == 2) { 816 pf_emit(ENF_OR); 817 } 818 } 819 820 if (hp != NULL) { 821 freehostent(hp); 822 } 823 } 824 825 826 static void 827 pf_compare_address(int offset, uint_t len, uchar_t *addr) 828 { 829 uint32_t val; 830 uint16_t sval; 831 boolean_t didone = B_FALSE; 832 833 /* 834 * If the property being filtered on is absent in the media 835 * packet, error out. 836 */ 837 if (offset == -1) 838 pr_err("filter option unsupported on media"); 839 840 while (len > 0) { 841 if (len >= 4) { 842 (void) memcpy(&val, addr, 4); 843 pf_compare_value(offset, 4, val); 844 addr += 4; 845 offset += 4; 846 len -= 4; 847 } else if (len >= 2) { 848 (void) memcpy(&sval, addr, 2); 849 pf_compare_value(offset, 2, sval); 850 addr += 2; 851 offset += 2; 852 len -= 2; 853 } else { 854 pf_compare_value(offset++, 1, *addr++); 855 len--; 856 } 857 if (didone) 858 pf_emit(ENF_AND); 859 didone = B_TRUE; 860 } 861 } 862 863 /* 864 * Compare ethernet addresses. 865 */ 866 static void 867 pf_etheraddr_match(which, hostname) 868 enum direction which; 869 char *hostname; 870 { 871 struct ether_addr e, *ep = NULL; 872 873 if (isxdigit(*hostname)) 874 ep = ether_aton(hostname); 875 if (ep == NULL) { 876 if (ether_hostton(hostname, &e)) 877 if (!arp_for_ether(hostname, &e)) 878 pr_err("cannot obtain ether addr for %s", 879 hostname); 880 ep = &e; 881 } 882 883 pf_clear_offset_register(); 884 885 switch (which) { 886 case TO: 887 pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len, 888 (uchar_t *)ep); 889 break; 890 case FROM: 891 pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len, 892 (uchar_t *)ep); 893 break; 894 case ANY: 895 pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len, 896 (uchar_t *)ep); 897 pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len, 898 (uchar_t *)ep); 899 pf_emit(ENF_OR); 900 break; 901 } 902 } 903 904 /* 905 * Emit code to compare the network part of 906 * an IP address. 907 */ 908 static void 909 pf_netaddr_match(which, netname) 910 enum direction which; 911 char *netname; 912 { 913 uint_t addr; 914 uint_t mask = 0xff000000; 915 struct netent *np; 916 917 if (isdigit(*netname)) { 918 addr = inet_network(netname); 919 } else { 920 np = getnetbyname(netname); 921 if (np == NULL) 922 pr_err("net %s not known", netname); 923 addr = np->n_net; 924 } 925 926 /* 927 * Left justify the address and figure 928 * out a mask based on the supplied address. 929 * Set the mask according to the number of zero 930 * low-order bytes. 931 * Note: this works only for whole octet masks. 932 */ 933 if (addr) { 934 while ((addr & ~mask) != 0) { 935 mask |= (mask >> 8); 936 } 937 } 938 939 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 940 941 switch (which) { 942 case TO: 943 pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 944 break; 945 case FROM: 946 pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 947 break; 948 case ANY: 949 pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask); 950 pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); 951 pf_emit(ENF_OR); 952 break; 953 } 954 } 955 956 /* 957 * Emit code to match on src or destination zoneid. 958 * The zoneid passed in is in network byte order. 959 */ 960 static void 961 pf_match_zone(enum direction which, uint32_t zoneid) 962 { 963 if (dl.dl_type != DL_IPNET) 964 pr_err("zone filter option unsupported on media"); 965 966 switch (which) { 967 case TO: 968 pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid); 969 break; 970 case FROM: 971 pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid); 972 break; 973 case ANY: 974 pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid); 975 pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid); 976 pf_emit(ENF_OR); 977 break; 978 } 979 } 980 981 /* 982 * A helper function to keep the code to emit instructions 983 * to change the offset register in one place. 984 * 985 * INPUTS: offset - An value representing an offset in 16-bit 986 * words. 987 * OUTPUTS: If there is enough room in the storage for the 988 * packet filtering program, instructions to load 989 * a constant to the offset register. Otherwise, 990 * nothing. 991 */ 992 static void 993 pf_emit_load_offset(uint_t offset) 994 { 995 pf_emit(ENF_LOAD_OFFSET | ENF_NOP); 996 pf_emit(offset); 997 } 998 999 /* 1000 * Clear pfmod's offset register. 1001 * 1002 * INPUTS: none 1003 * OUTPUTS: Instructions to clear the offset register if 1004 * there is enough space remaining in the packet 1005 * filtering program structure's storage, and 1006 * the last thing done to the offset register was 1007 * not clearing the offset register. Otherwise, 1008 * nothing. 1009 */ 1010 static void 1011 pf_clear_offset_register() 1012 { 1013 if (last_offset_operation != (void*)pf_clear_offset_register) { 1014 pf_emit_load_offset(0); 1015 last_offset_operation = (void*)pf_clear_offset_register; 1016 } 1017 } 1018 1019 /* 1020 * This function will issue opcodes to check if a packet 1021 * is VLAN tagged, and if so, update the offset register 1022 * with the appropriate offset. 1023 * 1024 * Note that if the packet is not VLAN tagged, then the offset 1025 * register will be cleared. 1026 * 1027 * If the interface type is not an ethernet type, then this 1028 * function returns without doing anything. 1029 * 1030 * If the last attempt to change the offset register occured because 1031 * of a call to this function that was called with the same offset, 1032 * then we don't issue packet filtering instructions. 1033 * 1034 * INPUTS: offset - an offset in 16 bit words. The function 1035 * will set the offset register to this 1036 * value if the packet is VLAN tagged. 1037 * OUTPUTS: If the conditions are met, packet filtering instructions. 1038 */ 1039 static void 1040 pf_check_vlan_tag(uint_t offset) 1041 { 1042 static uint_t last_offset = 0; 1043 1044 if ((interface->mac_type == DL_ETHER || 1045 interface->mac_type == DL_CSMACD) && 1046 (last_offset_operation != (void*)pf_check_vlan_tag || 1047 last_offset != offset)) { 1048 /* 1049 * First thing is to clear the offset register. 1050 * We don't know what state it is in, and if it 1051 * is not zero, then we have no idea what we load 1052 * when we execute ENF_PUSHWORD. 1053 */ 1054 pf_clear_offset_register(); 1055 1056 /* 1057 * Check the ethertype. 1058 */ 1059 pf_compare_value(dl.dl_link_type_offset, 2, 1060 htons(ETHERTYPE_VLAN)); 1061 1062 /* 1063 * And if it's not VLAN, don't load offset to the offset 1064 * register. 1065 */ 1066 pf_emit(ENF_BRFL | ENF_NOP); 1067 pf_emit(3); 1068 1069 /* 1070 * Otherwise, load offset to the offset register. 1071 */ 1072 pf_emit_load_offset(offset); 1073 1074 /* 1075 * Now get rid of the results of the comparison, 1076 * we don't want the results of the comparison to affect 1077 * other logic in the packet filtering program. 1078 */ 1079 pf_emit(ENF_POP | ENF_NOP); 1080 1081 /* 1082 * Set the last operation at the end, or any time 1083 * after the call to pf_clear_offset because 1084 * pf_clear_offset uses it. 1085 */ 1086 last_offset_operation = (void*)pf_check_vlan_tag; 1087 last_offset = offset; 1088 } 1089 } 1090 1091 /* 1092 * Utility function used to emit packet filtering code 1093 * to match an ethertype. 1094 * 1095 * INPUTS: ethertype - The ethertype we want to check for. 1096 * Don't call htons on the ethertype before 1097 * calling this function. 1098 * OUTPUTS: If there is sufficient storage available, packet 1099 * filtering code to check an ethertype. Otherwise, 1100 * nothing. 1101 */ 1102 static void 1103 pf_match_ethertype(uint_t ethertype) 1104 { 1105 /* 1106 * If the user wants to filter on ethertype VLAN, 1107 * then clear the offset register so that the offset 1108 * for ENF_PUSHWORD points to the right place in the 1109 * packet. 1110 * 1111 * Otherwise, call pf_check_vlan_tag to set the offset 1112 * register such that the contents of the offset register 1113 * plus the argument for ENF_PUSHWORD point to the right 1114 * part of the packet, whether or not the packet is VLAN 1115 * tagged. We call pf_check_vlan_tag with an offset of 1116 * two words because if the packet is VLAN tagged, we have 1117 * to move past the ethertype in the ethernet header, and 1118 * past the lower two octets of the VLAN header to get to 1119 * the ethertype in the VLAN header. 1120 */ 1121 if (ethertype == ETHERTYPE_VLAN) 1122 pf_clear_offset_register(); 1123 else 1124 pf_check_vlan_tag(2); 1125 1126 pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype)); 1127 } 1128 1129 static void 1130 pf_match_ipnettype(uint_t type) 1131 { 1132 pf_compare_value(dl.dl_link_type_offset, 2, htons(type)); 1133 } 1134 1135 static void 1136 pf_match_ibtype(uint_t type) 1137 { 1138 pf_compare_value(dl.dl_link_type_offset, 2, htons(type)); 1139 } 1140 1141 /* 1142 * This function uses the table above to generate a 1143 * piece of a packet filtering program to check a transport 1144 * protocol type. 1145 * 1146 * INPUTS: tranport_protocol - the transport protocol we're 1147 * interested in. 1148 * OUTPUTS: If there is sufficient storage, then packet filtering 1149 * code to check a transport protocol type. Otherwise, 1150 * nothing. 1151 */ 1152 static void 1153 pf_check_transport_protocol(uint_t transport_protocol) 1154 { 1155 int i; 1156 uint_t number_of_matches = 0; 1157 1158 for (i = 0; dl.dl_trans_map_tbl[i].transport_protocol != -1; i++) { 1159 if (transport_protocol == 1160 (uint_t)dl.dl_trans_map_tbl[i].transport_protocol) { 1161 number_of_matches++; 1162 dl.dl_match_fn(dl.dl_trans_map_tbl[i].network_protocol); 1163 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 1164 pf_compare_value(dl.dl_trans_map_tbl[i].offset + 1165 dl.dl_link_header_len, 1, 1166 transport_protocol); 1167 pf_emit(ENF_AND); 1168 if (number_of_matches > 1) { 1169 /* 1170 * Since we have two or more matches, in 1171 * order to have a correct and complete 1172 * program we need to OR the result of 1173 * each block of comparisons together. 1174 */ 1175 pf_emit(ENF_OR); 1176 } 1177 } 1178 } 1179 } 1180 1181 static void 1182 pf_matchfn(const char *proto) 1183 { 1184 int i; 1185 1186 for (i = 0; dl.dl_net_map_tbl[i].nmt_val != -1; i++) { 1187 if (strcmp(proto, dl.dl_net_map_tbl[i].nmt_name) == 0) { 1188 dl.dl_match_fn(dl.dl_net_map_tbl[i].nmt_val); 1189 break; 1190 } 1191 } 1192 } 1193 1194 static void 1195 pf_primary() 1196 { 1197 for (;;) { 1198 if (tokentype == FIELD) 1199 break; 1200 1201 if (EQ("ip")) { 1202 pf_matchfn("ip"); 1203 opstack++; 1204 next(); 1205 break; 1206 } 1207 1208 if (EQ("ip6")) { 1209 pf_matchfn("ip6"); 1210 opstack++; 1211 next(); 1212 break; 1213 } 1214 1215 if (EQ("pppoe")) { 1216 pf_matchfn("pppoe"); 1217 pf_match_ethertype(ETHERTYPE_PPPOES); 1218 pf_emit(ENF_OR); 1219 opstack++; 1220 next(); 1221 break; 1222 } 1223 1224 if (EQ("pppoed")) { 1225 pf_matchfn("pppoed"); 1226 opstack++; 1227 next(); 1228 break; 1229 } 1230 1231 if (EQ("pppoes")) { 1232 pf_matchfn("pppoes"); 1233 opstack++; 1234 next(); 1235 break; 1236 } 1237 1238 if (EQ("arp")) { 1239 pf_matchfn("arp"); 1240 opstack++; 1241 next(); 1242 break; 1243 } 1244 1245 if (EQ("vlan")) { 1246 pf_matchfn("vlan"); 1247 pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2, 1248 0, VLAN_ID_MASK); 1249 pf_emit(ENF_AND); 1250 opstack++; 1251 next(); 1252 break; 1253 } 1254 1255 if (EQ("vlan-id")) { 1256 next(); 1257 if (tokentype != NUMBER) 1258 pr_err("VLAN ID expected"); 1259 pf_matchfn("vlan-id"); 1260 pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval, 1261 VLAN_ID_MASK); 1262 pf_emit(ENF_AND); 1263 opstack++; 1264 next(); 1265 break; 1266 } 1267 1268 if (EQ("rarp")) { 1269 pf_matchfn("rarp"); 1270 opstack++; 1271 next(); 1272 break; 1273 } 1274 1275 if (EQ("tcp")) { 1276 pf_check_transport_protocol(IPPROTO_TCP); 1277 opstack++; 1278 next(); 1279 break; 1280 } 1281 1282 if (EQ("udp")) { 1283 pf_check_transport_protocol(IPPROTO_UDP); 1284 opstack++; 1285 next(); 1286 break; 1287 } 1288 1289 if (EQ("ospf")) { 1290 pf_check_transport_protocol(IPPROTO_OSPF); 1291 opstack++; 1292 next(); 1293 break; 1294 } 1295 1296 1297 if (EQ("sctp")) { 1298 pf_check_transport_protocol(IPPROTO_SCTP); 1299 opstack++; 1300 next(); 1301 break; 1302 } 1303 1304 if (EQ("icmp")) { 1305 pf_check_transport_protocol(IPPROTO_ICMP); 1306 opstack++; 1307 next(); 1308 break; 1309 } 1310 1311 if (EQ("icmp6")) { 1312 pf_check_transport_protocol(IPPROTO_ICMPV6); 1313 opstack++; 1314 next(); 1315 break; 1316 } 1317 1318 if (EQ("ip-in-ip")) { 1319 pf_check_transport_protocol(IPPROTO_ENCAP); 1320 opstack++; 1321 next(); 1322 break; 1323 } 1324 1325 if (EQ("esp")) { 1326 pf_check_transport_protocol(IPPROTO_ESP); 1327 opstack++; 1328 next(); 1329 break; 1330 } 1331 1332 if (EQ("ah")) { 1333 pf_check_transport_protocol(IPPROTO_AH); 1334 opstack++; 1335 next(); 1336 break; 1337 } 1338 1339 if (EQ("dccp")) { 1340 pf_check_transport_protocol(IPPROTO_DCCP); 1341 opstack++; 1342 next(); 1343 break; 1344 } 1345 1346 if (EQ("(")) { 1347 inBrace++; 1348 next(); 1349 pf_expression(); 1350 if (EQ(")")) { 1351 if (inBrace) 1352 inBraceOR--; 1353 inBrace--; 1354 next(); 1355 } 1356 break; 1357 } 1358 1359 if (EQ("to") || EQ("dst")) { 1360 dir = TO; 1361 next(); 1362 continue; 1363 } 1364 1365 if (EQ("from") || EQ("src")) { 1366 dir = FROM; 1367 next(); 1368 continue; 1369 } 1370 1371 if (EQ("ether")) { 1372 eaddr = 1; 1373 next(); 1374 continue; 1375 } 1376 1377 if (EQ("inet")) { 1378 next(); 1379 if (EQ("host")) 1380 next(); 1381 if (tokentype != ALPHA && tokentype != ADDR_IP) 1382 pr_err("host/IPv4 addr expected after inet"); 1383 pf_ipaddr_match(dir, token, IPV4_ONLY); 1384 opstack++; 1385 next(); 1386 break; 1387 } 1388 1389 if (EQ("inet6")) { 1390 next(); 1391 if (EQ("host")) 1392 next(); 1393 if (tokentype != ALPHA && tokentype != ADDR_IP6) 1394 pr_err("host/IPv6 addr expected after inet6"); 1395 pf_ipaddr_match(dir, token, IPV6_ONLY); 1396 opstack++; 1397 next(); 1398 break; 1399 } 1400 1401 if (EQ("proto")) { 1402 next(); 1403 if (tokentype != NUMBER) 1404 pr_err("IP proto type expected"); 1405 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); 1406 pf_compare_value( 1407 IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1, 1408 tokenval); 1409 opstack++; 1410 next(); 1411 break; 1412 } 1413 1414 if (EQ("broadcast")) { 1415 pf_clear_offset_register(); 1416 pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff); 1417 opstack++; 1418 next(); 1419 break; 1420 } 1421 1422 if (EQ("multicast")) { 1423 pf_clear_offset_register(); 1424 pf_compare_value_mask( 1425 dl.dl_link_dest_offset, 1, 0x01, 0x01); 1426 opstack++; 1427 next(); 1428 break; 1429 } 1430 1431 if (EQ("ethertype")) { 1432 next(); 1433 if (tokentype != NUMBER) 1434 pr_err("ether type expected"); 1435 pf_match_ethertype(tokenval); 1436 opstack++; 1437 next(); 1438 break; 1439 } 1440 1441 if (EQ("net") || EQ("dstnet") || EQ("srcnet")) { 1442 if (EQ("dstnet")) 1443 dir = TO; 1444 else if (EQ("srcnet")) 1445 dir = FROM; 1446 next(); 1447 pf_netaddr_match(dir, token); 1448 dir = ANY; 1449 opstack++; 1450 next(); 1451 break; 1452 } 1453 1454 if (EQ("zone")) { 1455 next(); 1456 if (tokentype != NUMBER) 1457 pr_err("zoneid expected after inet"); 1458 pf_match_zone(dir, BE_32((uint32_t)(tokenval))); 1459 opstack++; 1460 next(); 1461 break; 1462 } 1463 1464 /* 1465 * Give up on anything that's obviously 1466 * not a primary. 1467 */ 1468 if (EQ("and") || EQ("or") || 1469 EQ("not") || EQ("decnet") || EQ("apple") || 1470 EQ("length") || EQ("less") || EQ("greater") || 1471 EQ("port") || EQ("srcport") || EQ("dstport") || 1472 EQ("rpc") || EQ("gateway") || EQ("nofrag") || 1473 EQ("bootp") || EQ("dhcp") || EQ("dhcp6") || 1474 EQ("slp") || EQ("ldap")) { 1475 break; 1476 } 1477 1478 if (EQ("host") || EQ("between") || 1479 tokentype == ALPHA || /* assume its a hostname */ 1480 tokentype == ADDR_IP || 1481 tokentype == ADDR_IP6 || 1482 tokentype == ADDR_ETHER) { 1483 if (EQ("host") || EQ("between")) 1484 next(); 1485 if (eaddr || tokentype == ADDR_ETHER) { 1486 pf_etheraddr_match(dir, token); 1487 } else if (tokentype == ALPHA) { 1488 pf_ipaddr_match(dir, token, IPV4_AND_IPV6); 1489 } else if (tokentype == ADDR_IP) { 1490 pf_ipaddr_match(dir, token, IPV4_ONLY); 1491 } else { 1492 pf_ipaddr_match(dir, token, IPV6_ONLY); 1493 } 1494 dir = ANY; 1495 eaddr = 0; 1496 opstack++; 1497 next(); 1498 break; 1499 } 1500 1501 break; /* unknown token */ 1502 } 1503 } 1504 1505 static void 1506 pf_alternation() 1507 { 1508 int s = opstack; 1509 1510 pf_primary(); 1511 for (;;) { 1512 if (EQ("and")) 1513 next(); 1514 pf_primary(); 1515 if (opstack != s + 2) 1516 break; 1517 pf_emit(ENF_AND); 1518 opstack--; 1519 } 1520 } 1521 1522 static void 1523 pf_expression() 1524 { 1525 pf_alternation(); 1526 while (EQ("or") || EQ(",")) { 1527 if (inBrace) 1528 inBraceOR++; 1529 else 1530 foundOR++; 1531 next(); 1532 pf_alternation(); 1533 pf_emit(ENF_OR); 1534 opstack--; 1535 } 1536 } 1537 1538 /* 1539 * Attempt to compile the expression 1540 * in the string "e". If we can generate 1541 * pf code for it then return 1 - otherwise 1542 * return 0 and leave it up to the user-level 1543 * filter. 1544 */ 1545 int 1546 pf_compile(e, print) 1547 char *e; 1548 int print; 1549 { 1550 char *argstr; 1551 char *sav_str, *ptr, *sav_ptr; 1552 int inBr = 0, aheadOR = 0; 1553 1554 argstr = strdup(e); 1555 sav_str = e; 1556 tkp = argstr; 1557 dir = ANY; 1558 1559 pfp = &pf.Pf_Filter[0]; 1560 if (setjmp(env)) { 1561 return (0); 1562 } 1563 1564 /* 1565 * Set media specific packet offsets that this code uses. 1566 */ 1567 if (interface->mac_type == DL_ETHER) { 1568 dl.dl_type = DL_ETHER; 1569 dl.dl_match_fn = pf_match_ethertype; 1570 dl.dl_trans_map_tbl = ether_transport_mapping_table; 1571 dl.dl_net_map_tbl = ether_network_mapping_table; 1572 dl.dl_link_header_len = 14; 1573 dl.dl_link_type_offset = 12; 1574 dl.dl_link_dest_offset = 0; 1575 dl.dl_link_src_offset = 6; 1576 dl.dl_link_addr_len = 6; 1577 } 1578 1579 if (interface->mac_type == DL_IB) { 1580 dl.dl_type = DL_IB; 1581 dl.dl_link_header_len = 4; 1582 dl.dl_link_type_offset = 0; 1583 dl.dl_link_dest_offset = dl.dl_link_src_offset = -1; 1584 dl.dl_link_addr_len = 20; 1585 dl.dl_match_fn = pf_match_ibtype; 1586 dl.dl_trans_map_tbl = ib_transport_mapping_table; 1587 dl.dl_net_map_tbl = ib_network_mapping_table; 1588 } 1589 1590 if (interface->mac_type == DL_IPNET) { 1591 dl.dl_type = DL_IPNET; 1592 dl.dl_link_header_len = 24; 1593 dl.dl_link_type_offset = 0; 1594 dl.dl_link_dest_offset = dl.dl_link_src_offset = -1; 1595 dl.dl_link_addr_len = -1; 1596 dl.dl_match_fn = pf_match_ipnettype; 1597 dl.dl_trans_map_tbl = ipnet_transport_mapping_table; 1598 dl.dl_net_map_tbl = ipnet_network_mapping_table; 1599 } 1600 1601 next(); 1602 pf_expression(); 1603 1604 if (tokentype != EOL) { 1605 /* 1606 * The idea here is to do as much filtering as possible in 1607 * the kernel. So even if we find a token we don't understand, 1608 * we try to see if we can still set up a portion of the filter 1609 * in the kernel and use the userland filter to filter the 1610 * remaining stuff. Obviously, if our filter expression is of 1611 * type A AND B, we can filter A in kernel and then apply B 1612 * to the packets that got through. The same is not true for 1613 * a filter of type A OR B. We can't apply A first and then B 1614 * on the packets filtered through A. 1615 * 1616 * (We need to keep track of the fact when we find an OR, 1617 * and the fact that we are inside brackets when we find OR. 1618 * The variable 'foundOR' tells us if there was an OR behind, 1619 * 'inBraceOR' tells us if we found an OR before we could find 1620 * the end brace i.e. ')', and variable 'aheadOR' checks if 1621 * there is an OR in the expression ahead. if either of these 1622 * cases become true, we can't split the filtering) 1623 */ 1624 1625 if (foundOR || inBraceOR) { 1626 /* FORGET IN KERNEL FILTERING */ 1627 return (0); 1628 } else { 1629 1630 /* CHECK IF NO OR AHEAD */ 1631 sav_ptr = (char *)((uintptr_t)sav_str + 1632 (uintptr_t)sav_tkp - 1633 (uintptr_t)argstr); 1634 ptr = sav_ptr; 1635 while (*ptr != '\0') { 1636 switch (*ptr) { 1637 case '(': 1638 inBr++; 1639 break; 1640 case ')': 1641 inBr--; 1642 break; 1643 case 'o': 1644 case 'O': 1645 if ((*(ptr + 1) == 'R' || 1646 *(ptr + 1) == 'r') && !inBr) 1647 aheadOR = 1; 1648 break; 1649 case ',': 1650 if (!inBr) 1651 aheadOR = 1; 1652 break; 1653 } 1654 ptr++; 1655 } 1656 if (!aheadOR) { 1657 /* NO OR AHEAD, SPLIT UP THE FILTERING */ 1658 pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 1659 pf.Pf_Priority = 5; 1660 if (print) { 1661 pf_codeprint(&pf.Pf_Filter[0], 1662 pf.Pf_FilterLen); 1663 } 1664 compile(sav_ptr, print); 1665 return (2); 1666 } else 1667 return (0); 1668 } 1669 } 1670 1671 pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0]; 1672 pf.Pf_Priority = 5; /* unimportant, so long as > 2 */ 1673 if (print) { 1674 pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen); 1675 } 1676 return (1); 1677 }