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