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