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