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