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