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