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