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 1715 dg199075 * Common Development and Distribution License (the "License"). 6 1715 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 10616 Sebastien * 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 0 stevel #include <stdlib.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 <stddef.h> 35 10616 Sebastien #include <unistd.h> 36 10616 Sebastien #include <stropts.h> 37 0 stevel #include <sys/socket.h> 38 0 stevel #include <sys/sockio.h> 39 2760 dg199075 #include <sys/vlan.h> 40 0 stevel #include <net/if.h> 41 0 stevel #include <netinet/in.h> 42 0 stevel #include <netinet/ip.h> 43 0 stevel #include <inet/ip6.h> 44 0 stevel #include <inet/ip.h> 45 0 stevel #include <netinet/if_ether.h> 46 0 stevel #include <netinet/tcp.h> 47 0 stevel #include <netinet/udp.h> 48 0 stevel #include <netdb.h> 49 0 stevel #include <arpa/inet.h> 50 0 stevel #include <rpc/rpc.h> 51 0 stevel #include <rpc/rpcent.h> 52 8023 Phil #include <sys/dlpi.h> 53 0 stevel 54 0 stevel #include <snoop.h> 55 2760 dg199075 #include "snoop_vlan.h" 56 0 stevel 57 0 stevel #define IPV4_ONLY 0 58 0 stevel #define IPV6_ONLY 1 59 0 stevel #define IPV4_AND_IPV6 2 60 0 stevel 61 0 stevel /* 62 0 stevel * The following constants represent the offsets in bytes from the beginning 63 0 stevel * of the IP(v6) header of the source and destination IP(v6) addresses. 64 0 stevel * These are useful when generating filter code. 65 0 stevel */ 66 0 stevel #define IPV4_SRCADDR_OFFSET 12 67 0 stevel #define IPV4_DSTADDR_OFFSET 16 68 0 stevel #define IPV6_SRCADDR_OFFSET 8 69 0 stevel #define IPV6_DSTADDR_OFFSET 24 70 0 stevel #define IP_VERS(p) (((*(uchar_t *)p) & 0xf0) >> 4) 71 0 stevel #define MASKED_IPV4_VERS 0x40 72 0 stevel #define MASKED_IPV6_VERS 0x60 73 0 stevel #define IP_HDR_LEN(p) (((*(uchar_t *)p) & 0xf) * 4) 74 0 stevel #define TCP_HDR_LEN(p) ((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4) 75 2760 dg199075 76 0 stevel /* 77 0 stevel * Coding the constant below is tacky, but the compiler won't let us 78 0 stevel * be more clever. E.g., &((struct ip *)0)->ip_xxx 79 0 stevel */ 80 0 stevel #define IP_PROTO_OF(p) (((uchar_t *)p)[9]) 81 0 stevel 82 0 stevel /* 83 0 stevel * AppleTalk uses 802.2 Ethernet encapsulation with LLC/SNAP headers, 84 0 stevel * for 8 octets of overhead, and the common AppleTalk DDP Ethernet 85 0 stevel * header is another 4 octets. 86 0 stevel * 87 0 stevel * The following constants represents the offsets in bytes from the beginning 88 0 stevel * of the Ethernet payload to various parts of the DDP header. 89 0 stevel */ 90 0 stevel 91 0 stevel #define AT_DST_NET_OFFSET 12 92 0 stevel #define AT_SRC_NET_OFFSET 14 93 0 stevel #define AT_DST_NODE_OFFSET 16 94 0 stevel #define AT_SRC_NODE_OFFSET 17 95 8023 Phil 96 8023 Phil /* 97 8023 Phil * Offset for the source and destination zoneid in the ipnet header. 98 8023 Phil */ 99 10639 Darren #define IPNET_SRCZONE_OFFSET 16 100 10639 Darren #define IPNET_DSTZONE_OFFSET 20 101 0 stevel 102 0 stevel int eaddr; /* need ethernet addr */ 103 0 stevel 104 0 stevel int opstack; /* operand stack depth */ 105 0 stevel 106 0 stevel /* 107 0 stevel * These are the operators of the user-level filter. 108 0 stevel * STOP ends execution of the filter expression and 109 0 stevel * returns the truth value at the top of the stack. 110 0 stevel * OP_LOAD_OCTET, OP_LOAD_SHORT and OP_LOAD_LONG pop 111 0 stevel * an offset value from the stack and load a value of 112 0 stevel * an appropriate size from the packet (octet, short or 113 0 stevel * long). The offset is computed from a base value that 114 0 stevel * may be set via the OP_OFFSET operators. 115 0 stevel * OP_EQ, OP_NE, OP_GT, OP_GE, OP_LT, OP_LE pop two values 116 0 stevel * from the stack and return the result of their comparison. 117 0 stevel * OP_AND, OP_OR, OP_XOR pop two values from the stack and 118 0 stevel * do perform a bitwise operation on them - returning a result 119 0 stevel * to the stack. OP_NOT inverts the bits of the value on the 120 0 stevel * stack. 121 0 stevel * OP_BRFL and OP_BRTR branch to an offset in the code array 122 0 stevel * depending on the value at the top of the stack: true (not 0) 123 0 stevel * or false (0). 124 0 stevel * OP_ADD, OP_SUB, OP_MUL, OP_DIV and OP_REM pop two values 125 0 stevel * from the stack and perform arithmetic. 126 0 stevel * The OP_OFFSET operators change the base from which the 127 0 stevel * OP_LOAD operators compute their offsets. 128 0 stevel * OP_OFFSET_ZERO sets the offset to zero - beginning of packet. 129 0 stevel * OP_OFFSET_LINK sets the base to the first octet after 130 0 stevel * the link (DLC) header. OP_OFFSET_IP, OP_OFFSET_TCP, 131 0 stevel * and OP_OFFSET_UDP do the same for those headers - they 132 0 stevel * set the offset base to the *end* of the header - not the 133 0 stevel * beginning. The OP_OFFSET_RPC operator is a bit unusual. 134 0 stevel * It points the base at the cached RPC header. For the 135 0 stevel * purposes of selection, RPC reply headers look like call 136 0 stevel * headers except for the direction value. 137 2760 dg199075 * OP_OFFSET_ETHERTYPE sets base according to the following 138 2760 dg199075 * algorithm: 139 2760 dg199075 * if the packet is not VLAN tagged, then set base to 140 2760 dg199075 * the ethertype field in the ethernet header 141 2760 dg199075 * else set base to the ethertype field of the VLAN header 142 0 stevel * OP_OFFSET_POP restores the offset base to the value prior 143 0 stevel * to the most recent OP_OFFSET call. 144 0 stevel */ 145 0 stevel enum optype { 146 0 stevel OP_STOP = 0, 147 0 stevel OP_LOAD_OCTET, 148 0 stevel OP_LOAD_SHORT, 149 0 stevel OP_LOAD_LONG, 150 0 stevel OP_LOAD_CONST, 151 0 stevel OP_LOAD_LENGTH, 152 0 stevel OP_EQ, 153 0 stevel OP_NE, 154 0 stevel OP_GT, 155 0 stevel OP_GE, 156 0 stevel OP_LT, 157 0 stevel OP_LE, 158 0 stevel OP_AND, 159 0 stevel OP_OR, 160 0 stevel OP_XOR, 161 0 stevel OP_NOT, 162 0 stevel OP_BRFL, 163 0 stevel OP_BRTR, 164 0 stevel OP_ADD, 165 0 stevel OP_SUB, 166 0 stevel OP_MUL, 167 0 stevel OP_DIV, 168 0 stevel OP_REM, 169 0 stevel OP_OFFSET_POP, 170 0 stevel OP_OFFSET_ZERO, 171 0 stevel OP_OFFSET_LINK, 172 0 stevel OP_OFFSET_IP, 173 0 stevel OP_OFFSET_TCP, 174 0 stevel OP_OFFSET_UDP, 175 0 stevel OP_OFFSET_RPC, 176 0 stevel OP_OFFSET_SLP, 177 2760 dg199075 OP_OFFSET_ETHERTYPE, 178 0 stevel OP_LAST 179 0 stevel }; 180 0 stevel 181 0 stevel static char *opnames[] = { 182 0 stevel "STOP", 183 0 stevel "LOAD_OCTET", 184 0 stevel "LOAD_SHORT", 185 0 stevel "LOAD_LONG", 186 0 stevel "LOAD_CONST", 187 0 stevel "LOAD_LENGTH", 188 0 stevel "EQ", 189 0 stevel "NE", 190 0 stevel "GT", 191 0 stevel "GE", 192 0 stevel "LT", 193 0 stevel "LE", 194 0 stevel "AND", 195 0 stevel "OR", 196 0 stevel "XOR", 197 0 stevel "NOT", 198 0 stevel "BRFL", 199 0 stevel "BRTR", 200 0 stevel "ADD", 201 0 stevel "SUB", 202 0 stevel "MUL", 203 0 stevel "DIV", 204 0 stevel "REM", 205 0 stevel "OFFSET_POP", 206 0 stevel "OFFSET_ZERO", 207 0 stevel "OFFSET_ETHER", 208 0 stevel "OFFSET_IP", 209 0 stevel "OFFSET_TCP", 210 0 stevel "OFFSET_UDP", 211 0 stevel "OFFSET_RPC", 212 0 stevel "OP_OFFSET_SLP", 213 2760 dg199075 "OFFSET_ETHERTYPE", 214 0 stevel "" 215 0 stevel }; 216 0 stevel 217 0 stevel #define MAXOPS 1024 218 0 stevel #define MAXSS 64 219 0 stevel static uint_t oplist[MAXOPS]; /* array of operators */ 220 0 stevel static uint_t *curr_op; /* last op generated */ 221 0 stevel 222 0 stevel extern int valid_slp(uchar_t *, int); /* decides if a SLP msg is valid */ 223 0 stevel extern struct hostent *lgetipnodebyname(const char *, int, int, int *); 224 0 stevel 225 0 stevel static void alternation(); 226 0 stevel static uint_t chain(); 227 0 stevel static void codeprint(); 228 0 stevel static void emitop(); 229 0 stevel static void emitval(); 230 0 stevel static void expression(); 231 0 stevel static struct xid_entry *find_rpc(); 232 0 stevel static void optimize(); 233 0 stevel static void ethertype_match(); 234 0 stevel 235 2760 dg199075 /* 236 2760 dg199075 * Get a ushort from a possibly unaligned character buffer. 237 2760 dg199075 * 238 2760 dg199075 * INPUTS: buffer - where the data is. Must be at least 239 2760 dg199075 * sizeof(uint16_t) bytes long. 240 2760 dg199075 * OUPUTS: An unsigned short that contains the data at buffer. 241 2760 dg199075 * No calls to ntohs or htons are done on the data. 242 2760 dg199075 */ 243 2760 dg199075 static uint16_t 244 2760 dg199075 get_u16(uchar_t *buffer) 245 2760 dg199075 { 246 2760 dg199075 uint8_t *bufraw = buffer; 247 2760 dg199075 248 2760 dg199075 /* 249 2760 dg199075 * ntohs is used only as a cheap way to flip the bits 250 2760 dg199075 * around on a little endian platform. The value will 251 2760 dg199075 * still be in host order or network order, depending on 252 2760 dg199075 * the order it was in when it was passed in. 253 2760 dg199075 */ 254 2760 dg199075 return (ntohs(bufraw[0] << 8 | bufraw[1])); 255 2760 dg199075 } 256 0 stevel 257 0 stevel /* 258 0 stevel * Returns the ULP for an IPv4 or IPv6 packet 259 0 stevel * Assumes that the packet has already been checked to verify 260 0 stevel * that it's either IPv4 or IPv6 261 0 stevel * 262 0 stevel * XXX Will need to be updated for AH and ESP 263 0 stevel * XXX when IPsec is supported for v6. 264 0 stevel */ 265 0 stevel static uchar_t 266 0 stevel ip_proto_of(uchar_t *ip) 267 0 stevel { 268 0 stevel uchar_t nxt; 269 0 stevel boolean_t not_done = B_TRUE; 270 0 stevel uchar_t *ptr = ip; 271 0 stevel 272 0 stevel switch (IP_VERS(ip)) { 273 0 stevel case IPV4_VERSION: 274 0 stevel return (IP_PROTO_OF(ip)); 275 0 stevel case IPV6_VERSION: 276 0 stevel 277 0 stevel nxt = ip[6]; 278 0 stevel ptr += 40; /* size of ip6 header */ 279 0 stevel do { 280 0 stevel switch (nxt) { 281 0 stevel /* 282 0 stevel * XXX Add IPsec headers here when supported for v6 283 0 stevel * XXX (the AH will have a different size...) 284 0 stevel */ 285 0 stevel case IPPROTO_HOPOPTS: 286 0 stevel case IPPROTO_ROUTING: 287 0 stevel case IPPROTO_FRAGMENT: 288 0 stevel case IPPROTO_DSTOPTS: 289 0 stevel ptr += (8 * (ptr[1] + 1)); 290 0 stevel nxt = *ptr; 291 0 stevel break; 292 0 stevel 293 0 stevel default: 294 0 stevel not_done = B_FALSE; 295 0 stevel break; 296 0 stevel } 297 0 stevel } while (not_done); 298 0 stevel return (nxt); 299 0 stevel default: 300 0 stevel break; /* shouldn't get here... */ 301 0 stevel } 302 0 stevel return (0); 303 0 stevel } 304 0 stevel 305 0 stevel /* 306 0 stevel * Returns the total IP header length. 307 0 stevel * For v4, this includes any options present. 308 0 stevel * For v6, this is the length of the IPv6 header plus 309 0 stevel * any extension headers present. 310 0 stevel * 311 0 stevel * XXX Will need to be updated for AH and ESP 312 0 stevel * XXX when IPsec is supported for v6. 313 0 stevel */ 314 0 stevel static int 315 0 stevel ip_hdr_len(uchar_t *ip) 316 0 stevel { 317 0 stevel uchar_t nxt; 318 0 stevel int hdr_len; 319 0 stevel boolean_t not_done = B_TRUE; 320 0 stevel int len = 40; /* IPv6 header size */ 321 0 stevel uchar_t *ptr = ip; 322 0 stevel 323 0 stevel switch (IP_VERS(ip)) { 324 0 stevel case IPV4_VERSION: 325 0 stevel return (IP_HDR_LEN(ip)); 326 0 stevel case IPV6_VERSION: 327 0 stevel nxt = ip[6]; 328 0 stevel ptr += len; 329 0 stevel do { 330 0 stevel switch (nxt) { 331 0 stevel /* 332 0 stevel * XXX Add IPsec headers here when supported for v6 333 0 stevel * XXX (the AH will have a different size...) 334 0 stevel */ 335 0 stevel case IPPROTO_HOPOPTS: 336 0 stevel case IPPROTO_ROUTING: 337 0 stevel case IPPROTO_FRAGMENT: 338 0 stevel case IPPROTO_DSTOPTS: 339 0 stevel hdr_len = (8 * (ptr[1] + 1)); 340 0 stevel len += hdr_len; 341 0 stevel ptr += hdr_len; 342 0 stevel nxt = *ptr; 343 0 stevel break; 344 0 stevel 345 0 stevel default: 346 0 stevel not_done = B_FALSE; 347 0 stevel break; 348 0 stevel } 349 0 stevel } while (not_done); 350 0 stevel return (len); 351 0 stevel default: 352 0 stevel break; 353 0 stevel } 354 0 stevel return (0); /* not IP */ 355 0 stevel } 356 0 stevel 357 0 stevel static void 358 0 stevel codeprint() 359 0 stevel { 360 0 stevel uint_t *op; 361 0 stevel 362 0 stevel printf("User filter:\n"); 363 0 stevel 364 0 stevel for (op = oplist; *op; op++) { 365 0 stevel if (*op <= OP_LAST) 366 0 stevel printf("\t%2d: %s\n", op - oplist, opnames[*op]); 367 0 stevel else 368 0 stevel printf("\t%2d: (%d)\n", op - oplist, *op); 369 0 stevel 370 0 stevel switch (*op) { 371 0 stevel case OP_LOAD_CONST: 372 0 stevel case OP_BRTR: 373 0 stevel case OP_BRFL: 374 0 stevel op++; 375 0 stevel if ((int)*op < 0) 376 0 stevel printf("\t%2d: 0x%08x (%d)\n", 377 8023 Phil op - oplist, *op, *op); 378 0 stevel else 379 0 stevel printf("\t%2d: %d (0x%08x)\n", 380 8023 Phil op - oplist, *op, *op); 381 0 stevel } 382 0 stevel } 383 0 stevel printf("\t%2d: STOP\n", op - oplist); 384 0 stevel printf("\n"); 385 0 stevel } 386 0 stevel 387 0 stevel 388 0 stevel /* 389 0 stevel * Take a pass through the generated code and optimize 390 0 stevel * branches. A branch true (BRTR) that has another BRTR 391 0 stevel * at its destination can use the address of the destination 392 0 stevel * BRTR. A BRTR that points to a BRFL (branch false) should 393 0 stevel * point to the address following the BRFL. 394 0 stevel * A similar optimization applies to BRFL operators. 395 0 stevel */ 396 0 stevel static void 397 0 stevel optimize(uint_t *oplistp) 398 0 stevel { 399 0 stevel uint_t *op; 400 0 stevel 401 0 stevel for (op = oplistp; *op; op++) { 402 0 stevel switch (*op) { 403 0 stevel case OP_LOAD_CONST: 404 0 stevel op++; 405 0 stevel break; 406 0 stevel case OP_BRTR: 407 0 stevel op++; 408 0 stevel optimize(&oplist[*op]); 409 0 stevel if (oplist[*op] == OP_BRFL) 410 0 stevel *op += 2; 411 0 stevel else if (oplist[*op] == OP_BRTR) 412 0 stevel *op = oplist[*op + 1]; 413 0 stevel break; 414 0 stevel case OP_BRFL: 415 0 stevel op++; 416 0 stevel optimize(&oplist[*op]); 417 0 stevel if (oplist[*op] == OP_BRTR) 418 0 stevel *op += 2; 419 0 stevel else if (oplist[*op] == OP_BRFL) 420 0 stevel *op = oplist[*op + 1]; 421 0 stevel break; 422 0 stevel } 423 0 stevel } 424 0 stevel } 425 0 stevel 426 0 stevel /* 427 0 stevel * RPC packets are tough to filter. 428 0 stevel * While the call packet has all the interesting 429 0 stevel * info: program number, version, procedure etc, 430 0 stevel * the reply packet has none of this information. 431 0 stevel * If we want to do useful filtering based on this 432 0 stevel * information then we have to stash the information 433 0 stevel * from the call packet, and use the XID in the reply 434 0 stevel * to find the stashed info. The stashed info is 435 0 stevel * kept in a circular lifo, assuming that a call packet 436 0 stevel * will be followed quickly by its reply. 437 0 stevel */ 438 0 stevel 439 0 stevel struct xid_entry { 440 0 stevel unsigned x_xid; /* The XID (32 bits) */ 441 0 stevel unsigned x_dir; /* CALL or REPLY */ 442 0 stevel unsigned x_rpcvers; /* Protocol version (2) */ 443 0 stevel unsigned x_prog; /* RPC program number */ 444 0 stevel unsigned x_vers; /* RPC version number */ 445 0 stevel unsigned x_proc; /* RPC procedure number */ 446 0 stevel }; 447 0 stevel static struct xid_entry xe_table[XID_CACHE_SIZE]; 448 0 stevel static struct xid_entry *xe_first = &xe_table[0]; 449 0 stevel static struct xid_entry *xe = &xe_table[0]; 450 0 stevel static struct xid_entry *xe_last = &xe_table[XID_CACHE_SIZE - 1]; 451 0 stevel 452 0 stevel static struct xid_entry * 453 0 stevel find_rpc(struct rpc_msg *rpc) 454 0 stevel { 455 0 stevel struct xid_entry *x; 456 0 stevel 457 0 stevel for (x = xe; x >= xe_first; x--) 458 0 stevel if (x->x_xid == rpc->rm_xid) 459 0 stevel return (x); 460 0 stevel for (x = xe_last; x > xe; x--) 461 0 stevel if (x->x_xid == rpc->rm_xid) 462 0 stevel return (x); 463 0 stevel return (NULL); 464 0 stevel } 465 0 stevel 466 0 stevel static void 467 0 stevel stash_rpc(struct rpc_msg *rpc) 468 0 stevel { 469 0 stevel struct xid_entry *x; 470 0 stevel 471 0 stevel if (find_rpc(rpc)) 472 0 stevel return; 473 0 stevel 474 0 stevel x = xe++; 475 0 stevel if (xe > xe_last) 476 0 stevel xe = xe_first; 477 0 stevel x->x_xid = rpc->rm_xid; 478 0 stevel x->x_dir = htonl(REPLY); 479 0 stevel x->x_prog = rpc->rm_call.cb_prog; 480 0 stevel x->x_vers = rpc->rm_call.cb_vers; 481 0 stevel x->x_proc = rpc->rm_call.cb_proc; 482 0 stevel } 483 0 stevel 484 0 stevel /* 485 0 stevel * SLP can multicast requests, and recieve unicast replies in which 486 0 stevel * neither the source nor destination port is identifiable as a SLP 487 0 stevel * port. Hence, we need to do as RPC does, and keep track of packets we 488 0 stevel * are interested in. For SLP, however, we use ports, not XIDs, and 489 0 stevel * a smaller cache size is more efficient since every incoming packet 490 0 stevel * needs to be checked. 491 0 stevel */ 492 0 stevel 493 0 stevel #define SLP_CACHE_SIZE 64 494 0 stevel static uint_t slp_table[SLP_CACHE_SIZE]; 495 0 stevel static int slp_index = 0; 496 0 stevel 497 0 stevel /* 498 0 stevel * Returns the index of dport in the table if found, otherwise -1. 499 0 stevel */ 500 0 stevel static int 501 0 stevel find_slp(uint_t dport) { 502 0 stevel int i; 503 0 stevel 504 0 stevel if (!dport) 505 0 stevel return (0); 506 0 stevel 507 0 stevel for (i = slp_index; i >= 0; i--) 508 0 stevel if (slp_table[i] == dport) { 509 0 stevel return (i); 510 0 stevel } 511 0 stevel for (i = SLP_CACHE_SIZE - 1; i > slp_index; i--) 512 0 stevel if (slp_table[i] == dport) { 513 0 stevel return (i); 514 0 stevel } 515 0 stevel return (-1); 516 0 stevel } 517 0 stevel 518 0 stevel static void stash_slp(uint_t sport) { 519 0 stevel if (slp_table[slp_index - 1] == sport) 520 0 stevel /* avoid redundancy due to multicast retransmissions */ 521 0 stevel return; 522 0 stevel 523 0 stevel slp_table[slp_index++] = sport; 524 0 stevel if (slp_index == SLP_CACHE_SIZE) 525 0 stevel slp_index = 0; 526 0 stevel } 527 0 stevel 528 0 stevel /* 529 0 stevel * This routine takes a packet and returns true or false 530 0 stevel * according to whether the filter expression selects it 531 0 stevel * or not. 532 0 stevel * We assume here that offsets for short and long values 533 0 stevel * are even - we may die with an alignment error if the 534 0 stevel * CPU doesn't support odd addresses. Note that long 535 0 stevel * values are loaded as two shorts so that 32 bit word 536 0 stevel * alignment isn't important. 537 0 stevel * 538 0 stevel * IPv6 is a bit stickier to handle than IPv4... 539 0 stevel */ 540 0 stevel 541 0 stevel int 542 0 stevel want_packet(uchar_t *pkt, int len, int origlen) 543 0 stevel { 544 0 stevel uint_t stack[MAXSS]; /* operand stack */ 545 0 stevel uint_t *op; /* current operator */ 546 0 stevel uint_t *sp; /* top of operand stack */ 547 0 stevel uchar_t *base; /* base for offsets into packet */ 548 0 stevel uchar_t *ip; /* addr of IP header, unaligned */ 549 0 stevel uchar_t *tcp; /* addr of TCP header, unaligned */ 550 0 stevel uchar_t *udp; /* addr of UDP header, unaligned */ 551 0 stevel struct rpc_msg rpcmsg; /* addr of RPC header */ 552 0 stevel struct rpc_msg *rpc; 553 0 stevel int newrpc = 0; 554 0 stevel uchar_t *slphdr; /* beginning of SLP header */ 555 0 stevel uint_t slp_sport, slp_dport; 556 0 stevel int off, header_size; 557 0 stevel uchar_t *offstack[MAXSS]; /* offset stack */ 558 0 stevel uchar_t **offp; /* current offset */ 559 0 stevel uchar_t *opkt = NULL; 560 0 stevel uint_t olen; 561 0 stevel 562 0 stevel sp = stack; 563 0 stevel *sp = 1; 564 0 stevel base = pkt; 565 0 stevel offp = offstack; 566 0 stevel 567 10616 Sebastien header_size = (*interface->header_len)((char *)pkt, len); 568 0 stevel 569 0 stevel for (op = oplist; *op; op++) { 570 0 stevel switch ((enum optype) *op) { 571 0 stevel case OP_LOAD_OCTET: 572 0 stevel if ((base + *sp) > (pkt + len)) 573 0 stevel return (0); /* packet too short */ 574 0 stevel 575 0 stevel *sp = *((uchar_t *)(base + *sp)); 576 0 stevel break; 577 0 stevel case OP_LOAD_SHORT: 578 0 stevel off = *sp; 579 0 stevel 580 0 stevel if ((base + off + sizeof (uint16_t) - 1) > (pkt + len)) 581 0 stevel return (0); /* packet too short */ 582 0 stevel 583 2760 dg199075 *sp = ntohs(get_u16((uchar_t *)(base + off))); 584 0 stevel break; 585 0 stevel case OP_LOAD_LONG: 586 0 stevel off = *sp; 587 0 stevel 588 0 stevel if ((base + off + sizeof (uint32_t) - 1) > (pkt + len)) 589 0 stevel return (0); /* packet too short */ 590 0 stevel 591 0 stevel /* 592 0 stevel * Handle 3 possible alignments 593 0 stevel */ 594 0 stevel switch ((((unsigned)base) + off) % sizeof (uint_t)) { 595 0 stevel case 0: 596 0 stevel *sp = *(uint_t *)(base + off); 597 0 stevel break; 598 0 stevel 599 0 stevel case 2: 600 0 stevel *((ushort_t *)(sp)) = 601 8023 Phil *((ushort_t *)(base + off)); 602 0 stevel *(((ushort_t *)sp) + 1) = 603 8023 Phil *((ushort_t *)(base + off) + 1); 604 0 stevel break; 605 0 stevel 606 0 stevel case 1: 607 0 stevel case 3: 608 0 stevel *((uchar_t *)(sp)) = 609 8023 Phil *((uchar_t *)(base + off)); 610 0 stevel *(((uchar_t *)sp) + 1) = 611 8023 Phil *((uchar_t *)(base + off) + 1); 612 0 stevel *(((uchar_t *)sp) + 2) = 613 8023 Phil *((uchar_t *)(base + off) + 2); 614 0 stevel *(((uchar_t *)sp) + 3) = 615 8023 Phil *((uchar_t *)(base + off) + 3); 616 0 stevel break; 617 0 stevel } 618 0 stevel *sp = ntohl(*sp); 619 0 stevel break; 620 0 stevel case OP_LOAD_CONST: 621 0 stevel if (sp >= &stack[MAXSS]) 622 0 stevel return (0); 623 0 stevel *(++sp) = *(++op); 624 0 stevel break; 625 0 stevel case OP_LOAD_LENGTH: 626 0 stevel if (sp >= &stack[MAXSS]) 627 0 stevel return (0); 628 0 stevel *(++sp) = origlen; 629 0 stevel break; 630 0 stevel case OP_EQ: 631 0 stevel if (sp < &stack[1]) 632 0 stevel return (0); 633 0 stevel sp--; 634 0 stevel *sp = *sp == *(sp + 1); 635 0 stevel break; 636 0 stevel case OP_NE: 637 0 stevel if (sp < &stack[1]) 638 0 stevel return (0); 639 0 stevel sp--; 640 0 stevel *sp = *sp != *(sp + 1); 641 0 stevel break; 642 0 stevel case OP_GT: 643 0 stevel if (sp < &stack[1]) 644 0 stevel return (0); 645 0 stevel sp--; 646 0 stevel *sp = *sp > *(sp + 1); 647 0 stevel break; 648 0 stevel case OP_GE: 649 0 stevel if (sp < &stack[1]) 650 0 stevel return (0); 651 0 stevel sp--; 652 0 stevel *sp = *sp >= *(sp + 1); 653 0 stevel break; 654 0 stevel case OP_LT: 655 0 stevel if (sp < &stack[1]) 656 0 stevel return (0); 657 0 stevel sp--; 658 0 stevel *sp = *sp < *(sp + 1); 659 0 stevel break; 660 0 stevel case OP_LE: 661 0 stevel if (sp < &stack[1]) 662 0 stevel return (0); 663 0 stevel sp--; 664 0 stevel *sp = *sp <= *(sp + 1); 665 0 stevel break; 666 0 stevel case OP_AND: 667 0 stevel if (sp < &stack[1]) 668 0 stevel return (0); 669 0 stevel sp--; 670 0 stevel *sp &= *(sp + 1); 671 0 stevel break; 672 0 stevel case OP_OR: 673 0 stevel if (sp < &stack[1]) 674 0 stevel return (0); 675 0 stevel sp--; 676 0 stevel *sp |= *(sp + 1); 677 0 stevel break; 678 0 stevel case OP_XOR: 679 0 stevel if (sp < &stack[1]) 680 0 stevel return (0); 681 0 stevel sp--; 682 0 stevel *sp ^= *(sp + 1); 683 0 stevel break; 684 0 stevel case OP_NOT: 685 0 stevel *sp = !*sp; 686 0 stevel break; 687 0 stevel case OP_BRFL: 688 0 stevel op++; 689 0 stevel if (!*sp) 690 0 stevel op = &oplist[*op] - 1; 691 0 stevel break; 692 0 stevel case OP_BRTR: 693 0 stevel op++; 694 0 stevel if (*sp) 695 0 stevel op = &oplist[*op] - 1; 696 0 stevel break; 697 0 stevel case OP_ADD: 698 0 stevel if (sp < &stack[1]) 699 0 stevel return (0); 700 0 stevel sp--; 701 0 stevel *sp += *(sp + 1); 702 0 stevel break; 703 0 stevel case OP_SUB: 704 0 stevel if (sp < &stack[1]) 705 0 stevel return (0); 706 0 stevel sp--; 707 0 stevel *sp -= *(sp + 1); 708 0 stevel break; 709 0 stevel case OP_MUL: 710 0 stevel if (sp < &stack[1]) 711 0 stevel return (0); 712 0 stevel sp--; 713 0 stevel *sp *= *(sp + 1); 714 0 stevel break; 715 0 stevel case OP_DIV: 716 0 stevel if (sp < &stack[1]) 717 0 stevel return (0); 718 0 stevel sp--; 719 0 stevel *sp /= *(sp + 1); 720 0 stevel break; 721 0 stevel case OP_REM: 722 0 stevel if (sp < &stack[1]) 723 0 stevel return (0); 724 0 stevel sp--; 725 0 stevel *sp %= *(sp + 1); 726 0 stevel break; 727 0 stevel case OP_OFFSET_POP: 728 0 stevel if (offp < &offstack[0]) 729 0 stevel return (0); 730 0 stevel base = *offp--; 731 0 stevel if (opkt != NULL) { 732 0 stevel pkt = opkt; 733 0 stevel len = olen; 734 0 stevel opkt = NULL; 735 0 stevel } 736 0 stevel break; 737 0 stevel case OP_OFFSET_ZERO: 738 0 stevel if (offp >= &offstack[MAXSS]) 739 0 stevel return (0); 740 0 stevel *++offp = base; 741 0 stevel base = pkt; 742 0 stevel break; 743 0 stevel case OP_OFFSET_LINK: 744 0 stevel if (offp >= &offstack[MAXSS]) 745 0 stevel return (0); 746 0 stevel *++offp = base; 747 0 stevel base = pkt + header_size; 748 0 stevel /* 749 0 stevel * If the offset exceeds the packet length, 750 0 stevel * we should not be interested in this packet... 751 0 stevel * Just return 0. 752 0 stevel */ 753 0 stevel if (base > pkt + len) { 754 0 stevel return (0); 755 0 stevel } 756 0 stevel break; 757 0 stevel case OP_OFFSET_IP: 758 0 stevel if (offp >= &offstack[MAXSS]) 759 0 stevel return (0); 760 0 stevel *++offp = base; 761 0 stevel ip = pkt + header_size; 762 0 stevel base = ip + ip_hdr_len(ip); 763 0 stevel if (base == ip) { 764 0 stevel return (0); /* not IP */ 765 0 stevel } 766 0 stevel if (base > pkt + len) { 767 0 stevel return (0); /* bad pkt */ 768 0 stevel } 769 0 stevel break; 770 0 stevel case OP_OFFSET_TCP: 771 0 stevel if (offp >= &offstack[MAXSS]) 772 0 stevel return (0); 773 0 stevel *++offp = base; 774 0 stevel ip = pkt + header_size; 775 0 stevel tcp = ip + ip_hdr_len(ip); 776 0 stevel if (tcp == ip) { 777 0 stevel return (0); /* not IP */ 778 0 stevel } 779 0 stevel base = tcp + TCP_HDR_LEN(tcp); 780 0 stevel if (base > pkt + len) { 781 0 stevel return (0); 782 0 stevel } 783 0 stevel break; 784 0 stevel case OP_OFFSET_UDP: 785 0 stevel if (offp >= &offstack[MAXSS]) 786 0 stevel return (0); 787 0 stevel *++offp = base; 788 0 stevel ip = pkt + header_size; 789 0 stevel udp = ip + ip_hdr_len(ip); 790 0 stevel if (udp == ip) { 791 0 stevel return (0); /* not IP */ 792 0 stevel } 793 0 stevel base = udp + sizeof (struct udphdr); 794 0 stevel if (base > pkt + len) { 795 0 stevel return (0); 796 0 stevel } 797 0 stevel break; 798 0 stevel case OP_OFFSET_RPC: 799 0 stevel if (offp >= &offstack[MAXSS]) 800 0 stevel return (0); 801 0 stevel *++offp = base; 802 0 stevel ip = pkt + header_size; 803 0 stevel rpc = NULL; 804 0 stevel 805 0 stevel if (IP_VERS(ip) != IPV4_VERSION && 806 0 stevel IP_VERS(ip) != IPV6_VERSION) { 807 0 stevel if (sp >= &stack[MAXSS]) 808 0 stevel return (0); 809 0 stevel *(++sp) = 0; 810 0 stevel break; 811 0 stevel } 812 0 stevel 813 0 stevel switch (ip_proto_of(ip)) { 814 0 stevel case IPPROTO_UDP: 815 0 stevel udp = ip + ip_hdr_len(ip); 816 0 stevel rpc = (struct rpc_msg *)(udp + 817 0 stevel sizeof (struct udphdr)); 818 0 stevel break; 819 0 stevel case IPPROTO_TCP: 820 0 stevel tcp = ip + ip_hdr_len(ip); 821 0 stevel /* 822 0 stevel * Need to skip an extra 4 for the xdr_rec 823 0 stevel * field. 824 0 stevel */ 825 0 stevel rpc = (struct rpc_msg *)(tcp + 826 0 stevel TCP_HDR_LEN(tcp) + 4); 827 0 stevel break; 828 0 stevel } 829 0 stevel /* 830 0 stevel * We need to have at least 24 bytes of a RPC 831 0 stevel * packet to look at to determine the validity 832 0 stevel * of it. 833 0 stevel */ 834 0 stevel if (rpc == NULL || (uchar_t *)rpc + 24 > pkt + len) { 835 0 stevel if (sp >= &stack[MAXSS]) 836 0 stevel return (0); 837 0 stevel *(++sp) = 0; 838 0 stevel break; 839 0 stevel } 840 0 stevel /* align */ 841 0 stevel (void) memcpy(&rpcmsg, rpc, 24); 842 10616 Sebastien if (!valid_rpc((char *)&rpcmsg, 24)) { 843 0 stevel if (sp >= &stack[MAXSS]) 844 0 stevel return (0); 845 0 stevel *(++sp) = 0; 846 0 stevel break; 847 0 stevel } 848 0 stevel if (ntohl(rpcmsg.rm_direction) == CALL) { 849 0 stevel base = (uchar_t *)rpc; 850 0 stevel newrpc = 1; 851 0 stevel if (sp >= &stack[MAXSS]) 852 0 stevel return (0); 853 0 stevel *(++sp) = 1; 854 0 stevel } else { 855 0 stevel opkt = pkt; 856 0 stevel olen = len; 857 0 stevel 858 0 stevel pkt = base = (uchar_t *)find_rpc(&rpcmsg); 859 0 stevel len = sizeof (struct xid_entry); 860 0 stevel if (sp >= &stack[MAXSS]) 861 0 stevel return (0); 862 0 stevel *(++sp) = base != NULL; 863 0 stevel } 864 0 stevel break; 865 0 stevel case OP_OFFSET_SLP: 866 0 stevel slphdr = NULL; 867 0 stevel ip = pkt + header_size; 868 0 stevel 869 0 stevel if (IP_VERS(ip) != IPV4_VERSION && 870 0 stevel IP_VERS(ip) != IPV6_VERSION) { 871 0 stevel if (sp >= &stack[MAXSS]) 872 0 stevel return (0); 873 0 stevel *(++sp) = 0; 874 0 stevel break; 875 0 stevel } 876 0 stevel 877 0 stevel switch (ip_proto_of(ip)) { 878 0 stevel struct udphdr udp_h; 879 0 stevel struct tcphdr tcp_h; 880 0 stevel case IPPROTO_UDP: 881 0 stevel udp = ip + ip_hdr_len(ip); 882 0 stevel /* align */ 883 0 stevel memcpy(&udp_h, udp, sizeof (udp_h)); 884 0 stevel slp_sport = ntohs(udp_h.uh_sport); 885 0 stevel slp_dport = ntohs(udp_h.uh_dport); 886 0 stevel slphdr = udp + sizeof (struct udphdr); 887 0 stevel break; 888 0 stevel case IPPROTO_TCP: 889 0 stevel tcp = ip + ip_hdr_len(ip); 890 0 stevel /* align */ 891 0 stevel memcpy(&tcp_h, tcp, sizeof (tcp_h)); 892 0 stevel slp_sport = ntohs(tcp_h.th_sport); 893 0 stevel slp_dport = ntohs(tcp_h.th_dport); 894 0 stevel slphdr = tcp + TCP_HDR_LEN(tcp); 895 0 stevel break; 896 0 stevel } 897 0 stevel if (slphdr == NULL || slphdr > pkt + len) { 898 0 stevel if (sp >= &stack[MAXSS]) 899 0 stevel return (0); 900 0 stevel *(++sp) = 0; 901 0 stevel break; 902 0 stevel } 903 0 stevel if (slp_sport == 427 || slp_dport == 427) { 904 0 stevel if (sp >= &stack[MAXSS]) 905 0 stevel return (0); 906 0 stevel *(++sp) = 1; 907 0 stevel if (slp_sport != 427 && slp_dport == 427) 908 0 stevel stash_slp(slp_sport); 909 0 stevel break; 910 0 stevel } else if (find_slp(slp_dport) != -1) { 911 0 stevel if (valid_slp(slphdr, len)) { 912 0 stevel if (sp >= &stack[MAXSS]) 913 0 stevel return (0); 914 0 stevel *(++sp) = 1; 915 0 stevel break; 916 0 stevel } 917 0 stevel /* else fallthrough to reject */ 918 0 stevel } 919 0 stevel if (sp >= &stack[MAXSS]) 920 0 stevel return (0); 921 0 stevel *(++sp) = 0; 922 0 stevel break; 923 2760 dg199075 case OP_OFFSET_ETHERTYPE: 924 2760 dg199075 /* 925 8023 Phil * Set base to the location of the ethertype as 926 8023 Phil * appropriate for this link type. Note that it's 927 8023 Phil * not called "ethertype" for every link type, but 928 8023 Phil * we need to call it something. 929 2760 dg199075 */ 930 2760 dg199075 if (offp >= &offstack[MAXSS]) 931 2760 dg199075 return (0); 932 2760 dg199075 *++offp = base; 933 2760 dg199075 base = pkt + interface->network_type_offset; 934 8023 Phil 935 8023 Phil /* 936 8023 Phil * Below, we adjust the offset for unusual 937 8023 Phil * link-layer headers that may have the protocol 938 8023 Phil * type in a variable location beyond what was set 939 8023 Phil * above. 940 8023 Phil */ 941 8023 Phil switch (interface->mac_type) { 942 8023 Phil case DL_ETHER: 943 8023 Phil case DL_CSMACD: 944 8023 Phil /* 945 8023 Phil * If this is a VLAN-tagged packet, we need 946 8023 Phil * to point to the ethertype field in the 947 8023 Phil * VLAN header. Move past the ethertype 948 8023 Phil * field in the ethernet header. 949 8023 Phil */ 950 8023 Phil if (ntohs(get_u16(base)) == ETHERTYPE_VLAN) 951 8023 Phil base += (ENCAP_ETHERTYPE_OFF); 952 8023 Phil break; 953 8023 Phil } 954 2760 dg199075 if (base > pkt + len) { 955 2760 dg199075 /* Went too far, drop the packet */ 956 2760 dg199075 return (0); 957 2760 dg199075 } 958 2760 dg199075 break; 959 0 stevel } 960 0 stevel } 961 0 stevel 962 0 stevel if (*sp && newrpc) 963 0 stevel stash_rpc(&rpcmsg); 964 0 stevel 965 0 stevel return (*sp); 966 0 stevel } 967 0 stevel 968 0 stevel static void 969 0 stevel load_const(uint_t constval) 970 0 stevel { 971 0 stevel emitop(OP_LOAD_CONST); 972 0 stevel emitval(constval); 973 0 stevel } 974 0 stevel 975 0 stevel static void 976 0 stevel load_value(int offset, int len) 977 0 stevel { 978 0 stevel if (offset >= 0) 979 0 stevel load_const(offset); 980 0 stevel 981 0 stevel switch (len) { 982 0 stevel case 1: 983 0 stevel emitop(OP_LOAD_OCTET); 984 0 stevel break; 985 0 stevel case 2: 986 0 stevel emitop(OP_LOAD_SHORT); 987 0 stevel break; 988 0 stevel case 4: 989 0 stevel emitop(OP_LOAD_LONG); 990 0 stevel break; 991 0 stevel } 992 0 stevel } 993 0 stevel 994 0 stevel /* 995 0 stevel * Emit code to compare a field in 996 0 stevel * the packet against a constant value. 997 0 stevel */ 998 0 stevel static void 999 0 stevel compare_value(uint_t offset, uint_t len, uint_t val) 1000 0 stevel { 1001 0 stevel load_const(val); 1002 0 stevel load_value(offset, len); 1003 0 stevel emitop(OP_EQ); 1004 0 stevel } 1005 0 stevel 1006 0 stevel static void 1007 0 stevel compare_addr_v4(uint_t offset, uint_t len, uint_t val) 1008 0 stevel { 1009 0 stevel load_const(ntohl(val)); 1010 0 stevel load_value(offset, len); 1011 0 stevel emitop(OP_EQ); 1012 0 stevel } 1013 0 stevel 1014 0 stevel static void 1015 0 stevel compare_addr_v6(uint_t offset, uint_t len, struct in6_addr val) 1016 0 stevel { 1017 0 stevel int i; 1018 0 stevel uint32_t value; 1019 0 stevel 1020 0 stevel for (i = 0; i < len; i += 4) { 1021 0 stevel value = ntohl(*(uint32_t *)&val.s6_addr[i]); 1022 0 stevel load_const(value); 1023 0 stevel load_value(offset + i, 4); 1024 0 stevel emitop(OP_EQ); 1025 0 stevel if (i != 0) 1026 0 stevel emitop(OP_AND); 1027 0 stevel } 1028 0 stevel } 1029 0 stevel 1030 0 stevel /* 1031 0 stevel * Same as above except do the comparison 1032 0 stevel * after and'ing a mask value. Useful 1033 0 stevel * for comparing IP network numbers 1034 0 stevel */ 1035 0 stevel static void 1036 0 stevel compare_value_mask(uint_t offset, uint_t len, uint_t val, int mask) 1037 0 stevel { 1038 0 stevel load_value(offset, len); 1039 0 stevel load_const(mask); 1040 0 stevel emitop(OP_AND); 1041 0 stevel load_const(val); 1042 0 stevel emitop(OP_EQ); 1043 8023 Phil } 1044 8023 Phil 1045 8023 Phil /* 1046 8023 Phil * Compare two zoneid's. The arg val passed in is stored in network 1047 8023 Phil * byte order. 1048 8023 Phil */ 1049 8023 Phil static void 1050 10639 Darren compare_value_zone(uint_t offset, uint32_t val) 1051 8023 Phil { 1052 8023 Phil int i; 1053 8023 Phil 1054 10639 Darren load_const(ntohl(((uint32_t *)&val)[i])); 1055 10639 Darren load_value(offset + i * 4, 4); 1056 10639 Darren emitop(OP_EQ); 1057 0 stevel } 1058 0 stevel 1059 0 stevel /* Emit an operator into the code array */ 1060 0 stevel static void 1061 0 stevel emitop(enum optype opcode) 1062 0 stevel { 1063 0 stevel if (curr_op >= &oplist[MAXOPS]) 1064 0 stevel pr_err("expression too long"); 1065 0 stevel *curr_op++ = opcode; 1066 0 stevel } 1067 0 stevel 1068 0 stevel /* 1069 0 stevel * Remove n operators recently emitted into 1070 0 stevel * the code array. Used by alternation(). 1071 0 stevel */ 1072 0 stevel static void 1073 0 stevel unemit(int numops) 1074 0 stevel { 1075 0 stevel curr_op -= numops; 1076 0 stevel } 1077 0 stevel 1078 0 stevel 1079 0 stevel /* 1080 0 stevel * Same as emitop except that we're emitting 1081 0 stevel * a value that's not an operator. 1082 0 stevel */ 1083 0 stevel static void 1084 0 stevel emitval(uint_t val) 1085 0 stevel { 1086 0 stevel if (curr_op >= &oplist[MAXOPS]) 1087 0 stevel pr_err("expression too long"); 1088 0 stevel *curr_op++ = val; 1089 0 stevel } 1090 0 stevel 1091 0 stevel /* 1092 0 stevel * Used to chain forward branches together 1093 0 stevel * for later resolution by resolve_chain(). 1094 0 stevel */ 1095 0 stevel static uint_t 1096 0 stevel chain(int p) 1097 0 stevel { 1098 0 stevel uint_t pos = curr_op - oplist; 1099 0 stevel 1100 0 stevel emitval(p); 1101 0 stevel return (pos); 1102 0 stevel } 1103 0 stevel 1104 0 stevel /* 1105 0 stevel * Proceed backward through the code array 1106 0 stevel * following a chain of forward references. 1107 0 stevel * At each reference install the destination 1108 0 stevel * branch offset. 1109 0 stevel */ 1110 0 stevel static void 1111 0 stevel resolve_chain(uint_t p) 1112 0 stevel { 1113 0 stevel uint_t n; 1114 0 stevel uint_t pos = curr_op - oplist; 1115 0 stevel 1116 0 stevel while (p) { 1117 0 stevel n = oplist[p]; 1118 0 stevel oplist[p] = pos; 1119 0 stevel p = n; 1120 0 stevel } 1121 0 stevel } 1122 0 stevel 1123 0 stevel #define EQ(val) (strcmp(token, val) == 0) 1124 0 stevel 1125 0 stevel char *tkp, *sav_tkp; 1126 0 stevel char *token; 1127 0 stevel enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL, 1128 0 stevel ADDR_IP6, ADDR_AT } tokentype; 1129 0 stevel uint_t tokenval; 1130 0 stevel 1131 0 stevel /* 1132 0 stevel * This is the scanner. Each call returns the next 1133 0 stevel * token in the filter expression. A token is either: 1134 0 stevel * EOL: The end of the line - no more tokens. 1135 0 stevel * ALPHA: A name that begins with a letter and contains 1136 0 stevel * letters or digits, hyphens or underscores. 1137 0 stevel * NUMBER: A number. The value can be represented as 1138 0 stevel * a decimal value (1234) or an octal value 1139 0 stevel * that begins with zero (066) or a hex value 1140 0 stevel * that begins with 0x or 0X (0xff). 1141 0 stevel * FIELD: A name followed by a left square bracket. 1142 0 stevel * ADDR_IP: An IP address. Any sequence of digits 1143 0 stevel * separated by dots e.g. 109.104.40.13 1144 0 stevel * ADDR_ETHER: An ethernet address. Any sequence of hex 1145 0 stevel * digits separated by colons e.g. 8:0:20:0:76:39 1146 0 stevel * SPECIAL: A special character e.g. ">" or "(". The scanner 1147 0 stevel * correctly handles digraphs - two special characters 1148 0 stevel * that constitute a single token e.g. "==" or ">=". 1149 0 stevel * ADDR_IP6: An IPv6 address. 1150 0 stevel * 1151 0 stevel * ADDR_AT: An AppleTalk Phase II address. A sequence of two numbers 1152 0 stevel * separated by a dot. 1153 0 stevel * 1154 0 stevel * The current token is maintained in "token" and and its 1155 0 stevel * type in "tokentype". If tokentype is NUMBER then the 1156 0 stevel * value is held in "tokenval". 1157 0 stevel */ 1158 0 stevel 1159 0 stevel static const char *namechars = 1160 0 stevel "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-."; 1161 0 stevel static const char *numchars = "0123456789abcdefABCDEFXx:."; 1162 0 stevel 1163 0 stevel void 1164 0 stevel next() 1165 0 stevel { 1166 0 stevel static int savechar; 1167 0 stevel char *p; 1168 0 stevel int size, size1; 1169 0 stevel int base, colons, dots, alphas, double_colon; 1170 0 stevel 1171 0 stevel colons = 0; 1172 0 stevel double_colon = 0; 1173 0 stevel 1174 0 stevel if (*tkp == '\0') { 1175 0 stevel token = tkp; 1176 0 stevel *tkp = savechar; 1177 0 stevel } 1178 0 stevel 1179 0 stevel sav_tkp = tkp; 1180 0 stevel 1181 0 stevel while (isspace(*tkp)) tkp++; 1182 0 stevel token = tkp; 1183 0 stevel if (*token == '\0') { 1184 0 stevel tokentype = EOL; 1185 0 stevel return; 1186 0 stevel } 1187 0 stevel 1188 0 stevel /* A token containing ':' cannot be ALPHA type */ 1189 0 stevel tkp = token + strspn(token, numchars); 1190 0 stevel for (p = token; p < tkp; p++) { 1191 0 stevel if (*p == ':') { 1192 0 stevel colons++; 1193 0 stevel if (*(p+1) == ':') 1194 0 stevel double_colon++; 1195 0 stevel } 1196 0 stevel } 1197 0 stevel 1198 0 stevel tkp = token; 1199 0 stevel if (isalpha(*tkp) && !colons) { 1200 0 stevel tokentype = ALPHA; 1201 0 stevel tkp += strspn(tkp, namechars); 1202 0 stevel if (*tkp == '[') { 1203 0 stevel tokentype = FIELD; 1204 0 stevel *tkp++ = '\0'; 1205 0 stevel } 1206 0 stevel } else 1207 0 stevel 1208 0 stevel /* 1209 0 stevel * RFC1123 states that host names may now start with digits. Need 1210 0 stevel * to change parser to account for this. Also, need to distinguish 1211 0 stevel * between 1.2.3.4 and 1.2.3.a where the first case is an IP address 1212 0 stevel * and the second is a domain name. 333aaa needs to be distinguished 1213 0 stevel * from 0x333aaa. The first is a host name and the second is a number. 1214 0 stevel * 1215 0 stevel * The (colons > 1) conditional differentiates between ethernet 1216 0 stevel * and IPv6 addresses, and an expression of the form base[expr:size], 1217 0 stevel * which can only contain one ':' character. 1218 0 stevel */ 1219 0 stevel if (isdigit(*tkp) || colons > 1) { 1220 0 stevel tkp = token + strspn(token, numchars); 1221 0 stevel dots = alphas = 0; 1222 0 stevel for (p = token; p < tkp; p++) { 1223 0 stevel if (*p == '.') 1224 0 stevel dots++; 1225 0 stevel else if (isalpha(*p)) 1226 0 stevel alphas = 1; 1227 0 stevel } 1228 0 stevel if (colons > 1) { 1229 0 stevel if (colons == 5 && double_colon == 0) { 1230 0 stevel tokentype = ADDR_ETHER; 1231 0 stevel } else { 1232 0 stevel tokentype = ADDR_IP6; 1233 0 stevel } 1234 0 stevel } else if (dots) { 1235 0 stevel size = tkp - token; 1236 0 stevel size1 = strspn(token, "0123456789."); 1237 0 stevel if (dots == 1 && size == size1) { 1238 0 stevel tokentype = ADDR_AT; 1239 0 stevel } else 1240 0 stevel if (dots != 3 || size != size1) { 1241 0 stevel tokentype = ALPHA; 1242 0 stevel if (*tkp != '\0' && !isspace(*tkp)) { 1243 0 stevel tkp += strspn(tkp, namechars); 1244 0 stevel if (*tkp == '[') { 1245 0 stevel tokentype = FIELD; 1246 0 stevel *tkp++ = '\0'; 1247 0 stevel } 1248 0 stevel } 1249 0 stevel } else 1250 0 stevel tokentype = ADDR_IP; 1251 0 stevel } else if (token + strspn(token, namechars) <= tkp) { 1252 0 stevel /* 1253 0 stevel * With the above check, if there are more 1254 0 stevel * characters after the last digit, assume 1255 0 stevel * that it is not a number. 1256 0 stevel */ 1257 0 stevel tokentype = NUMBER; 1258 0 stevel p = tkp; 1259 0 stevel tkp = token; 1260 0 stevel base = 10; 1261 0 stevel if (*tkp == '0') { 1262 0 stevel base = 8; 1263 0 stevel tkp++; 1264 0 stevel if (*tkp == 'x' || *tkp == 'X') 1265 0 stevel base = 16; 1266 0 stevel } 1267 0 stevel if ((base == 10 || base == 8) && alphas) { 1268 0 stevel tokentype = ALPHA; 1269 0 stevel tkp = p; 1270 0 stevel } else if (base == 16) { 1271 0 stevel size = 2 + strspn(token+2, 1272 8023 Phil "0123456789abcdefABCDEF"); 1273 0 stevel size1 = p - token; 1274 0 stevel if (size != size1) { 1275 0 stevel tokentype = ALPHA; 1276 0 stevel tkp = p; 1277 0 stevel } else 1278 0 stevel /* 1279 0 stevel * handles the case of 0x so an error message 1280 0 stevel * is not printed. Treats 0x as 0. 1281 0 stevel */ 1282 0 stevel if (size == 2) { 1283 0 stevel tokenval = 0; 1284 0 stevel tkp = token +2; 1285 0 stevel } else { 1286 0 stevel tokenval = strtoul(token, &tkp, base); 1287 0 stevel } 1288 0 stevel } else { 1289 0 stevel tokenval = strtoul(token, &tkp, base); 1290 0 stevel } 1291 0 stevel } else { 1292 0 stevel tokentype = ALPHA; 1293 0 stevel tkp += strspn(tkp, namechars); 1294 0 stevel if (*tkp == '[') { 1295 0 stevel tokentype = FIELD; 1296 0 stevel *tkp++ = '\0'; 1297 0 stevel } 1298 0 stevel } 1299 0 stevel } else { 1300 0 stevel tokentype = SPECIAL; 1301 0 stevel tkp++; 1302 0 stevel if ((*token == '=' && *tkp == '=') || 1303 0 stevel (*token == '>' && *tkp == '=') || 1304 0 stevel (*token == '<' && *tkp == '=') || 1305 0 stevel (*token == '!' && *tkp == '=')) 1306 0 stevel tkp++; 1307 0 stevel } 1308 0 stevel 1309 0 stevel savechar = *tkp; 1310 0 stevel *tkp = '\0'; 1311 0 stevel } 1312 0 stevel 1313 8023 Phil typedef struct match_type { 1314 0 stevel char *m_name; 1315 0 stevel int m_offset; 1316 0 stevel int m_size; 1317 0 stevel int m_value; 1318 0 stevel int m_depend; 1319 0 stevel enum optype m_optype; 1320 8023 Phil } match_type_t; 1321 8023 Phil 1322 8023 Phil static match_type_t ether_match_types[] = { 1323 0 stevel /* 1324 0 stevel * Table initialized assuming Ethernet data link headers. 1325 2760 dg199075 * m_offset is an offset beyond the offset op, which is why 1326 2760 dg199075 * the offset is zero for when snoop needs to check an ethertype. 1327 0 stevel */ 1328 2760 dg199075 "ip", 0, 2, ETHERTYPE_IP, -1, OP_OFFSET_ETHERTYPE, 1329 2760 dg199075 "ip6", 0, 2, ETHERTYPE_IPV6, -1, OP_OFFSET_ETHERTYPE, 1330 2760 dg199075 "arp", 0, 2, ETHERTYPE_ARP, -1, OP_OFFSET_ETHERTYPE, 1331 2760 dg199075 "rarp", 0, 2, ETHERTYPE_REVARP, -1, OP_OFFSET_ETHERTYPE, 1332 2760 dg199075 "pppoed", 0, 2, ETHERTYPE_PPPOED, -1, OP_OFFSET_ETHERTYPE, 1333 2760 dg199075 "pppoes", 0, 2, ETHERTYPE_PPPOES, -1, OP_OFFSET_ETHERTYPE, 1334 2760 dg199075 "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK, 1335 2760 dg199075 "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK, 1336 2760 dg199075 "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK, 1337 2760 dg199075 "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK, 1338 2760 dg199075 "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK, 1339 2760 dg199075 "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK, 1340 2760 dg199075 "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK, 1341 2760 dg199075 "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK, 1342 2760 dg199075 "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK, 1343 2760 dg199075 "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK, 1344 2760 dg199075 "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK, 1345 2760 dg199075 "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK, 1346 2760 dg199075 "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK, 1347 2760 dg199075 "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK, 1348 2760 dg199075 "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK, 1349 2760 dg199075 0, 0, 0, 0, 0, 0 1350 0 stevel }; 1351 0 stevel 1352 8023 Phil static match_type_t ipnet_match_types[] = { 1353 8023 Phil /* 1354 8023 Phil * Table initialized assuming Ethernet data link headers. 1355 8023 Phil * m_offset is an offset beyond the offset op, which is why 1356 8023 Phil * the offset is zero for when snoop needs to check an ethertype. 1357 8023 Phil */ 1358 8105 Sebastien "ip", 0, 1, IPV4_VERSION, -1, OP_OFFSET_ETHERTYPE, 1359 8105 Sebastien "ip6", 0, 1, IPV6_VERSION, -1, OP_OFFSET_ETHERTYPE, 1360 8023 Phil "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK, 1361 8023 Phil "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK, 1362 8023 Phil "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK, 1363 8023 Phil "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK, 1364 8023 Phil "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK, 1365 8023 Phil "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK, 1366 8023 Phil "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK, 1367 8023 Phil "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK, 1368 8023 Phil "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK, 1369 8023 Phil "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK, 1370 8023 Phil "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK, 1371 8023 Phil "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK, 1372 8023 Phil "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK, 1373 8023 Phil "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK, 1374 8023 Phil "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK, 1375 8023 Phil 0, 0, 0, 0, 0, 0 1376 8023 Phil }; 1377 8023 Phil 1378 10616 Sebastien static match_type_t iptun_match_types[] = { 1379 10616 Sebastien "ip", 0, 1, IPPROTO_ENCAP, -1, OP_OFFSET_ETHERTYPE, 1380 10616 Sebastien "ip6", 0, 1, IPPROTO_IPV6, -1, OP_OFFSET_ETHERTYPE, 1381 10616 Sebastien "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK, 1382 10616 Sebastien "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK, 1383 10616 Sebastien "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK, 1384 10616 Sebastien "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK, 1385 10616 Sebastien "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK, 1386 10616 Sebastien "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK, 1387 10616 Sebastien "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK, 1388 10616 Sebastien "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK, 1389 10616 Sebastien "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK, 1390 10616 Sebastien "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK, 1391 10616 Sebastien "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK, 1392 10616 Sebastien "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK, 1393 10616 Sebastien "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK, 1394 10616 Sebastien "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK, 1395 10616 Sebastien "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK, 1396 10616 Sebastien 0, 0, 0, 0, 0, 0 1397 10616 Sebastien }; 1398 10616 Sebastien 1399 0 stevel static void 1400 8023 Phil generate_check(match_type_t match_types[], int index, int type) 1401 0 stevel { 1402 8023 Phil match_type_t *mtp = &match_types[index]; 1403 0 stevel /* 1404 0 stevel * Note: this code assumes the above dependencies are 1405 0 stevel * not cyclic. This *should* always be true. 1406 0 stevel */ 1407 0 stevel if (mtp->m_depend != -1) 1408 8023 Phil generate_check(match_types, mtp->m_depend, type); 1409 0 stevel 1410 2760 dg199075 emitop(mtp->m_optype); 1411 2760 dg199075 load_value(mtp->m_offset, mtp->m_size); 1412 2760 dg199075 load_const(mtp->m_value); 1413 2760 dg199075 emitop(OP_OFFSET_POP); 1414 0 stevel 1415 0 stevel emitop(OP_EQ); 1416 0 stevel 1417 0 stevel if (mtp->m_depend != -1) 1418 0 stevel emitop(OP_AND); 1419 0 stevel } 1420 0 stevel 1421 0 stevel /* 1422 0 stevel * Generate code based on the keyword argument. 1423 0 stevel * This word is looked up in the match_types table 1424 0 stevel * and checks a field within the packet for a given 1425 0 stevel * value e.g. ether or ip type field. The match 1426 0 stevel * can also have a dependency on another entry e.g. 1427 0 stevel * "tcp" requires that the packet also be "ip". 1428 0 stevel */ 1429 0 stevel static int 1430 0 stevel comparison(char *s) 1431 0 stevel { 1432 0 stevel unsigned int i, n_checks = 0; 1433 8023 Phil match_type_t *match_types; 1434 8023 Phil 1435 8023 Phil switch (interface->mac_type) { 1436 8023 Phil case DL_ETHER: 1437 8023 Phil match_types = ether_match_types; 1438 8023 Phil break; 1439 8023 Phil case DL_IPNET: 1440 8023 Phil match_types = ipnet_match_types; 1441 10616 Sebastien break; 1442 10616 Sebastien case DL_IPV4: 1443 10616 Sebastien case DL_IPV6: 1444 10616 Sebastien case DL_6TO4: 1445 10616 Sebastien match_types = iptun_match_types; 1446 8023 Phil break; 1447 8023 Phil default: 1448 8023 Phil return (0); 1449 8023 Phil } 1450 0 stevel 1451 0 stevel for (i = 0; match_types[i].m_name != NULL; i++) { 1452 0 stevel if (strcmp(s, match_types[i].m_name) != 0) 1453 0 stevel continue; 1454 0 stevel 1455 0 stevel n_checks++; 1456 8023 Phil generate_check(match_types, i, interface->mac_type); 1457 0 stevel if (n_checks > 1) 1458 0 stevel emitop(OP_OR); 1459 0 stevel } 1460 0 stevel 1461 0 stevel return (n_checks > 0); 1462 0 stevel } 1463 0 stevel 1464 0 stevel enum direction { ANY, TO, FROM }; 1465 0 stevel enum direction dir; 1466 0 stevel 1467 0 stevel /* 1468 0 stevel * Generate code to match an IP address. The address 1469 0 stevel * may be supplied either as a hostname or in dotted format. 1470 0 stevel * For source packets both the IP source address and ARP 1471 0 stevel * src are checked. 1472 0 stevel * Note: we don't check packet type here - whether IP or ARP. 1473 0 stevel * It's possible that we'll do an improper match. 1474 0 stevel */ 1475 0 stevel static void 1476 0 stevel ipaddr_match(enum direction which, char *hostname, int inet_type) 1477 0 stevel { 1478 0 stevel bool_t found_host; 1479 0 stevel int m = 0, n = 0; 1480 0 stevel uint_t *addr4ptr; 1481 0 stevel uint_t addr4; 1482 0 stevel struct in6_addr *addr6ptr; 1483 0 stevel int h_addr_index; 1484 0 stevel struct hostent *hp = NULL; 1485 0 stevel int error_num = 0; 1486 0 stevel boolean_t freehp = B_FALSE; 1487 0 stevel boolean_t first = B_TRUE; 1488 0 stevel 1489 0 stevel /* 1490 0 stevel * The addr4offset and addr6offset variables simplify the code which 1491 0 stevel * generates the address comparison filter. With these two variables, 1492 0 stevel * duplicate code need not exist for the TO and FROM case. 1493 0 stevel * A value of -1 describes the ANY case (TO and FROM). 1494 0 stevel */ 1495 0 stevel int addr4offset; 1496 0 stevel int addr6offset; 1497 0 stevel 1498 0 stevel found_host = 0; 1499 0 stevel 1500 0 stevel if (tokentype == ADDR_IP) { 1501 8023 Phil hp = lgetipnodebyname(hostname, AF_INET, 0, &error_num); 1502 0 stevel if (hp == NULL) { 1503 8023 Phil hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 1504 0 stevel freehp = 1; 1505 0 stevel } 1506 0 stevel if (hp == NULL) { 1507 0 stevel if (error_num == TRY_AGAIN) { 1508 0 stevel pr_err("couldn't resolve %s (try again later)", 1509 0 stevel hostname); 1510 0 stevel } else { 1511 0 stevel pr_err("couldn't resolve %s", hostname); 1512 0 stevel } 1513 0 stevel } 1514 0 stevel inet_type = IPV4_ONLY; 1515 0 stevel } else if (tokentype == ADDR_IP6) { 1516 8023 Phil hp = lgetipnodebyname(hostname, AF_INET6, 0, &error_num); 1517 0 stevel if (hp == NULL) { 1518 8023 Phil hp = getipnodebyname(hostname, AF_INET6, 0, &error_num); 1519 0 stevel freehp = 1; 1520 0 stevel } 1521 0 stevel if (hp == NULL) { 1522 0 stevel if (error_num == TRY_AGAIN) { 1523 0 stevel pr_err("couldn't resolve %s (try again later)", 1524 0 stevel hostname); 1525 0 stevel } else { 1526 0 stevel pr_err("couldn't resolve %s", hostname); 1527 0 stevel } 1528 0 stevel } 1529 0 stevel inet_type = IPV6_ONLY; 1530 0 stevel } else { 1531 0 stevel /* Some hostname i.e. tokentype is ALPHA */ 1532 0 stevel switch (inet_type) { 1533 0 stevel case IPV4_ONLY: 1534 0 stevel /* Only IPv4 address is needed */ 1535 8023 Phil hp = lgetipnodebyname(hostname, AF_INET, 0, &error_num); 1536 0 stevel if (hp == NULL) { 1537 8023 Phil hp = getipnodebyname(hostname, AF_INET, 0, 1538 8023 Phil &error_num); 1539 0 stevel freehp = 1; 1540 0 stevel } 1541 0 stevel if (hp != NULL) { 1542 0 stevel found_host = 1; 1543 0 stevel } 1544 0 stevel break; 1545 0 stevel case IPV6_ONLY: 1546 0 stevel /* Only IPv6 address is needed */ 1547 8023 Phil hp = lgetipnodebyname(hostname, AF_INET6, 0, 1548 8023 Phil &error_num); 1549 0 stevel if (hp == NULL) { 1550 8023 Phil hp = getipnodebyname(hostname, AF_INET6, 0, 1551 8023 Phil &error_num); 1552 0 stevel freehp = 1; 1553 0 stevel } 1554 0 stevel if (hp != NULL) { 1555 0 stevel found_host = 1; 1556 0 stevel } 1557 0 stevel break; 1558 0 stevel case IPV4_AND_IPV6: 1559 0 stevel /* Both IPv4 and IPv6 are needed */ 1560 0 stevel hp = lgetipnodebyname(hostname, AF_INET6, 1561 8023 Phil AI_ALL | AI_V4MAPPED, &error_num); 1562 0 stevel if (hp == NULL) { 1563 0 stevel hp = getipnodebyname(hostname, AF_INET6, 1564 8023 Phil AI_ALL | AI_V4MAPPED, &error_num); 1565 0 stevel freehp = 1; 1566 0 stevel } 1567 0 stevel if (hp != NULL) { 1568 0 stevel found_host = 1; 1569 0 stevel } 1570 0 stevel break; 1571 0 stevel default: 1572 0 stevel found_host = 0; 1573 0 stevel } 1574 0 stevel 1575 0 stevel if (!found_host) { 1576 0 stevel if (error_num == TRY_AGAIN) { 1577 0 stevel pr_err("could not resolve %s (try again later)", 1578 0 stevel hostname); 1579 0 stevel } else { 1580 0 stevel pr_err("could not resolve %s", hostname); 1581 0 stevel } 1582 0 stevel } 1583 0 stevel } 1584 0 stevel 1585 0 stevel switch (which) { 1586 0 stevel case TO: 1587 0 stevel addr4offset = IPV4_DSTADDR_OFFSET; 1588 0 stevel addr6offset = IPV6_DSTADDR_OFFSET; 1589 0 stevel break; 1590 0 stevel case FROM: 1591 0 stevel addr4offset = IPV4_SRCADDR_OFFSET; 1592 0 stevel addr6offset = IPV6_SRCADDR_OFFSET; 1593 0 stevel break; 1594 0 stevel case ANY: 1595 0 stevel addr4offset = -1; 1596 0 stevel addr6offset = -1; 1597 0 stevel break; 1598 0 stevel } 1599 0 stevel 1600 0 stevel /* 1601 0 stevel * The code below generates the filter. 1602 0 stevel */ 1603 0 stevel if (hp != NULL && hp->h_addrtype == AF_INET) { 1604 8023 Phil ethertype_match(interface->network_type_ip); 1605 0 stevel emitop(OP_BRFL); 1606 0 stevel n = chain(n); 1607 0 stevel emitop(OP_OFFSET_LINK); 1608 0 stevel h_addr_index = 0; 1609 0 stevel addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index]; 1610 0 stevel while (addr4ptr != NULL) { 1611 0 stevel if (addr4offset == -1) { 1612 0 stevel compare_addr_v4(IPV4_SRCADDR_OFFSET, 4, 1613 0 stevel *addr4ptr); 1614 0 stevel emitop(OP_BRTR); 1615 0 stevel m = chain(m); 1616 0 stevel compare_addr_v4(IPV4_DSTADDR_OFFSET, 4, 1617 0 stevel *addr4ptr); 1618 0 stevel } else { 1619 0 stevel compare_addr_v4(addr4offset, 4, *addr4ptr); 1620 0 stevel } 1621 0 stevel addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index]; 1622 0 stevel if (addr4ptr != NULL) { 1623 0 stevel emitop(OP_BRTR); 1624 0 stevel m = chain(m); 1625 0 stevel } 1626 0 stevel } 1627 0 stevel if (m != 0) { 1628 0 stevel resolve_chain(m); 1629 0 stevel } 1630 0 stevel emitop(OP_OFFSET_POP); 1631 0 stevel resolve_chain(n); 1632 0 stevel } else { 1633 0 stevel /* first pass: IPv4 addresses */ 1634 0 stevel h_addr_index = 0; 1635 0 stevel addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 1636 0 stevel first = B_TRUE; 1637 0 stevel while (addr6ptr != NULL) { 1638 0 stevel if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 1639 0 stevel if (first) { 1640 8023 Phil ethertype_match( 1641 8023 Phil interface->network_type_ip); 1642 0 stevel emitop(OP_BRFL); 1643 0 stevel n = chain(n); 1644 0 stevel emitop(OP_OFFSET_LINK); 1645 0 stevel first = B_FALSE; 1646 0 stevel } else { 1647 0 stevel emitop(OP_BRTR); 1648 0 stevel m = chain(m); 1649 0 stevel } 1650 0 stevel IN6_V4MAPPED_TO_INADDR(addr6ptr, 1651 0 stevel (struct in_addr *)&addr4); 1652 0 stevel if (addr4offset == -1) { 1653 0 stevel compare_addr_v4(IPV4_SRCADDR_OFFSET, 4, 1654 0 stevel addr4); 1655 0 stevel emitop(OP_BRTR); 1656 0 stevel m = chain(m); 1657 0 stevel compare_addr_v4(IPV4_DSTADDR_OFFSET, 4, 1658 0 stevel addr4); 1659 0 stevel } else { 1660 0 stevel compare_addr_v4(addr4offset, 4, addr4); 1661 0 stevel } 1662 0 stevel } 1663 0 stevel addr6ptr = (struct in6_addr *) 1664 0 stevel hp->h_addr_list[++h_addr_index]; 1665 0 stevel } 1666 0 stevel /* second pass: IPv6 addresses */ 1667 0 stevel h_addr_index = 0; 1668 0 stevel addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index]; 1669 0 stevel first = B_TRUE; 1670 0 stevel while (addr6ptr != NULL) { 1671 0 stevel if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) { 1672 0 stevel if (first) { 1673 0 stevel /* 1674 0 stevel * bypass check for IPv6 addresses 1675 0 stevel * when we have an IPv4 packet 1676 0 stevel */ 1677 0 stevel if (n != 0) { 1678 0 stevel emitop(OP_BRTR); 1679 0 stevel m = chain(m); 1680 0 stevel emitop(OP_BRFL); 1681 0 stevel m = chain(m); 1682 0 stevel resolve_chain(n); 1683 0 stevel n = 0; 1684 0 stevel } 1685 8023 Phil ethertype_match( 1686 8023 Phil interface->network_type_ipv6); 1687 0 stevel emitop(OP_BRFL); 1688 0 stevel n = chain(n); 1689 0 stevel emitop(OP_OFFSET_LINK); 1690 0 stevel first = B_FALSE; 1691 0 stevel } else { 1692 0 stevel emitop(OP_BRTR); 1693 0 stevel m = chain(m); 1694 0 stevel } 1695 0 stevel if (addr6offset == -1) { 1696 0 stevel compare_addr_v6(IPV6_SRCADDR_OFFSET, 1697 0 stevel 16, *addr6ptr); 1698 0 stevel emitop(OP_BRTR); 1699 0 stevel m = chain(m); 1700 0 stevel compare_addr_v6(IPV6_DSTADDR_OFFSET, 1701 0 stevel 16, *addr6ptr); 1702 0 stevel } else { 1703 0 stevel compare_addr_v6(addr6offset, 16, 1704 0 stevel *addr6ptr); 1705 0 stevel } 1706 0 stevel } 1707 0 stevel addr6ptr = (struct in6_addr *) 1708 0 stevel hp->h_addr_list[++h_addr_index]; 1709 0 stevel } 1710 0 stevel if (m != 0) { 1711 0 stevel resolve_chain(m); 1712 0 stevel } 1713 0 stevel emitop(OP_OFFSET_POP); 1714 0 stevel resolve_chain(n); 1715 0 stevel } 1716 0 stevel 1717 0 stevel /* only free struct hostent returned by getipnodebyname() */ 1718 0 stevel if (freehp) { 1719 0 stevel freehostent(hp); 1720 8023 Phil } 1721 8023 Phil } 1722 8023 Phil 1723 8023 Phil /* 1724 8023 Phil * Match on zoneid. The arg zone passed in is in network byte order. 1725 8023 Phil */ 1726 8023 Phil static void 1727 10639 Darren zone_match(enum direction which, uint32_t zone) 1728 8023 Phil { 1729 8023 Phil 1730 8023 Phil switch (which) { 1731 8023 Phil case TO: 1732 8023 Phil compare_value_zone(IPNET_DSTZONE_OFFSET, zone); 1733 8023 Phil break; 1734 8023 Phil case FROM: 1735 8023 Phil compare_value_zone(IPNET_SRCZONE_OFFSET, zone); 1736 8023 Phil break; 1737 8023 Phil case ANY: 1738 8023 Phil compare_value_zone(IPNET_SRCZONE_OFFSET, zone); 1739 8023 Phil compare_value_zone(IPNET_DSTZONE_OFFSET, zone); 1740 8023 Phil emitop(OP_OR); 1741 0 stevel } 1742 0 stevel } 1743 0 stevel 1744 0 stevel /* 1745 0 stevel * Generate code to match an AppleTalk address. The address 1746 0 stevel * must be given as two numbers with a dot between 1747 0 stevel * 1748 0 stevel */ 1749 0 stevel static void 1750 0 stevel ataddr_match(enum direction which, char *hostname) 1751 0 stevel { 1752 0 stevel uint_t net; 1753 0 stevel uint_t node; 1754 0 stevel uint_t m, n; 1755 0 stevel 1756 0 stevel sscanf(hostname, "%u.%u", &net, &node); 1757 0 stevel 1758 0 stevel emitop(OP_OFFSET_LINK); 1759 0 stevel switch (which) { 1760 0 stevel case TO: 1761 0 stevel compare_value(AT_DST_NET_OFFSET, 2, net); 1762 0 stevel emitop(OP_BRFL); 1763 0 stevel m = chain(0); 1764 0 stevel compare_value(AT_DST_NODE_OFFSET, 1, node); 1765 0 stevel resolve_chain(m); 1766 0 stevel break; 1767 0 stevel case FROM: 1768 0 stevel compare_value(AT_SRC_NET_OFFSET, 2, net); 1769 0 stevel emitop(OP_BRFL); 1770 0 stevel m = chain(0); 1771 0 stevel compare_value(AT_SRC_NODE_OFFSET, 1, node); 1772 0 stevel resolve_chain(m); 1773 0 stevel break; 1774 0 stevel case ANY: 1775 0 stevel compare_value(AT_DST_NET_OFFSET, 2, net); 1776 0 stevel emitop(OP_BRFL); 1777 0 stevel m = chain(0); 1778 0 stevel compare_value(AT_DST_NODE_OFFSET, 1, node); 1779 0 stevel resolve_chain(m); 1780 0 stevel emitop(OP_BRTR); 1781 0 stevel n = chain(0); 1782 0 stevel compare_value(AT_SRC_NET_OFFSET, 2, net); 1783 0 stevel emitop(OP_BRFL); 1784 0 stevel m = chain(0); 1785 0 stevel compare_value(AT_SRC_NODE_OFFSET, 1, node); 1786 0 stevel resolve_chain(m); 1787 0 stevel resolve_chain(n); 1788 0 stevel break; 1789 0 stevel } 1790 0 stevel emitop(OP_OFFSET_POP); 1791 0 stevel } 1792 0 stevel 1793 0 stevel /* 1794 0 stevel * Compare ethernet addresses. The address may 1795 0 stevel * be provided either as a hostname or as a 1796 0 stevel * 6 octet colon-separated address. 1797 0 stevel */ 1798 0 stevel static void 1799 0 stevel etheraddr_match(enum direction which, char *hostname) 1800 0 stevel { 1801 0 stevel uint_t addr; 1802 0 stevel ushort_t *addrp; 1803 0 stevel int to_offset, from_offset; 1804 0 stevel struct ether_addr e, *ep = NULL; 1805 0 stevel int m; 1806 0 stevel 1807 0 stevel /* 1808 0 stevel * First, check the interface type for whether src/dest address 1809 0 stevel * is determinable; if not, retreat early. 1810 0 stevel */ 1811 0 stevel switch (interface->mac_type) { 1812 0 stevel case DL_ETHER: 1813 0 stevel from_offset = ETHERADDRL; 1814 0 stevel to_offset = 0; 1815 0 stevel break; 1816 0 stevel 1817 0 stevel case DL_IB: 1818 0 stevel /* 1819 0 stevel * If an ethernet address is attempted to be used 1820 0 stevel * on an IPoIB interface, flag error. Link address 1821 0 stevel * based filtering is unsupported on IPoIB, so there 1822 0 stevel * is no ipibaddr_match() or parsing support for IPoIB 1823 0 stevel * 20 byte link addresses. 1824 0 stevel */ 1825 0 stevel pr_err("filter option unsupported on media"); 1826 0 stevel break; 1827 0 stevel 1828 0 stevel case DL_FDDI: 1829 0 stevel from_offset = 7; 1830 0 stevel to_offset = 1; 1831 0 stevel break; 1832 0 stevel 1833 0 stevel default: 1834 0 stevel /* 1835 0 stevel * Where do we find "ether" address for FDDI & TR? 1836 0 stevel * XXX can improve? ~sparker 1837 0 stevel */ 1838 0 stevel load_const(1); 1839 0 stevel return; 1840 0 stevel } 1841 0 stevel 1842 0 stevel if (isxdigit(*hostname)) 1843 0 stevel ep = ether_aton(hostname); 1844 0 stevel if (ep == NULL) { 1845 0 stevel if (ether_hostton(hostname, &e)) 1846 0 stevel if (!arp_for_ether(hostname, &e)) 1847 0 stevel pr_err("cannot obtain ether addr for %s", 1848 8023 Phil hostname); 1849 0 stevel ep = &e; 1850 0 stevel } 1851 0 stevel memcpy(&addr, (ushort_t *)ep, 4); 1852 0 stevel addrp = (ushort_t *)ep + 2; 1853 0 stevel 1854 2760 dg199075 emitop(OP_OFFSET_ZERO); 1855 0 stevel switch (which) { 1856 0 stevel case TO: 1857 0 stevel compare_value(to_offset, 4, ntohl(addr)); 1858 0 stevel emitop(OP_BRFL); 1859 0 stevel m = chain(0); 1860 0 stevel compare_value(to_offset + 4, 2, ntohs(*addrp)); 1861 0 stevel resolve_chain(m); 1862 0 stevel break; 1863 0 stevel case FROM: 1864 0 stevel compare_value(from_offset, 4, ntohl(addr)); 1865 0 stevel emitop(OP_BRFL); 1866 0 stevel m = chain(0); 1867 0 stevel compare_value(from_offset + 4, 2, ntohs(*addrp)); 1868 0 stevel resolve_chain(m); 1869 0 stevel break; 1870 0 stevel case ANY: 1871 0 stevel compare_value(to_offset, 4, ntohl(addr)); 1872 0 stevel compare_value(to_offset + 4, 2, ntohs(*addrp)); 1873 0 stevel emitop(OP_AND); 1874 0 stevel emitop(OP_BRTR); 1875 0 stevel m = chain(0); 1876 0 stevel 1877 0 stevel compare_value(from_offset, 4, ntohl(addr)); 1878 0 stevel compare_value(from_offset + 4, 2, ntohs(*addrp)); 1879 0 stevel emitop(OP_AND); 1880 0 stevel resolve_chain(m); 1881 0 stevel break; 1882 0 stevel } 1883 2760 dg199075 emitop(OP_OFFSET_POP); 1884 0 stevel } 1885 0 stevel 1886 0 stevel static void 1887 0 stevel ethertype_match(int val) 1888 0 stevel { 1889 2760 dg199075 int ether_offset = interface->network_type_offset; 1890 0 stevel 1891 2760 dg199075 /* 1892 2760 dg199075 * If the user is interested in ethertype VLAN, 1893 2760 dg199075 * then we need to set the offset to the beginning of the packet. 1894 2760 dg199075 * But if the user is interested in another ethertype, 1895 2760 dg199075 * such as IPv4, then we need to take into consideration 1896 2760 dg199075 * the fact that the packet might be VLAN tagged. 1897 2760 dg199075 */ 1898 2760 dg199075 if (interface->mac_type == DL_ETHER || 1899 2760 dg199075 interface->mac_type == DL_CSMACD) { 1900 2760 dg199075 if (val != ETHERTYPE_VLAN) { 1901 2760 dg199075 /* 1902 2760 dg199075 * OP_OFFSET_ETHERTYPE puts us at the ethertype 1903 2760 dg199075 * field whether or not there is a VLAN tag, 1904 2760 dg199075 * so ether_offset goes to zero if we get here. 1905 2760 dg199075 */ 1906 2760 dg199075 emitop(OP_OFFSET_ETHERTYPE); 1907 2760 dg199075 ether_offset = 0; 1908 2760 dg199075 } else { 1909 2760 dg199075 emitop(OP_OFFSET_ZERO); 1910 2760 dg199075 } 1911 0 stevel } 1912 8023 Phil compare_value(ether_offset, interface->network_type_len, val); 1913 2760 dg199075 if (interface->mac_type == DL_ETHER || 1914 2760 dg199075 interface->mac_type == DL_CSMACD) { 1915 2760 dg199075 emitop(OP_OFFSET_POP); 1916 2760 dg199075 } 1917 0 stevel } 1918 0 stevel 1919 0 stevel /* 1920 0 stevel * Match a network address. The host part 1921 0 stevel * is masked out. The network address may 1922 0 stevel * be supplied either as a netname or in 1923 0 stevel * IP dotted format. The mask to be used 1924 0 stevel * for the comparison is assumed from the 1925 0 stevel * address format (see comment below). 1926 0 stevel */ 1927 0 stevel static void 1928 0 stevel netaddr_match(enum direction which, char *netname) 1929 0 stevel { 1930 0 stevel uint_t addr; 1931 0 stevel uint_t mask = 0xff000000; 1932 0 stevel uint_t m; 1933 0 stevel struct netent *np; 1934 0 stevel 1935 0 stevel if (isdigit(*netname)) { 1936 0 stevel addr = inet_network(netname); 1937 0 stevel } else { 1938 0 stevel np = getnetbyname(netname); 1939 0 stevel if (np == NULL) 1940 0 stevel pr_err("net %s not known", netname); 1941 0 stevel addr = np->n_net; 1942 0 stevel } 1943 0 stevel 1944 0 stevel /* 1945 0 stevel * Left justify the address and figure 1946 0 stevel * out a mask based on the supplied address. 1947 0 stevel * Set the mask according to the number of zero 1948 0 stevel * low-order bytes. 1949 0 stevel * Note: this works only for whole octet masks. 1950 0 stevel */ 1951 0 stevel if (addr) { 1952 0 stevel while ((addr & ~mask) != 0) { 1953 0 stevel mask |= (mask >> 8); 1954 0 stevel } 1955 0 stevel } 1956 0 stevel 1957 0 stevel emitop(OP_OFFSET_LINK); 1958 0 stevel switch (which) { 1959 0 stevel case TO: 1960 0 stevel compare_value_mask(16, 4, addr, mask); 1961 0 stevel break; 1962 0 stevel case FROM: 1963 0 stevel compare_value_mask(12, 4, addr, mask); 1964 0 stevel break; 1965 0 stevel case ANY: 1966 0 stevel compare_value_mask(12, 4, addr, mask); 1967 0 stevel emitop(OP_BRTR); 1968 0 stevel m = chain(0); 1969 0 stevel compare_value_mask(16, 4, addr, mask); 1970 0 stevel resolve_chain(m); 1971 0 stevel break; 1972 0 stevel } 1973 0 stevel emitop(OP_OFFSET_POP); 1974 0 stevel } 1975 0 stevel 1976 0 stevel /* 1977 0 stevel * Match either a UDP or TCP port number. 1978 0 stevel * The port number may be provided either as 1979 0 stevel * port name as listed in /etc/services ("nntp") or as 1980 0 stevel * the port number itself (2049). 1981 0 stevel */ 1982 0 stevel static void 1983 0 stevel port_match(enum direction which, char *portname) 1984 0 stevel { 1985 0 stevel struct servent *sp; 1986 0 stevel uint_t m, port; 1987 0 stevel 1988 0 stevel if (isdigit(*portname)) { 1989 0 stevel port = atoi(portname); 1990 0 stevel } else { 1991 0 stevel sp = getservbyname(portname, NULL); 1992 0 stevel if (sp == NULL) 1993 8023 Phil pr_err("invalid port number or name: %s", portname); 1994 0 stevel port = ntohs(sp->s_port); 1995 0 stevel } 1996 0 stevel 1997 0 stevel emitop(OP_OFFSET_IP); 1998 0 stevel 1999 0 stevel switch (which) { 2000 0 stevel case TO: 2001 0 stevel compare_value(2, 2, port); 2002 0 stevel break; 2003 0 stevel case FROM: 2004 0 stevel compare_value(0, 2, port); 2005 0 stevel break; 2006 0 stevel case ANY: 2007 0 stevel compare_value(2, 2, port); 2008 0 stevel emitop(OP_BRTR); 2009 0 stevel m = chain(0); 2010 0 stevel compare_value(0, 2, port); 2011 0 stevel resolve_chain(m); 2012 0 stevel break; 2013 0 stevel } 2014 0 stevel emitop(OP_OFFSET_POP); 2015 0 stevel } 2016 0 stevel 2017 0 stevel /* 2018 0 stevel * Generate code to match packets with a specific 2019 0 stevel * RPC program number. If the progname is a name 2020 0 stevel * it is converted to a number via /etc/rpc. 2021 0 stevel * The program version and/or procedure may be provided 2022 0 stevel * as extra qualifiers. 2023 0 stevel */ 2024 0 stevel static void 2025 0 stevel rpc_match_prog(enum direction which, char *progname, int vers, int proc) 2026 0 stevel { 2027 0 stevel struct rpcent *rpc; 2028 0 stevel uint_t prog; 2029 0 stevel uint_t m, n; 2030 0 stevel 2031 0 stevel if (isdigit(*progname)) { 2032 0 stevel prog = atoi(progname); 2033 0 stevel } else { 2034 0 stevel rpc = (struct rpcent *)getrpcbyname(progname); 2035 0 stevel if (rpc == NULL) 2036 0 stevel pr_err("invalid program name: %s", progname); 2037 0 stevel prog = rpc->r_number; 2038 0 stevel } 2039 0 stevel 2040 0 stevel emitop(OP_OFFSET_RPC); 2041 0 stevel emitop(OP_BRFL); 2042 0 stevel n = chain(0); 2043 0 stevel 2044 0 stevel compare_value(12, 4, prog); 2045 0 stevel emitop(OP_BRFL); 2046 0 stevel m = chain(0); 2047 0 stevel if (vers >= 0) { 2048 0 stevel compare_value(16, 4, vers); 2049 0 stevel emitop(OP_BRFL); 2050 0 stevel m = chain(m); 2051 0 stevel } 2052 0 stevel if (proc >= 0) { 2053 0 stevel compare_value(20, 4, proc); 2054 0 stevel emitop(OP_BRFL); 2055 0 stevel m = chain(m); 2056 0 stevel } 2057 0 stevel 2058 0 stevel switch (which) { 2059 0 stevel case TO: 2060 0 stevel compare_value(4, 4, CALL); 2061 0 stevel emitop(OP_BRFL); 2062 0 stevel m = chain(m); 2063 0 stevel break; 2064 0 stevel case FROM: 2065 0 stevel compare_value(4, 4, REPLY); 2066 0 stevel emitop(OP_BRFL); 2067 0 stevel m = chain(m); 2068 0 stevel break; 2069 0 stevel } 2070 0 stevel resolve_chain(m); 2071 0 stevel resolve_chain(n); 2072 0 stevel emitop(OP_OFFSET_POP); 2073 0 stevel } 2074 0 stevel 2075 0 stevel /* 2076 0 stevel * Generate code to parse a field specification 2077 0 stevel * and load the value of the field from the packet 2078 0 stevel * onto the operand stack. 2079 0 stevel * The field offset may be specified relative to the 2080 0 stevel * beginning of the ether header, IP header, UDP header, 2081 0 stevel * or TCP header. An optional size specification may 2082 0 stevel * be provided following a colon. If no size is given 2083 0 stevel * one byte is assumed e.g. 2084 0 stevel * 2085 0 stevel * ether[0] The first byte of the ether header 2086 0 stevel * ip[2:2] The second 16 bit field of the IP header 2087 0 stevel */ 2088 0 stevel static void 2089 0 stevel load_field() 2090 0 stevel { 2091 0 stevel int size = 1; 2092 0 stevel int s; 2093 0 stevel 2094 0 stevel 2095 0 stevel if (EQ("ether")) 2096 0 stevel emitop(OP_OFFSET_ZERO); 2097 0 stevel else if (EQ("ip") || EQ("ip6") || EQ("pppoed") || EQ("pppoes")) 2098 0 stevel emitop(OP_OFFSET_LINK); 2099 0 stevel else if (EQ("udp") || EQ("tcp") || EQ("icmp") || EQ("ip-in-ip") || 2100 0 stevel EQ("ah") || EQ("esp")) 2101 0 stevel emitop(OP_OFFSET_IP); 2102 0 stevel else 2103 0 stevel pr_err("invalid field type"); 2104 0 stevel next(); 2105 0 stevel s = opstack; 2106 0 stevel expression(); 2107 0 stevel if (opstack != s + 1) 2108 0 stevel pr_err("invalid field offset"); 2109 0 stevel opstack--; 2110 0 stevel if (*token == ':') { 2111 0 stevel next(); 2112 0 stevel if (tokentype != NUMBER) 2113 0 stevel pr_err("field size expected"); 2114 0 stevel size = tokenval; 2115 0 stevel if (size != 1 && size != 2 && size != 4) 2116 0 stevel pr_err("field size invalid"); 2117 0 stevel next(); 2118 0 stevel } 2119 0 stevel if (*token != ']') 2120 0 stevel pr_err("right bracket expected"); 2121 0 stevel 2122 0 stevel load_value(-1, size); 2123 0 stevel emitop(OP_OFFSET_POP); 2124 0 stevel } 2125 0 stevel 2126 0 stevel /* 2127 0 stevel * Check that the operand stack 2128 0 stevel * contains n arguments 2129 0 stevel */ 2130 0 stevel static void 2131 0 stevel checkstack(int numargs) 2132 0 stevel { 2133 0 stevel if (opstack != numargs) 2134 0 stevel pr_err("invalid expression at \"%s\".", token); 2135 0 stevel } 2136 0 stevel 2137 0 stevel static void 2138 0 stevel primary() 2139 0 stevel { 2140 3431 carlsonj int m, m2, s; 2141 0 stevel 2142 0 stevel for (;;) { 2143 0 stevel if (tokentype == FIELD) { 2144 0 stevel load_field(); 2145 0 stevel opstack++; 2146 0 stevel next(); 2147 0 stevel break; 2148 0 stevel } 2149 0 stevel 2150 0 stevel if (comparison(token)) { 2151 0 stevel opstack++; 2152 0 stevel next(); 2153 0 stevel break; 2154 0 stevel } 2155 0 stevel 2156 0 stevel if (EQ("not") || EQ("!")) { 2157 0 stevel next(); 2158 0 stevel s = opstack; 2159 0 stevel primary(); 2160 0 stevel checkstack(s + 1); 2161 0 stevel emitop(OP_NOT); 2162 0 stevel break; 2163 0 stevel } 2164 0 stevel 2165 0 stevel if (EQ("(")) { 2166 0 stevel next(); 2167 0 stevel s = opstack; 2168 0 stevel expression(); 2169 0 stevel checkstack(s + 1); 2170 0 stevel if (!EQ(")")) 2171 0 stevel pr_err("right paren expected"); 2172 0 stevel next(); 2173 0 stevel } 2174 0 stevel 2175 0 stevel if (EQ("to") || EQ("dst")) { 2176 0 stevel dir = TO; 2177 0 stevel next(); 2178 0 stevel continue; 2179 0 stevel } 2180 0 stevel 2181 0 stevel if (EQ("from") || EQ("src")) { 2182 0 stevel dir = FROM; 2183 0 stevel next(); 2184 0 stevel continue; 2185 0 stevel } 2186 0 stevel 2187 0 stevel if (EQ("ether")) { 2188 0 stevel eaddr = 1; 2189 0 stevel next(); 2190 0 stevel continue; 2191 0 stevel } 2192 0 stevel 2193 3220 dg199075 if (EQ("proto")) { 2194 3220 dg199075 next(); 2195 3220 dg199075 if (tokentype != NUMBER) 2196 3220 dg199075 pr_err("IP proto type expected"); 2197 3220 dg199075 emitop(OP_OFFSET_LINK); 2198 3220 dg199075 compare_value(IPV4_TYPE_HEADER_OFFSET, 1, tokenval); 2199 3220 dg199075 emitop(OP_OFFSET_POP); 2200 3220 dg199075 opstack++; 2201 0 stevel next(); 2202 0 stevel continue; 2203 0 stevel } 2204 0 stevel 2205 0 stevel if (EQ("broadcast")) { 2206 0 stevel /* 2207 0 stevel * Be tricky: FDDI ether dst address begins at 2208 0 stevel * byte one. Since the address is really six 2209 0 stevel * bytes long, this works for FDDI & ethernet. 2210 0 stevel * XXX - Token ring? 2211 0 stevel */ 2212 2760 dg199075 emitop(OP_OFFSET_ZERO); 2213 0 stevel if (interface->mac_type == DL_IB) 2214 0 stevel pr_err("filter option unsupported on media"); 2215 0 stevel compare_value(1, 4, 0xffffffff); 2216 2760 dg199075 emitop(OP_OFFSET_POP); 2217 0 stevel opstack++; 2218 0 stevel next(); 2219 0 stevel break; 2220 0 stevel } 2221 0 stevel 2222 0 stevel if (EQ("multicast")) { 2223 0 stevel /* XXX Token ring? */ 2224 2760 dg199075 emitop(OP_OFFSET_ZERO); 2225 0 stevel if (interface->mac_type == DL_FDDI) { 2226 0 stevel compare_value_mask(1, 1, 0x01, 0x01); 2227 0 stevel } else if (interface->mac_type == DL_IB) { 2228 0 stevel pr_err("filter option unsupported on media"); 2229 0 stevel } else { 2230 0 stevel compare_value_mask(0, 1, 0x01, 0x01); 2231 0 stevel } 2232 2760 dg199075 emitop(OP_OFFSET_POP); 2233 0 stevel opstack++; 2234 0 stevel next(); 2235 0 stevel break; 2236 0 stevel } 2237 0 stevel 2238 0 stevel if (EQ("decnet")) { 2239 0 stevel /* XXX Token ring? */ 2240 0 stevel if (interface->mac_type == DL_FDDI) { 2241 0 stevel load_value(19, 2); /* ether type */ 2242 0 stevel load_const(0x6000); 2243 0 stevel emitop(OP_GE); 2244 0 stevel emitop(OP_BRFL); 2245 0 stevel m = chain(0); 2246 0 stevel load_value(19, 2); /* ether type */ 2247 0 stevel load_const(0x6009); 2248 0 stevel emitop(OP_LE); 2249 0 stevel resolve_chain(m); 2250 0 stevel } else { 2251 2760 dg199075 emitop(OP_OFFSET_ETHERTYPE); 2252 2760 dg199075 load_value(0, 2); /* ether type */ 2253 0 stevel load_const(0x6000); 2254 0 stevel emitop(OP_GE); 2255 0 stevel emitop(OP_BRFL); 2256 0 stevel m = chain(0); 2257 2760 dg199075 load_value(0, 2); /* ether type */ 2258 0 stevel load_const(0x6009); 2259 0 stevel emitop(OP_LE); 2260 0 stevel resolve_chain(m); 2261 2760 dg199075 emitop(OP_OFFSET_POP); 2262 0 stevel } 2263 2760 dg199075 opstack++; 2264 2760 dg199075 next(); 2265 2760 dg199075 break; 2266 2760 dg199075 } 2267 2760 dg199075 2268 2760 dg199075 if (EQ("vlan-id")) { 2269 2760 dg199075 next(); 2270 2760 dg199075 if (tokentype != NUMBER) 2271 2760 dg199075 pr_err("vlan id expected"); 2272 2760 dg199075 emitop(OP_OFFSET_ZERO); 2273 2760 dg199075 ethertype_match(ETHERTYPE_VLAN); 2274 2760 dg199075 emitop(OP_BRFL); 2275 2760 dg199075 m = chain(0); 2276 2760 dg199075 compare_value_mask(VLAN_ID_OFFSET, 2, tokenval, 2277 2760 dg199075 VLAN_ID_MASK); 2278 2760 dg199075 resolve_chain(m); 2279 2760 dg199075 emitop(OP_OFFSET_POP); 2280 0 stevel opstack++; 2281 0 stevel next(); 2282 0 stevel break; 2283 0 stevel } 2284 0 stevel 2285 0 stevel if (EQ("apple")) { 2286 0 stevel /* 2287 0 stevel * Appletalk also appears in 802.2 2288 0 stevel * packets, so check for the ethertypes 2289 0 stevel * at offset 12 and 20 in the MAC header. 2290 0 stevel */ 2291 0 stevel ethertype_match(ETHERTYPE_AT); 2292 0 stevel emitop(OP_BRTR); 2293 0 stevel m = chain(0); 2294 0 stevel ethertype_match(ETHERTYPE_AARP); 2295 0 stevel emitop(OP_BRTR); 2296 0 stevel m = chain(m); 2297 0 stevel compare_value(20, 2, ETHERTYPE_AT); /* 802.2 */ 2298 0 stevel emitop(OP_BRTR); 2299 0 stevel m = chain(m); 2300 0 stevel compare_value(20, 2, ETHERTYPE_AARP); /* 802.2 */ 2301 0 stevel resolve_chain(m); 2302 0 stevel opstack++; 2303 0 stevel next(); 2304 0 stevel break; 2305 0 stevel } 2306 0 stevel 2307 2760 dg199075 if (EQ("vlan")) { 2308 2760 dg199075 ethertype_match(ETHERTYPE_VLAN); 2309 2760 dg199075 compare_value_mask(VLAN_ID_OFFSET, 2, 0, VLAN_ID_MASK); 2310 2760 dg199075 emitop(OP_NOT); 2311 2760 dg199075 emitop(OP_AND); 2312 2760 dg199075 opstack++; 2313 2760 dg199075 next(); 2314 2760 dg199075 break; 2315 2760 dg199075 } 2316 2760 dg199075 2317 0 stevel if (EQ("bootp") || EQ("dhcp")) { 2318 8023 Phil ethertype_match(interface->network_type_ip); 2319 3431 carlsonj emitop(OP_BRFL); 2320 3431 carlsonj m = chain(0); 2321 0 stevel emitop(OP_OFFSET_LINK); 2322 3431 carlsonj compare_value(9, 1, IPPROTO_UDP); 2323 3431 carlsonj emitop(OP_OFFSET_POP); 2324 3431 carlsonj emitop(OP_BRFL); 2325 3431 carlsonj m = chain(m); 2326 0 stevel emitop(OP_OFFSET_IP); 2327 0 stevel compare_value(0, 4, 2328 3431 carlsonj (IPPORT_BOOTPS << 16) | IPPORT_BOOTPC); 2329 0 stevel emitop(OP_BRTR); 2330 3431 carlsonj m2 = chain(0); 2331 3431 carlsonj compare_value(0, 4, 2332 3431 carlsonj (IPPORT_BOOTPC << 16) | IPPORT_BOOTPS); 2333 3431 carlsonj resolve_chain(m2); 2334 3431 carlsonj emitop(OP_OFFSET_POP); 2335 3431 carlsonj resolve_chain(m); 2336 3431 carlsonj opstack++; 2337 3431 carlsonj dir = ANY; 2338 3431 carlsonj next(); 2339 3431 carlsonj break; 2340 3431 carlsonj } 2341 3431 carlsonj 2342 3431 carlsonj if (EQ("dhcp6")) { 2343 8023 Phil ethertype_match(interface->network_type_ipv6); 2344 3431 carlsonj emitop(OP_BRFL); 2345 0 stevel m = chain(0); 2346 3431 carlsonj emitop(OP_OFFSET_LINK); 2347 3431 carlsonj compare_value(6, 1, IPPROTO_UDP); 2348 3431 carlsonj emitop(OP_OFFSET_POP); 2349 3431 carlsonj emitop(OP_BRFL); 2350 3431 carlsonj m = chain(m); 2351 3431 carlsonj emitop(OP_OFFSET_IP); 2352 3431 carlsonj compare_value(2, 2, IPPORT_DHCPV6S); 2353 3431 carlsonj emitop(OP_BRTR); 2354 3431 carlsonj m2 = chain(0); 2355 3431 carlsonj compare_value(2, 2, IPPORT_DHCPV6C); 2356 3431 carlsonj resolve_chain(m2); 2357 3431 carlsonj emitop(OP_OFFSET_POP); 2358 0 stevel resolve_chain(m); 2359 0 stevel opstack++; 2360 0 stevel dir = ANY; 2361 0 stevel next(); 2362 0 stevel break; 2363 0 stevel } 2364 0 stevel 2365 0 stevel if (EQ("ethertype")) { 2366 0 stevel next(); 2367 0 stevel if (tokentype != NUMBER) 2368 0 stevel pr_err("ether type expected"); 2369 0 stevel ethertype_match(tokenval); 2370 0 stevel opstack++; 2371 0 stevel next(); 2372 0 stevel break; 2373 0 stevel } 2374 0 stevel 2375 0 stevel if (EQ("pppoe")) { 2376 0 stevel ethertype_match(ETHERTYPE_PPPOED); 2377 0 stevel ethertype_match(ETHERTYPE_PPPOES); 2378 0 stevel emitop(OP_OR); 2379 0 stevel opstack++; 2380 0 stevel next(); 2381 0 stevel break; 2382 0 stevel } 2383 0 stevel 2384 0 stevel if (EQ("inet")) { 2385 0 stevel next(); 2386 0 stevel if (EQ("host")) 2387 0 stevel next(); 2388 0 stevel if (tokentype != ALPHA && tokentype != ADDR_IP) 2389 0 stevel pr_err("host/IPv4 addr expected after inet"); 2390 0 stevel ipaddr_match(dir, token, IPV4_ONLY); 2391 0 stevel opstack++; 2392 0 stevel next(); 2393 0 stevel break; 2394 0 stevel } 2395 0 stevel 2396 0 stevel if (EQ("inet6")) { 2397 0 stevel next(); 2398 0 stevel if (EQ("host")) 2399 0 stevel next(); 2400 0 stevel if (tokentype != ALPHA && tokentype != ADDR_IP6) 2401 0 stevel pr_err("host/IPv6 addr expected after inet6"); 2402 0 stevel ipaddr_match(dir, token, IPV6_ONLY); 2403 0 stevel opstack++; 2404 0 stevel next(); 2405 0 stevel break; 2406 0 stevel } 2407 0 stevel 2408 0 stevel if (EQ("length")) { 2409 0 stevel emitop(OP_LOAD_LENGTH); 2410 0 stevel opstack++; 2411 0 stevel next(); 2412 0 stevel break; 2413 0 stevel } 2414 0 stevel 2415 0 stevel if (EQ("less")) { 2416 0 stevel next(); 2417 0 stevel if (tokentype != NUMBER) 2418 0 stevel pr_err("packet length expected"); 2419 0 stevel emitop(OP_LOAD_LENGTH); 2420 0 stevel load_const(tokenval); 2421 0 stevel emitop(OP_LT); 2422 0 stevel opstack++; 2423 0 stevel next(); 2424 0 stevel break; 2425 0 stevel } 2426 0 stevel 2427 0 stevel if (EQ("greater")) { 2428 0 stevel next(); 2429 0 stevel if (tokentype != NUMBER) 2430 0 stevel pr_err("packet length expected"); 2431 0 stevel emitop(OP_LOAD_LENGTH); 2432 0 stevel load_const(tokenval); 2433 0 stevel emitop(OP_GT); 2434 0 stevel opstack++; 2435 0 stevel next(); 2436 0 stevel break; 2437 0 stevel } 2438 0 stevel 2439 0 stevel if (EQ("nofrag")) { 2440 0 stevel emitop(OP_OFFSET_LINK); 2441 0 stevel compare_value_mask(6, 2, 0, 0x1fff); 2442 0 stevel emitop(OP_OFFSET_POP); 2443 0 stevel emitop(OP_BRFL); 2444 0 stevel m = chain(0); 2445 8023 Phil ethertype_match(interface->network_type_ip); 2446 0 stevel resolve_chain(m); 2447 0 stevel opstack++; 2448 0 stevel next(); 2449 0 stevel break; 2450 0 stevel } 2451 0 stevel 2452 0 stevel if (EQ("net") || EQ("dstnet") || EQ("srcnet")) { 2453 0 stevel if (EQ("dstnet")) 2454 0 stevel dir = TO; 2455 0 stevel else if (EQ("srcnet")) 2456 0 stevel dir = FROM; 2457 0 stevel next(); 2458 0 stevel netaddr_match(dir, token); 2459 0 stevel dir = ANY; 2460 0 stevel opstack++; 2461 0 stevel next(); 2462 0 stevel break; 2463 0 stevel } 2464 0 stevel 2465 0 stevel if (EQ("port") || EQ("srcport") || EQ("dstport")) { 2466 0 stevel if (EQ("dstport")) 2467 0 stevel dir = TO; 2468 0 stevel else if (EQ("srcport")) 2469 0 stevel dir = FROM; 2470 0 stevel next(); 2471 0 stevel port_match(dir, token); 2472 0 stevel dir = ANY; 2473 0 stevel opstack++; 2474 0 stevel next(); 2475 0 stevel break; 2476 0 stevel } 2477 0 stevel 2478 0 stevel if (EQ("rpc")) { 2479 0 stevel uint_t vers, proc; 2480 0 stevel char savetoken[32]; 2481 0 stevel 2482 0 stevel vers = proc = -1; 2483 0 stevel next(); 2484 0 stevel (void) strlcpy(savetoken, token, sizeof (savetoken)); 2485 0 stevel next(); 2486 0 stevel if (*token == ',') { 2487 0 stevel next(); 2488 0 stevel if (tokentype != NUMBER) 2489 0 stevel pr_err("version number expected"); 2490 0 stevel vers = tokenval; 2491 0 stevel next(); 2492 0 stevel } 2493 0 stevel if (*token == ',') { 2494 0 stevel next(); 2495 0 stevel if (tokentype != NUMBER) 2496 0 stevel pr_err("proc number expected"); 2497 0 stevel proc = tokenval; 2498 0 stevel next(); 2499 0 stevel } 2500 0 stevel rpc_match_prog(dir, savetoken, vers, proc); 2501 0 stevel dir = ANY; 2502 0 stevel opstack++; 2503 0 stevel break; 2504 0 stevel } 2505 0 stevel 2506 0 stevel if (EQ("slp")) { 2507 8023 Phil /* filter out TCP handshakes */ 2508 8023 Phil emitop(OP_OFFSET_LINK); 2509 8023 Phil compare_value(9, 1, IPPROTO_TCP); 2510 8023 Phil emitop(OP_LOAD_CONST); 2511 8023 Phil emitval(52); 2512 8023 Phil emitop(OP_LOAD_CONST); 2513 8023 Phil emitval(2); 2514 8023 Phil emitop(OP_LOAD_SHORT); 2515 8023 Phil emitop(OP_GE); 2516 8023 Phil emitop(OP_AND); /* proto == TCP && len < 52 */ 2517 8023 Phil emitop(OP_NOT); 2518 8023 Phil emitop(OP_BRFL); /* pkt too short to be a SLP call */ 2519 8023 Phil m = chain(0); 2520 0 stevel 2521 8023 Phil emitop(OP_OFFSET_POP); 2522 8023 Phil emitop(OP_OFFSET_SLP); 2523 8023 Phil resolve_chain(m); 2524 8023 Phil opstack++; 2525 8023 Phil next(); 2526 8023 Phil break; 2527 0 stevel } 2528 0 stevel 2529 0 stevel if (EQ("ldap")) { 2530 0 stevel dir = ANY; 2531 0 stevel port_match(dir, "ldap"); 2532 0 stevel opstack++; 2533 0 stevel next(); 2534 0 stevel break; 2535 0 stevel } 2536 0 stevel 2537 0 stevel if (EQ("and") || EQ("or")) { 2538 8023 Phil break; 2539 8023 Phil } 2540 8023 Phil 2541 8023 Phil if (EQ("zone")) { 2542 8023 Phil next(); 2543 8023 Phil if (tokentype != NUMBER) 2544 8023 Phil pr_err("zoneid expected"); 2545 10639 Darren zone_match(dir, BE_32((uint32_t)(tokenval))); 2546 8023 Phil opstack++; 2547 8023 Phil next(); 2548 0 stevel break; 2549 0 stevel } 2550 0 stevel 2551 0 stevel if (EQ("gateway")) { 2552 0 stevel next(); 2553 0 stevel if (eaddr || tokentype != ALPHA) 2554 0 stevel pr_err("hostname required: %s", token); 2555 0 stevel etheraddr_match(dir, token); 2556 0 stevel dir = ANY; 2557 0 stevel emitop(OP_BRFL); 2558 0 stevel m = chain(0); 2559 0 stevel ipaddr_match(dir, token, IPV4_AND_IPV6); 2560 0 stevel emitop(OP_NOT); 2561 0 stevel resolve_chain(m); 2562 0 stevel opstack++; 2563 0 stevel next(); 2564 0 stevel } 2565 0 stevel 2566 0 stevel if (EQ("host") || EQ("between") || 2567 0 stevel tokentype == ALPHA || /* assume its a hostname */ 2568 0 stevel tokentype == ADDR_IP || 2569 0 stevel tokentype == ADDR_IP6 || 2570 0 stevel tokentype == ADDR_AT || 2571 0 stevel tokentype == ADDR_ETHER) { 2572 0 stevel if (EQ("host") || EQ("between")) 2573 0 stevel next(); 2574 0 stevel if (eaddr || tokentype == ADDR_ETHER) { 2575 0 stevel etheraddr_match(dir, token); 2576 0 stevel } else if (tokentype == ALPHA) { 2577 0 stevel ipaddr_match(dir, token, IPV4_AND_IPV6); 2578 0 stevel } else if (tokentype == ADDR_AT) { 2579 0 stevel ataddr_match(dir, token); 2580 0 stevel } else if (tokentype == ADDR_IP) { 2581 0 stevel ipaddr_match(dir, token, IPV4_ONLY); 2582 0 stevel } else { 2583 0 stevel ipaddr_match(dir, token, IPV6_ONLY); 2584 0 stevel } 2585 0 stevel dir = ANY; 2586 0 stevel eaddr = 0; 2587 0 stevel opstack++; 2588 0 stevel next(); 2589 0 stevel break; 2590 0 stevel } 2591 0 stevel 2592 0 stevel if (tokentype == NUMBER) { 2593 0 stevel load_const(tokenval); 2594 0 stevel opstack++; 2595 0 stevel next(); 2596 0 stevel break; 2597 0 stevel } 2598 0 stevel 2599 0 stevel break; /* unknown token */ 2600 0 stevel } 2601 0 stevel } 2602 0 stevel 2603 0 stevel struct optable { 2604 0 stevel char *op_tok; 2605 0 stevel enum optype op_type; 2606 0 stevel }; 2607 0 stevel 2608 0 stevel static struct optable 2609 0 stevel mulops[] = { 2610 0 stevel "*", OP_MUL, 2611 0 stevel "/", OP_DIV, 2612 0 stevel "%", OP_REM, 2613 0 stevel "&", OP_AND, 2614 0 stevel "", OP_STOP, 2615 0 stevel }; 2616 0 stevel 2617 0 stevel static struct optable 2618 0 stevel addops[] = { 2619 0 stevel "+", OP_ADD, 2620 0 stevel "-", OP_SUB, 2621 0 stevel "|", OP_OR, 2622 0 stevel "^", OP_XOR, 2623 0 stevel "", OP_STOP, 2624 0 stevel }; 2625 0 stevel 2626 0 stevel static struct optable 2627 0 stevel compareops[] = { 2628 0 stevel "==", OP_EQ, 2629 0 stevel "=", OP_EQ, 2630 0 stevel "!=", OP_NE, 2631 0 stevel ">", OP_GT, 2632 0 stevel ">=", OP_GE, 2633 0 stevel "<", OP_LT, 2634 0 stevel "<=", OP_LE, 2635 0 stevel "", OP_STOP, 2636 0 stevel }; 2637 0 stevel 2638 0 stevel /* 2639 0 stevel * Using the table, find the operator 2640 0 stevel * that corresponds to the token. 2641 0 stevel * Return 0 if not found. 2642 0 stevel */ 2643 0 stevel static int 2644 0 stevel find_op(char *tok, struct optable *table) 2645 0 stevel { 2646 0 stevel struct optable *op; 2647 0 stevel 2648 0 stevel for (op = table; *op->op_tok; op++) { 2649 0 stevel if (strcmp(tok, op->op_tok) == 0) 2650 0 stevel return (op->op_type); 2651 0 stevel } 2652 0 stevel 2653 0 stevel return (0); 2654 0 stevel } 2655 0 stevel 2656 0 stevel static void 2657 0 stevel expr_mul() 2658 0 stevel { 2659 0 stevel int op; 2660 0 stevel int s = opstack; 2661 0 stevel 2662 0 stevel primary(); 2663 0 stevel while (op = find_op(token, mulops)) { 2664 0 stevel next(); 2665 0 stevel primary(); 2666 0 stevel checkstack(s + 2); 2667 0 stevel emitop(op); 2668 0 stevel opstack--; 2669 0 stevel } 2670 0 stevel } 2671 0 stevel 2672 0 stevel static void 2673 0 stevel expr_add() 2674 0 stevel { 2675 0 stevel int op, s = opstack; 2676 0 stevel 2677 0 stevel expr_mul(); 2678 0 stevel while (op = find_op(token, addops)) { 2679 0 stevel next(); 2680 0 stevel expr_mul(); 2681 0 stevel checkstack(s + 2); 2682 0 stevel emitop(op); 2683 0 stevel opstack--; 2684 0 stevel } 2685 0 stevel } 2686 0 stevel 2687 0 stevel static void 2688 0 stevel expr_compare() 2689 0 stevel { 2690 0 stevel int op, s = opstack; 2691 0 stevel 2692 0 stevel expr_add(); 2693 0 stevel while (op = find_op(token, compareops)) { 2694 0 stevel next(); 2695 0 stevel expr_add(); 2696 0 stevel checkstack(s + 2); 2697 0 stevel emitop(op); 2698 0 stevel opstack--; 2699 0 stevel } 2700 0 stevel } 2701 0 stevel 2702 0 stevel /* 2703 0 stevel * Alternation ("and") is difficult because 2704 0 stevel * an implied "and" is acknowledge between 2705 0 stevel * two adjacent primaries. Just keep calling 2706 0 stevel * the lower-level expression routine until 2707 0 stevel * no value is added to the opstack. 2708 0 stevel */ 2709 0 stevel static void 2710 0 stevel alternation() 2711 0 stevel { 2712 0 stevel int m = 0; 2713 0 stevel int s = opstack; 2714 0 stevel 2715 0 stevel expr_compare(); 2716 0 stevel checkstack(s + 1); 2717 0 stevel for (;;) { 2718 0 stevel if (EQ("and")) 2719 0 stevel next(); 2720 0 stevel emitop(OP_BRFL); 2721 0 stevel m = chain(m); 2722 0 stevel expr_compare(); 2723 0 stevel if (opstack != s + 2) 2724 0 stevel break; 2725 0 stevel opstack--; 2726 0 stevel } 2727 0 stevel unemit(2); 2728 0 stevel resolve_chain(m); 2729 0 stevel } 2730 0 stevel 2731 0 stevel static void 2732 0 stevel expression() 2733 0 stevel { 2734 0 stevel int m = 0; 2735 0 stevel int s = opstack; 2736 0 stevel 2737 0 stevel alternation(); 2738 0 stevel while (EQ("or") || EQ(",")) { 2739 0 stevel emitop(OP_BRTR); 2740 0 stevel m = chain(m); 2741 0 stevel next(); 2742 0 stevel alternation(); 2743 0 stevel checkstack(s + 2); 2744 0 stevel opstack--; 2745 0 stevel } 2746 0 stevel resolve_chain(m); 2747 0 stevel } 2748 0 stevel 2749 0 stevel /* 2750 0 stevel * Take n args from the argv list 2751 0 stevel * and concatenate them into a single string. 2752 0 stevel */ 2753 0 stevel char * 2754 0 stevel concat_args(char **argv, int argc) 2755 0 stevel { 2756 0 stevel int i, len; 2757 0 stevel char *str, *p; 2758 0 stevel 2759 0 stevel /* First add the lengths of all the strings */ 2760 0 stevel len = 0; 2761 0 stevel for (i = 0; i < argc; i++) 2762 0 stevel len += strlen(argv[i]) + 1; 2763 0 stevel 2764 0 stevel /* allocate the big string */ 2765 0 stevel str = (char *)malloc(len); 2766 0 stevel if (str == NULL) 2767 0 stevel pr_err("no mem"); 2768 0 stevel 2769 0 stevel p = str; 2770 0 stevel 2771 0 stevel /* 2772 0 stevel * Concat the strings into the big 2773 0 stevel * string using a space as separator 2774 0 stevel */ 2775 0 stevel for (i = 0; i < argc; i++) { 2776 0 stevel strcpy(p, argv[i]); 2777 0 stevel p += strlen(p); 2778 0 stevel *p++ = ' '; 2779 0 stevel } 2780 0 stevel *--p = '\0'; 2781 0 stevel 2782 0 stevel return (str); 2783 0 stevel } 2784 0 stevel 2785 0 stevel /* 2786 0 stevel * Take the expression in the string "expr" 2787 0 stevel * and compile it into the code array. 2788 0 stevel * Print the generated code if the print 2789 0 stevel * arg is set. 2790 0 stevel */ 2791 0 stevel void 2792 0 stevel compile(char *expr, int print) 2793 0 stevel { 2794 0 stevel expr = strdup(expr); 2795 0 stevel if (expr == NULL) 2796 0 stevel pr_err("no mem"); 2797 0 stevel curr_op = oplist; 2798 0 stevel tkp = expr; 2799 0 stevel dir = ANY; 2800 0 stevel 2801 0 stevel next(); 2802 0 stevel if (tokentype != EOL) 2803 0 stevel expression(); 2804 0 stevel emitop(OP_STOP); 2805 0 stevel if (tokentype != EOL) 2806 0 stevel pr_err("invalid expression"); 2807 0 stevel optimize(oplist); 2808 0 stevel if (print) 2809 0 stevel codeprint(); 2810 0 stevel } 2811 0 stevel 2812 0 stevel /* 2813 0 stevel * Lookup hostname in the arp cache. 2814 0 stevel */ 2815 0 stevel boolean_t 2816 0 stevel arp_for_ether(char *hostname, struct ether_addr *ep) 2817 0 stevel { 2818 0 stevel struct arpreq ar; 2819 0 stevel struct hostent *hp; 2820 0 stevel struct sockaddr_in *sin; 2821 0 stevel int error_num; 2822 0 stevel int s; 2823 0 stevel 2824 0 stevel memset(&ar, 0, sizeof (ar)); 2825 0 stevel sin = (struct sockaddr_in *)&ar.arp_pa; 2826 0 stevel sin->sin_family = AF_INET; 2827 0 stevel hp = getipnodebyname(hostname, AF_INET, 0, &error_num); 2828 0 stevel if (hp == NULL) { 2829 0 stevel return (B_FALSE); 2830 0 stevel } 2831 0 stevel memcpy(&sin->sin_addr, hp->h_addr, sizeof (sin->sin_addr)); 2832 0 stevel s = socket(AF_INET, SOCK_DGRAM, 0); 2833 0 stevel if (s < 0) { 2834 0 stevel return (B_FALSE); 2835 0 stevel } 2836 0 stevel if (ioctl(s, SIOCGARP, &ar) < 0) { 2837 0 stevel close(s); 2838 0 stevel return (B_FALSE); 2839 0 stevel } 2840 0 stevel close(s); 2841 0 stevel memcpy(ep->ether_addr_octet, ar.arp_ha.sa_data, sizeof (*ep)); 2842 0 stevel return (B_TRUE); 2843 0 stevel } 2844