xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c (revision 041bde0a02e9359336a030297bb507ce6bda43f1)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stddef.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <sys/isa_defs.h>
35 
36 #include <sys/socket.h>
37 #include <sys/vlan.h>
38 #include <net/if.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/if_ether.h>
43 #include <netinet/tcp.h>
44 #include <netinet/udp.h>
45 #include <inet/ip.h>
46 #include <inet/ip6.h>
47 #include <netdb.h>
48 #include <rpc/rpc.h>
49 #include <setjmp.h>
50 
51 #include <sys/pfmod.h>
52 #include "snoop.h"
53 #include "snoop_vlan.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 typedef struct {
86 	int	transport_protocol;
87 	int	network_protocol;
88 	/*
89 	 * offset is the offset in bytes from the beginning
90 	 * of the network protocol header to where the transport
91 	 * protocol type is.
92 	 */
93 	int	offset;
94 } transport_table_t;
95 
96 typedef struct network_table {
97 	char *nmt_name;
98 	int nmt_val;
99 } network_table_t;
100 
101 static network_table_t ether_network_mapping_table[] = {
102 	{ "pup", ETHERTYPE_PUP },
103 	{ "ip", ETHERTYPE_IP },
104 	{ "arp", ETHERTYPE_ARP },
105 	{ "revarp", ETHERTYPE_REVARP },
106 	{ "at", ETHERTYPE_AT },
107 	{ "aarp", ETHERTYPE_AARP },
108 	{ "vlan", ETHERTYPE_VLAN },
109 	{ "ip6", ETHERTYPE_IPV6 },
110 	{ "slow", ETHERTYPE_SLOW },
111 	{ "ppoed", ETHERTYPE_PPPOED },
112 	{ "ppoes", ETHERTYPE_PPPOES },
113 	{ "NULL", -1 }
114 
115 };
116 
117 static network_table_t ib_network_mapping_table[] = {
118 	{ "pup", ETHERTYPE_PUP },
119 	{ "ip", ETHERTYPE_IP },
120 	{ "arp", ETHERTYPE_ARP },
121 	{ "revarp", ETHERTYPE_REVARP },
122 	{ "at", ETHERTYPE_AT },
123 	{ "aarp", ETHERTYPE_AARP },
124 	{ "vlan", ETHERTYPE_VLAN },
125 	{ "ip6", ETHERTYPE_IPV6 },
126 	{ "slow", ETHERTYPE_SLOW },
127 	{ "ppoed", ETHERTYPE_PPPOED },
128 	{ "ppoes", ETHERTYPE_PPPOES },
129 	{ "NULL", -1 }
130 
131 };
132 
133 static network_table_t ipnet_network_mapping_table[] = {
134 	{ "ip", (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION) },
135 	{ "ip6", (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION) },
136 	{ "NULL", -1 }
137 
138 };
139 
140 static transport_table_t ether_transport_mapping_table[] = {
141 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
142 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
143 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
144 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
145 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
146 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
147 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
148 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
149 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
150 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
151 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
152 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
153 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
154 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
155 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
156 	{-1, 0, 0}	/* must be the final entry */
157 };
158 
159 static transport_table_t ipnet_transport_mapping_table[] = {
160 	{IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
161 	    IPV4_TYPE_HEADER_OFFSET},
162 	{IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
163 	    IPV6_TYPE_HEADER_OFFSET},
164 	{IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
165 	    IPV4_TYPE_HEADER_OFFSET},
166 	{IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
167 	    IPV6_TYPE_HEADER_OFFSET},
168 	{IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
169 	    IPV4_TYPE_HEADER_OFFSET},
170 	{IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
171 	    IPV6_TYPE_HEADER_OFFSET},
172 	{IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
173 	    IPV4_TYPE_HEADER_OFFSET},
174 	{IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
175 	    IPV6_TYPE_HEADER_OFFSET},
176 	{IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
177 	    IPV4_TYPE_HEADER_OFFSET},
178 	{IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
179 	    IPV6_TYPE_HEADER_OFFSET},
180 	{IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
181 	    IPV4_TYPE_HEADER_OFFSET},
182 	{IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
183 	    IPV4_TYPE_HEADER_OFFSET},
184 	{IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
185 	    IPV6_TYPE_HEADER_OFFSET},
186 	{IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
187 	    IPV4_TYPE_HEADER_OFFSET},
188 	{IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
189 	    IPV6_TYPE_HEADER_OFFSET},
190 	{-1, 0, 0}	/* must be the final entry */
191 };
192 
193 static transport_table_t ib_transport_mapping_table[] = {
194 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
195 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
196 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
197 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
198 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
199 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
200 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
201 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
202 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
203 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
204 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
205 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
206 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
207 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
208 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
209 	{-1, 0, 0}	/* must be the final entry */
210 };
211 
212 typedef struct datalink {
213 	uint_t			dl_type;
214 	void			(*dl_match_fn)(uint_t datatype);
215 	transport_table_t	*dl_trans_map_tbl;
216 	network_table_t		*dl_net_map_tbl;
217 	int			dl_link_header_len;
218 	int			dl_link_type_offset;
219 	int			dl_link_dest_offset;
220 	int			dl_link_src_offset;
221 	int			dl_link_addr_len;
222 } datalink_t;
223 
224 datalink_t	dl;
225 
226 #define	IPV4_SRCADDR_OFFSET	(dl.dl_link_header_len + 12)
227 #define	IPV4_DSTADDR_OFFSET	(dl.dl_link_header_len + 16)
228 #define	IPV6_SRCADDR_OFFSET	(dl.dl_link_header_len + 8)
229 #define	IPV6_DSTADDR_OFFSET	(dl.dl_link_header_len + 24)
230 
231 #define	IPNET_SRCZONE_OFFSET 8
232 #define	IPNET_DSTZONE_OFFSET 16
233 
234 static int inBrace = 0, inBraceOR = 0;
235 static int foundOR = 0;
236 char *tkp, *sav_tkp;
237 char *token;
238 enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
239 	ADDR_IP6 } tokentype;
240 uint_t tokenval;
241 
242 enum direction { ANY, TO, FROM };
243 enum direction dir;
244 
245 extern void next();
246 
247 static void pf_expression();
248 static void pf_check_vlan_tag(uint_t offset);
249 static void pf_clear_offset_register();
250 static void pf_emit_load_offset(uint_t offset);
251 static void pf_match_ethertype(uint_t ethertype);
252 static void pf_match_ipnettype(uint_t type);
253 static void pf_match_ibtype(uint_t type);
254 static void pf_check_transport_protocol(uint_t transport_protocol);
255 static void pf_compare_value_mask_generic(int offset, uint_t len,
256     uint_t val, int mask, uint_t op);
257 static void pf_matchfn(const char *name);
258 
259 /*
260  * This pointer points to the function that last generated
261  * instructions to change the offset register.  It's used
262  * for comparisons to see if we need to issue more instructions
263  * to change the register.
264  *
265  * It's initialized to pf_clear_offset_register because the offset
266  * register in pfmod is initialized to zero, similar to the state
267  * it would be in after executing the instructions issued by
268  * pf_clear_offset_register.
269  */
270 static void *last_offset_operation = (void*)pf_clear_offset_register;
271 
272 static void
273 pf_emit(x)
274 	ushort_t x;
275 {
276 	if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1])
277 		longjmp(env, 1);
278 	*pfp++ = x;
279 }
280 
281 static void
282 pf_codeprint(code, len)
283 	ushort_t *code;
284 	int len;
285 {
286 	ushort_t *pc;
287 	ushort_t *plast = code + len;
288 	int op, action;
289 
290 	if (len > 0) {
291 		printf("Kernel Filter:\n");
292 	}
293 
294 	for (pc = code; pc < plast; pc++) {
295 		printf("\t%3d: ", pc - code);
296 
297 		op = *pc & 0xfc00;	/* high 10 bits */
298 		action = *pc & 0x3ff;	/* low   6 bits */
299 
300 		switch (action) {
301 		case ENF_PUSHLIT:
302 			printf("PUSHLIT ");
303 			break;
304 		case ENF_PUSHZERO:
305 			printf("PUSHZERO ");
306 			break;
307 #ifdef ENF_PUSHONE
308 		case ENF_PUSHONE:
309 			printf("PUSHONE ");
310 			break;
311 #endif
312 #ifdef ENF_PUSHFFFF
313 		case ENF_PUSHFFFF:
314 			printf("PUSHFFFF ");
315 			break;
316 #endif
317 #ifdef ENF_PUSHFF00
318 		case ENF_PUSHFF00:
319 			printf("PUSHFF00 ");
320 			break;
321 #endif
322 #ifdef ENF_PUSH00FF
323 		case ENF_PUSH00FF:
324 			printf("PUSH00FF ");
325 			break;
326 #endif
327 		case ENF_LOAD_OFFSET:
328 			printf("LOAD_OFFSET ");
329 			break;
330 		case ENF_BRTR:
331 			printf("BRTR ");
332 			break;
333 		case ENF_BRFL:
334 			printf("BRFL ");
335 			break;
336 		case ENF_POP:
337 			printf("POP ");
338 			break;
339 		}
340 
341 		if (action >= ENF_PUSHWORD)
342 			printf("PUSHWORD %d ", action - ENF_PUSHWORD);
343 
344 		switch (op) {
345 		case ENF_EQ:
346 			printf("EQ ");
347 			break;
348 		case ENF_LT:
349 			printf("LT ");
350 			break;
351 		case ENF_LE:
352 			printf("LE ");
353 			break;
354 		case ENF_GT:
355 			printf("GT ");
356 			break;
357 		case ENF_GE:
358 			printf("GE ");
359 			break;
360 		case ENF_AND:
361 			printf("AND ");
362 			break;
363 		case ENF_OR:
364 			printf("OR ");
365 			break;
366 		case ENF_XOR:
367 			printf("XOR ");
368 			break;
369 		case ENF_COR:
370 			printf("COR ");
371 			break;
372 		case ENF_CAND:
373 			printf("CAND ");
374 			break;
375 		case ENF_CNOR:
376 			printf("CNOR ");
377 			break;
378 		case ENF_CNAND:
379 			printf("CNAND ");
380 			break;
381 		case ENF_NEQ:
382 			printf("NEQ ");
383 			break;
384 		}
385 
386 		if (action == ENF_PUSHLIT ||
387 		    action == ENF_LOAD_OFFSET ||
388 		    action == ENF_BRTR ||
389 		    action == ENF_BRFL) {
390 			pc++;
391 			printf("\n\t%3d:   %d (0x%04x)", pc - code, *pc, *pc);
392 		}
393 
394 		printf("\n");
395 	}
396 }
397 
398 /*
399  * Emit packet filter code to check a
400  * field in the packet for a particular value.
401  * Need different code for each field size.
402  * Since the pf can only compare 16 bit quantities
403  * we have to use masking to compare byte values.
404  * Long word (32 bit) quantities have to be done
405  * as two 16 bit comparisons.
406  */
407 static void
408 pf_compare_value(int offset, uint_t len, uint_t val)
409 {
410 	/*
411 	 * If the property being filtered on is absent in the media
412 	 * packet, error out.
413 	 */
414 	if (offset == -1)
415 		pr_err("filter option unsupported on media");
416 
417 	switch (len) {
418 	case 1:
419 		pf_emit(ENF_PUSHWORD + offset / 2);
420 #if defined(_BIG_ENDIAN)
421 		if (offset % 2)
422 #else
423 		if (!(offset % 2))
424 #endif
425 		{
426 #ifdef ENF_PUSH00FF
427 			pf_emit(ENF_PUSH00FF | ENF_AND);
428 #else
429 			pf_emit(ENF_PUSHLIT | ENF_AND);
430 			pf_emit(0x00FF);
431 #endif
432 			pf_emit(ENF_PUSHLIT | ENF_EQ);
433 			pf_emit(val);
434 		} else {
435 #ifdef ENF_PUSHFF00
436 			pf_emit(ENF_PUSHFF00 | ENF_AND);
437 #else
438 			pf_emit(ENF_PUSHLIT | ENF_AND);
439 			pf_emit(0xFF00);
440 #endif
441 			pf_emit(ENF_PUSHLIT | ENF_EQ);
442 			pf_emit(val << 8);
443 		}
444 		break;
445 
446 	case 2:
447 		pf_emit(ENF_PUSHWORD + offset / 2);
448 		pf_emit(ENF_PUSHLIT | ENF_EQ);
449 		pf_emit((ushort_t)val);
450 		break;
451 
452 	case 4:
453 		pf_emit(ENF_PUSHWORD + offset / 2);
454 		pf_emit(ENF_PUSHLIT | ENF_EQ);
455 #if defined(_BIG_ENDIAN)
456 		pf_emit(val >> 16);
457 #elif defined(_LITTLE_ENDIAN)
458 		pf_emit(val & 0xffff);
459 #else
460 #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined
461 #endif
462 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
463 		pf_emit(ENF_PUSHLIT | ENF_EQ);
464 #if defined(_BIG_ENDIAN)
465 		pf_emit(val & 0xffff);
466 #else
467 		pf_emit(val >> 16);
468 #endif
469 		pf_emit(ENF_AND);
470 		break;
471 	}
472 }
473 
474 /*
475  * same as pf_compare_value, but only for emiting code to
476  * compare ipv6 addresses.
477  */
478 static void
479 pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
480 {
481 	int i;
482 
483 	for (i = 0; i < len; i += 2) {
484 		pf_emit(ENF_PUSHWORD + offset / 2 + i / 2);
485 		pf_emit(ENF_PUSHLIT | ENF_EQ);
486 		pf_emit(*(uint16_t *)&val.s6_addr[i]);
487 		if (i != 0)
488 			pf_emit(ENF_AND);
489 	}
490 }
491 
492 
493 /*
494  * Same as above except mask the field value
495  * before doing the comparison.  The comparison checks
496  * to make sure the values are equal.
497  */
498 static void
499 pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
500 {
501 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ);
502 }
503 
504 /*
505  * Same as above except the values are compared to see if they are not
506  * equal.
507  */
508 static void
509 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask)
510 {
511 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ);
512 }
513 
514 /*
515  * Similar to pf_compare_value.
516  *
517  * This is the utility function that does the actual work to compare
518  * two values using a mask.  The comparison operation is passed into
519  * the function.
520  */
521 static void
522 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask,
523     uint_t op)
524 {
525 	/*
526 	 * If the property being filtered on is absent in the media
527 	 * packet, error out.
528 	 */
529 	if (offset == -1)
530 		pr_err("filter option unsupported on media");
531 
532 	switch (len) {
533 	case 1:
534 		pf_emit(ENF_PUSHWORD + offset / 2);
535 #if defined(_BIG_ENDIAN)
536 		if (offset % 2)
537 #else
538 		if (!offset % 2)
539 #endif
540 		{
541 			pf_emit(ENF_PUSHLIT | ENF_AND);
542 			pf_emit(mask & 0x00ff);
543 			pf_emit(ENF_PUSHLIT | op);
544 			pf_emit(val);
545 		} else {
546 			pf_emit(ENF_PUSHLIT | ENF_AND);
547 			pf_emit((mask << 8) & 0xff00);
548 			pf_emit(ENF_PUSHLIT | op);
549 			pf_emit(val << 8);
550 		}
551 		break;
552 
553 	case 2:
554 		pf_emit(ENF_PUSHWORD + offset / 2);
555 		pf_emit(ENF_PUSHLIT | ENF_AND);
556 		pf_emit(htons((ushort_t)mask));
557 		pf_emit(ENF_PUSHLIT | op);
558 		pf_emit(htons((ushort_t)val));
559 		break;
560 
561 	case 4:
562 		pf_emit(ENF_PUSHWORD + offset / 2);
563 		pf_emit(ENF_PUSHLIT | ENF_AND);
564 		pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
565 		pf_emit(ENF_PUSHLIT | op);
566 		pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
567 
568 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
569 		pf_emit(ENF_PUSHLIT | ENF_AND);
570 		pf_emit(htons((ushort_t)(mask & 0xffff)));
571 		pf_emit(ENF_PUSHLIT | op);
572 		pf_emit(htons((ushort_t)(val & 0xffff)));
573 
574 		pf_emit(ENF_AND);
575 		break;
576 	}
577 }
578 
579 /*
580  * Like pf_compare_value() but compare on a 64-bit zoneid value.
581  * The argument val passed in is in network byte order.
582  */
583 static void
584 pf_compare_zoneid(int offset, uint64_t val)
585 {
586 	int i;
587 
588 	for (i = 0; i < sizeof (uint64_t) / 2; i ++) {
589 		pf_emit(ENF_PUSHWORD + offset / 2 + i);
590 		pf_emit(ENF_PUSHLIT | ENF_EQ);
591 		pf_emit(((uint16_t *)&val)[i]);
592 		if (i != 0)
593 			pf_emit(ENF_AND);
594 	}
595 }
596 
597 /*
598  * Generate pf code to match an IPv4 or IPv6 address.
599  */
600 static void
601 pf_ipaddr_match(which, hostname, inet_type)
602 	enum direction which;
603 	char *hostname;
604 	int inet_type;
605 {
606 	bool_t found_host;
607 	uint_t *addr4ptr;
608 	uint_t addr4;
609 	struct in6_addr *addr6ptr;
610 	int h_addr_index;
611 	struct hostent *hp = NULL;
612 	int error_num = 0;
613 	boolean_t first = B_TRUE;
614 	int pass = 0;
615 	int i;
616 
617 	/*
618 	 * The addr4offset and addr6offset variables simplify the code which
619 	 * generates the address comparison filter.  With these two variables,
620 	 * duplicate code need not exist for the TO and FROM case.
621 	 * A value of -1 describes the ANY case (TO and FROM).
622 	 */
623 	int addr4offset;
624 	int addr6offset;
625 
626 	found_host = 0;
627 
628 	if (tokentype == ADDR_IP) {
629 		hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
630 		if (hp == NULL) {
631 			if (error_num == TRY_AGAIN) {
632 				pr_err("could not resolve %s (try again later)",
633 				    hostname);
634 			} else {
635 				pr_err("could not resolve %s", hostname);
636 			}
637 		}
638 		inet_type = IPV4_ONLY;
639 	} else if (tokentype == ADDR_IP6) {
640 		hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
641 		if (hp == NULL) {
642 			if (error_num == TRY_AGAIN) {
643 				pr_err("could not resolve %s (try again later)",
644 				    hostname);
645 			} else {
646 				pr_err("could not resolve %s", hostname);
647 			}
648 		}
649 		inet_type = IPV6_ONLY;
650 	} else if (tokentype == ALPHA) {
651 		/* Some hostname i.e. tokentype is ALPHA */
652 		switch (inet_type) {
653 		case IPV4_ONLY:
654 			/* Only IPv4 address is needed */
655 			hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
656 			if (hp != NULL) {
657 				found_host = 1;
658 			}
659 			break;
660 		case IPV6_ONLY:
661 			/* Only IPv6 address is needed */
662 			hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
663 			if (hp != NULL) {
664 				found_host = 1;
665 			}
666 			break;
667 		case IPV4_AND_IPV6:
668 			/* Both IPv4 and IPv6 are needed */
669 			hp = getipnodebyname(hostname, AF_INET6,
670 			    AI_ALL | AI_V4MAPPED, &error_num);
671 			if (hp != NULL) {
672 				found_host = 1;
673 			}
674 			break;
675 		default:
676 			found_host = 0;
677 		}
678 
679 		if (!found_host) {
680 			if (error_num == TRY_AGAIN) {
681 				pr_err("could not resolve %s (try again later)",
682 				    hostname);
683 			} else {
684 				pr_err("could not resolve %s", hostname);
685 			}
686 		}
687 	} else {
688 		pr_err("unknown token type: %s", hostname);
689 	}
690 
691 	switch (which) {
692 	case TO:
693 		addr4offset = IPV4_DSTADDR_OFFSET;
694 		addr6offset = IPV6_DSTADDR_OFFSET;
695 		break;
696 	case FROM:
697 		addr4offset = IPV4_SRCADDR_OFFSET;
698 		addr6offset = IPV6_SRCADDR_OFFSET;
699 		break;
700 	case ANY:
701 		addr4offset = -1;
702 		addr6offset = -1;
703 		break;
704 	}
705 
706 	if (hp != NULL && hp->h_addrtype == AF_INET) {
707 		pf_matchfn("ip");
708 		if (dl.dl_type == DL_ETHER)
709 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
710 		h_addr_index = 0;
711 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
712 		while (addr4ptr != NULL) {
713 			if (addr4offset == -1) {
714 				pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
715 				    *addr4ptr);
716 				if (h_addr_index != 0)
717 					pf_emit(ENF_OR);
718 				pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
719 				    *addr4ptr);
720 				pf_emit(ENF_OR);
721 			} else {
722 				pf_compare_value(addr4offset, 4,
723 				    *addr4ptr);
724 				if (h_addr_index != 0)
725 					pf_emit(ENF_OR);
726 			}
727 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
728 		}
729 		pf_emit(ENF_AND);
730 	} else {
731 		/* first pass: IPv4 addresses */
732 		h_addr_index = 0;
733 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
734 		first = B_TRUE;
735 		while (addr6ptr != NULL) {
736 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
737 				if (first) {
738 					pf_matchfn("ip");
739 					if (dl.dl_type == DL_ETHER) {
740 						pf_check_vlan_tag(
741 						    ENCAP_ETHERTYPE_OFF/2);
742 					}
743 					pass++;
744 				}
745 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
746 				    (struct in_addr *)&addr4);
747 				if (addr4offset == -1) {
748 					pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
749 					    addr4);
750 					if (!first)
751 						pf_emit(ENF_OR);
752 					pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
753 					    addr4);
754 					pf_emit(ENF_OR);
755 				} else {
756 					pf_compare_value(addr4offset, 4,
757 					    addr4);
758 					if (!first)
759 						pf_emit(ENF_OR);
760 				}
761 				if (first)
762 					first = B_FALSE;
763 			}
764 			addr6ptr = (struct in6_addr *)
765 				hp->h_addr_list[++h_addr_index];
766 		}
767 		if (!first) {
768 			pf_emit(ENF_AND);
769 		}
770 		/* second pass: IPv6 addresses */
771 		h_addr_index = 0;
772 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
773 		first = B_TRUE;
774 		while (addr6ptr != NULL) {
775 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
776 				if (first) {
777 					pf_matchfn("ip6");
778 					if (dl.dl_type == DL_ETHER) {
779 						pf_check_vlan_tag(
780 							ENCAP_ETHERTYPE_OFF/2);
781 					}
782 					pass++;
783 				}
784 				if (addr6offset == -1) {
785 					pf_compare_value_v6(IPV6_SRCADDR_OFFSET,
786 					    16, *addr6ptr);
787 					if (!first)
788 						pf_emit(ENF_OR);
789 					pf_compare_value_v6(IPV6_DSTADDR_OFFSET,
790 					    16, *addr6ptr);
791 					pf_emit(ENF_OR);
792 				} else {
793 					pf_compare_value_v6(addr6offset, 16,
794 					    *addr6ptr);
795 					if (!first)
796 						pf_emit(ENF_OR);
797 				}
798 				if (first)
799 					first = B_FALSE;
800 			}
801 			addr6ptr = (struct in6_addr *)
802 				hp->h_addr_list[++h_addr_index];
803 		}
804 		if (!first) {
805 			pf_emit(ENF_AND);
806 		}
807 		if (pass == 2) {
808 			pf_emit(ENF_OR);
809 		}
810 	}
811 
812 	if (hp != NULL) {
813 		freehostent(hp);
814 	}
815 }
816 
817 
818 static void
819 pf_compare_address(int offset, uint_t len, uchar_t *addr)
820 {
821 	uint32_t val;
822 	uint16_t sval;
823 	boolean_t didone = B_FALSE;
824 
825 	/*
826 	 * If the property being filtered on is absent in the media
827 	 * packet, error out.
828 	 */
829 	if (offset == -1)
830 		pr_err("filter option unsupported on media");
831 
832 	while (len > 0) {
833 		if (len >= 4) {
834 			(void) memcpy(&val, addr, 4);
835 			pf_compare_value(offset, 4, val);
836 			addr += 4;
837 			offset += 4;
838 			len -= 4;
839 		} else if (len >= 2) {
840 			(void) memcpy(&sval, addr, 2);
841 			pf_compare_value(offset, 2, sval);
842 			addr += 2;
843 			offset += 2;
844 			len -= 2;
845 		} else {
846 			pf_compare_value(offset++, 1, *addr++);
847 			len--;
848 		}
849 		if (didone)
850 			pf_emit(ENF_AND);
851 		didone = B_TRUE;
852 	}
853 }
854 
855 /*
856  * Compare ethernet addresses.
857  */
858 static void
859 pf_etheraddr_match(which, hostname)
860 	enum direction which;
861 	char *hostname;
862 {
863 	struct ether_addr e, *ep = NULL;
864 
865 	if (isxdigit(*hostname))
866 		ep = ether_aton(hostname);
867 	if (ep == NULL) {
868 		if (ether_hostton(hostname, &e))
869 			if (!arp_for_ether(hostname, &e))
870 				pr_err("cannot obtain ether addr for %s",
871 					hostname);
872 		ep = &e;
873 	}
874 
875 	pf_clear_offset_register();
876 
877 	switch (which) {
878 	case TO:
879 		pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
880 		    (uchar_t *)ep);
881 		break;
882 	case FROM:
883 		pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
884 		    (uchar_t *)ep);
885 		break;
886 	case ANY:
887 		pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
888 		    (uchar_t *)ep);
889 		pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
890 		    (uchar_t *)ep);
891 		pf_emit(ENF_OR);
892 		break;
893 	}
894 }
895 
896 /*
897  * Emit code to compare the network part of
898  * an IP address.
899  */
900 static void
901 pf_netaddr_match(which, netname)
902 	enum direction which;
903 	char *netname;
904 {
905 	uint_t addr;
906 	uint_t mask = 0xff000000;
907 	struct netent *np;
908 
909 	if (isdigit(*netname)) {
910 		addr = inet_network(netname);
911 	} else {
912 		np = getnetbyname(netname);
913 		if (np == NULL)
914 			pr_err("net %s not known", netname);
915 		addr = np->n_net;
916 	}
917 
918 	/*
919 	 * Left justify the address and figure
920 	 * out a mask based on the supplied address.
921 	 * Set the mask according to the number of zero
922 	 * low-order bytes.
923 	 * Note: this works only for whole octet masks.
924 	 */
925 	if (addr) {
926 		while ((addr & ~mask) != 0) {
927 			mask |= (mask >> 8);
928 		}
929 	}
930 
931 	pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
932 
933 	switch (which) {
934 	case TO:
935 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
936 		break;
937 	case FROM:
938 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
939 		break;
940 	case ANY:
941 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
942 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
943 		pf_emit(ENF_OR);
944 		break;
945 	}
946 }
947 
948 /*
949  * Emit code to match on src or destination zoneid.
950  * The zoneid passed in is in network byte order.
951  */
952 static void
953 pf_match_zone(enum direction which, uint64_t zoneid)
954 {
955 	if (dl.dl_type != DL_IPNET)
956 		pr_err("zone filter option unsupported on media");
957 
958 	switch (which) {
959 	case TO:
960 		pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
961 		break;
962 	case FROM:
963 		pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
964 		break;
965 	case ANY:
966 		pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
967 		pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
968 		pf_emit(ENF_OR);
969 		break;
970 	}
971 }
972 
973 /*
974  * A helper function to keep the code to emit instructions
975  * to change the offset register in one place.
976  *
977  * INPUTS: offset - An value representing an offset in 16-bit
978  *                  words.
979  * OUTPUTS:  If there is enough room in the storage for the
980  *           packet filtering program, instructions to load
981  *           a constant to the offset register.  Otherwise,
982  *           nothing.
983  */
984 static void
985 pf_emit_load_offset(uint_t offset)
986 {
987 	pf_emit(ENF_LOAD_OFFSET | ENF_NOP);
988 	pf_emit(offset);
989 }
990 
991 /*
992  * Clear pfmod's offset register.
993  *
994  * INPUTS:  none
995  * OUTPUTS:  Instructions to clear the offset register if
996  *           there is enough space remaining in the packet
997  *           filtering program structure's storage, and
998  *           the last thing done to the offset register was
999  *           not clearing the offset register.  Otherwise,
1000  *           nothing.
1001  */
1002 static void
1003 pf_clear_offset_register()
1004 {
1005 	if (last_offset_operation != (void*)pf_clear_offset_register) {
1006 		pf_emit_load_offset(0);
1007 		last_offset_operation = (void*)pf_clear_offset_register;
1008 	}
1009 }
1010 
1011 /*
1012  * This function will issue opcodes to check if a packet
1013  * is VLAN tagged, and if so, update the offset register
1014  * with the appropriate offset.
1015  *
1016  * Note that if the packet is not VLAN tagged, then the offset
1017  * register will be cleared.
1018  *
1019  * If the interface type is not an ethernet type, then this
1020  * function returns without doing anything.
1021  *
1022  * If the last attempt to change the offset register occured because
1023  * of a call to this function that was called with the same offset,
1024  * then we don't issue packet filtering instructions.
1025  *
1026  * INPUTS:  offset - an offset in 16 bit words.  The function
1027  *                   will set the offset register to this
1028  *                   value if the packet is VLAN tagged.
1029  * OUTPUTS:  If the conditions are met, packet filtering instructions.
1030  */
1031 static void
1032 pf_check_vlan_tag(uint_t offset)
1033 {
1034 	static uint_t last_offset = 0;
1035 
1036 	if ((interface->mac_type == DL_ETHER ||
1037 	    interface->mac_type == DL_CSMACD) &&
1038 	    (last_offset_operation != (void*)pf_check_vlan_tag ||
1039 	    last_offset != offset)) {
1040 		/*
1041 		 * First thing is to clear the offset register.
1042 		 * We don't know what state it is in, and if it
1043 		 * is not zero, then we have no idea what we load
1044 		 * when we execute ENF_PUSHWORD.
1045 		 */
1046 		pf_clear_offset_register();
1047 
1048 		/*
1049 		 * Check the ethertype.
1050 		 */
1051 		pf_compare_value(dl.dl_link_type_offset, 2,
1052 		    htons(ETHERTYPE_VLAN));
1053 
1054 		/*
1055 		 * And if it's not VLAN, don't load offset to the offset
1056 		 * register.
1057 		 */
1058 		pf_emit(ENF_BRFL | ENF_NOP);
1059 		pf_emit(3);
1060 
1061 		/*
1062 		 * Otherwise, load offset to the offset register.
1063 		 */
1064 		pf_emit_load_offset(offset);
1065 
1066 		/*
1067 		 * Now get rid of the results of the comparison,
1068 		 * we don't want the results of the comparison to affect
1069 		 * other logic in the packet filtering program.
1070 		 */
1071 		pf_emit(ENF_POP | ENF_NOP);
1072 
1073 		/*
1074 		 * Set the last operation at the end, or any time
1075 		 * after the call to pf_clear_offset because
1076 		 * pf_clear_offset uses it.
1077 		 */
1078 		last_offset_operation = (void*)pf_check_vlan_tag;
1079 		last_offset = offset;
1080 	}
1081 }
1082 
1083 /*
1084  * Utility function used to emit packet filtering code
1085  * to match an ethertype.
1086  *
1087  * INPUTS:  ethertype - The ethertype we want to check for.
1088  *                      Don't call htons on the ethertype before
1089  *                      calling this function.
1090  * OUTPUTS:  If there is sufficient storage available, packet
1091  *           filtering code to check an ethertype.  Otherwise,
1092  *           nothing.
1093  */
1094 static void
1095 pf_match_ethertype(uint_t ethertype)
1096 {
1097 	/*
1098 	 * If the user wants to filter on ethertype VLAN,
1099 	 * then clear the offset register so that the offset
1100 	 * for ENF_PUSHWORD points to the right place in the
1101 	 * packet.
1102 	 *
1103 	 * Otherwise, call pf_check_vlan_tag to set the offset
1104 	 * register such that the contents of the offset register
1105 	 * plus the argument for ENF_PUSHWORD point to the right
1106 	 * part of the packet, whether or not the packet is VLAN
1107 	 * tagged.  We call pf_check_vlan_tag with an offset of
1108 	 * two words because if the packet is VLAN tagged, we have
1109 	 * to move past the ethertype in the ethernet header, and
1110 	 * past the lower two octets of the VLAN header to get to
1111 	 * the ethertype in the VLAN header.
1112 	 */
1113 	if (ethertype == ETHERTYPE_VLAN)
1114 		pf_clear_offset_register();
1115 	else
1116 		pf_check_vlan_tag(2);
1117 
1118 	pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype));
1119 }
1120 
1121 static void
1122 pf_match_ipnettype(uint_t type)
1123 {
1124 	pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1125 }
1126 
1127 static void
1128 pf_match_ibtype(uint_t type)
1129 {
1130 	pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1131 }
1132 
1133 /*
1134  * This function uses the table above to generate a
1135  * piece of a packet filtering program to check a transport
1136  * protocol type.
1137  *
1138  * INPUTS:  tranport_protocol - the transport protocol we're
1139  *                              interested in.
1140  * OUTPUTS:  If there is sufficient storage, then packet filtering
1141  *           code to check a transport protocol type.  Otherwise,
1142  *           nothing.
1143  */
1144 static void
1145 pf_check_transport_protocol(uint_t transport_protocol)
1146 {
1147 	int i;
1148 	uint_t number_of_matches = 0;
1149 
1150 	for (i = 0; dl.dl_trans_map_tbl[i].transport_protocol != -1; i++) {
1151 		if (transport_protocol ==
1152 		    (uint_t)dl.dl_trans_map_tbl[i].transport_protocol) {
1153 			number_of_matches++;
1154 			dl.dl_match_fn(dl.dl_trans_map_tbl[i].network_protocol);
1155 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1156 			pf_compare_value(dl.dl_trans_map_tbl[i].offset +
1157 			    dl.dl_link_header_len, 1,
1158 			    transport_protocol);
1159 			pf_emit(ENF_AND);
1160 			if (number_of_matches > 1) {
1161 				/*
1162 				 * Since we have two or more matches, in
1163 				 * order to have a correct and complete
1164 				 * program we need to OR the result of
1165 				 * each block of comparisons together.
1166 				 */
1167 				pf_emit(ENF_OR);
1168 			}
1169 		}
1170 	}
1171 }
1172 
1173 static void
1174 pf_matchfn(const char *proto)
1175 {
1176 	int i;
1177 
1178 	for (i = 0; dl.dl_net_map_tbl[i].nmt_val != -1; i++) {
1179 		if (strcmp(proto, dl.dl_net_map_tbl[i].nmt_name) == 0) {
1180 			dl.dl_match_fn(dl.dl_net_map_tbl[i].nmt_val);
1181 			break;
1182 		}
1183 	}
1184 }
1185 
1186 static void
1187 pf_primary()
1188 {
1189 	for (;;) {
1190 		if (tokentype == FIELD)
1191 			break;
1192 
1193 		if (EQ("ip")) {
1194 			pf_matchfn("ip");
1195 			opstack++;
1196 			next();
1197 			break;
1198 		}
1199 
1200 		if (EQ("ip6")) {
1201 			pf_matchfn("ip6");
1202 			opstack++;
1203 			next();
1204 			break;
1205 		}
1206 
1207 		if (EQ("pppoe")) {
1208 			pf_matchfn("pppoe");
1209 			pf_match_ethertype(ETHERTYPE_PPPOES);
1210 			pf_emit(ENF_OR);
1211 			opstack++;
1212 			next();
1213 			break;
1214 		}
1215 
1216 		if (EQ("pppoed")) {
1217 			pf_matchfn("pppoed");
1218 			opstack++;
1219 			next();
1220 			break;
1221 		}
1222 
1223 		if (EQ("pppoes")) {
1224 			pf_matchfn("pppoes");
1225 			opstack++;
1226 			next();
1227 			break;
1228 		}
1229 
1230 		if (EQ("arp")) {
1231 			pf_matchfn("arp");
1232 			opstack++;
1233 			next();
1234 			break;
1235 		}
1236 
1237 		if (EQ("vlan")) {
1238 			pf_matchfn("vlan");
1239 			pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2,
1240 			    0, VLAN_ID_MASK);
1241 			pf_emit(ENF_AND);
1242 			opstack++;
1243 			next();
1244 			break;
1245 		}
1246 
1247 		if (EQ("vlan-id")) {
1248 			next();
1249 			if (tokentype != NUMBER)
1250 				pr_err("VLAN ID expected");
1251 			pf_matchfn("vlan-id");
1252 			pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
1253 			    VLAN_ID_MASK);
1254 			pf_emit(ENF_AND);
1255 			opstack++;
1256 			next();
1257 			break;
1258 		}
1259 
1260 		if (EQ("rarp")) {
1261 			pf_matchfn("rarp");
1262 			opstack++;
1263 			next();
1264 			break;
1265 		}
1266 
1267 		if (EQ("tcp")) {
1268 			pf_check_transport_protocol(IPPROTO_TCP);
1269 			opstack++;
1270 			next();
1271 			break;
1272 		}
1273 
1274 		if (EQ("udp")) {
1275 			pf_check_transport_protocol(IPPROTO_UDP);
1276 			opstack++;
1277 			next();
1278 			break;
1279 		}
1280 
1281 		if (EQ("ospf")) {
1282 			pf_check_transport_protocol(IPPROTO_OSPF);
1283 			opstack++;
1284 			next();
1285 			break;
1286 		}
1287 
1288 
1289 		if (EQ("sctp")) {
1290 			pf_check_transport_protocol(IPPROTO_SCTP);
1291 			opstack++;
1292 			next();
1293 			break;
1294 		}
1295 
1296 		if (EQ("icmp")) {
1297 			pf_check_transport_protocol(IPPROTO_ICMP);
1298 			opstack++;
1299 			next();
1300 			break;
1301 		}
1302 
1303 		if (EQ("icmp6")) {
1304 			pf_check_transport_protocol(IPPROTO_ICMPV6);
1305 			opstack++;
1306 			next();
1307 			break;
1308 		}
1309 
1310 		if (EQ("ip-in-ip")) {
1311 			pf_check_transport_protocol(IPPROTO_ENCAP);
1312 			opstack++;
1313 			next();
1314 			break;
1315 		}
1316 
1317 		if (EQ("esp")) {
1318 			pf_check_transport_protocol(IPPROTO_ESP);
1319 			opstack++;
1320 			next();
1321 			break;
1322 		}
1323 
1324 		if (EQ("ah")) {
1325 			pf_check_transport_protocol(IPPROTO_AH);
1326 			opstack++;
1327 			next();
1328 			break;
1329 		}
1330 
1331 		if (EQ("(")) {
1332 			inBrace++;
1333 			next();
1334 			pf_expression();
1335 			if (EQ(")")) {
1336 				if (inBrace)
1337 					inBraceOR--;
1338 				inBrace--;
1339 				next();
1340 			}
1341 			break;
1342 		}
1343 
1344 		if (EQ("to") || EQ("dst")) {
1345 			dir = TO;
1346 			next();
1347 			continue;
1348 		}
1349 
1350 		if (EQ("from") || EQ("src")) {
1351 			dir = FROM;
1352 			next();
1353 			continue;
1354 		}
1355 
1356 		if (EQ("ether")) {
1357 			eaddr = 1;
1358 			next();
1359 			continue;
1360 		}
1361 
1362 		if (EQ("inet")) {
1363 			next();
1364 			if (EQ("host"))
1365 				next();
1366 			if (tokentype != ALPHA && tokentype != ADDR_IP)
1367 				pr_err("host/IPv4 addr expected after inet");
1368 			pf_ipaddr_match(dir, token, IPV4_ONLY);
1369 			opstack++;
1370 			next();
1371 			break;
1372 		}
1373 
1374 		if (EQ("inet6")) {
1375 			next();
1376 			if (EQ("host"))
1377 				next();
1378 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
1379 				pr_err("host/IPv6 addr expected after inet6");
1380 			pf_ipaddr_match(dir, token, IPV6_ONLY);
1381 			opstack++;
1382 			next();
1383 			break;
1384 		}
1385 
1386 		if (EQ("proto")) {
1387 			next();
1388 			if (tokentype != NUMBER)
1389 				pr_err("IP proto type expected");
1390 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1391 			pf_compare_value(
1392 			    IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1,
1393 			    tokenval);
1394 			opstack++;
1395 			next();
1396 			break;
1397 		}
1398 
1399 		if (EQ("broadcast")) {
1400 			pf_clear_offset_register();
1401 			pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff);
1402 			opstack++;
1403 			next();
1404 			break;
1405 		}
1406 
1407 		if (EQ("multicast")) {
1408 			pf_clear_offset_register();
1409 			pf_compare_value_mask(
1410 			    dl.dl_link_dest_offset, 1, 0x01, 0x01);
1411 			opstack++;
1412 			next();
1413 			break;
1414 		}
1415 
1416 		if (EQ("ethertype")) {
1417 			next();
1418 			if (tokentype != NUMBER)
1419 				pr_err("ether type expected");
1420 			pf_match_ethertype(tokenval);
1421 			opstack++;
1422 			next();
1423 			break;
1424 		}
1425 
1426 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
1427 			if (EQ("dstnet"))
1428 				dir = TO;
1429 			else if (EQ("srcnet"))
1430 				dir = FROM;
1431 			next();
1432 			pf_netaddr_match(dir, token);
1433 			dir = ANY;
1434 			opstack++;
1435 			next();
1436 			break;
1437 		}
1438 
1439 		if (EQ("zone")) {
1440 			next();
1441 			if (tokentype != NUMBER)
1442 				pr_err("zoneid expected after inet");
1443 			pf_match_zone(dir, BE_64((uint64_t)(tokenval)));
1444 			opstack++;
1445 			next();
1446 			break;
1447 		}
1448 
1449 		/*
1450 		 * Give up on anything that's obviously
1451 		 * not a primary.
1452 		 */
1453 		if (EQ("and") || EQ("or") ||
1454 		    EQ("not") || EQ("decnet") || EQ("apple") ||
1455 		    EQ("length") || EQ("less") || EQ("greater") ||
1456 		    EQ("port") || EQ("srcport") || EQ("dstport") ||
1457 		    EQ("rpc") || EQ("gateway") || EQ("nofrag") ||
1458 		    EQ("bootp") || EQ("dhcp") || EQ("dhcp6") ||
1459 		    EQ("slp") || EQ("ldap")) {
1460 			break;
1461 		}
1462 
1463 		if (EQ("host") || EQ("between") ||
1464 		    tokentype == ALPHA || /* assume its a hostname */
1465 		    tokentype == ADDR_IP ||
1466 		    tokentype == ADDR_IP6 ||
1467 		    tokentype == ADDR_ETHER) {
1468 			if (EQ("host") || EQ("between"))
1469 				next();
1470 			if (eaddr || tokentype == ADDR_ETHER) {
1471 				pf_etheraddr_match(dir, token);
1472 			} else if (tokentype == ALPHA) {
1473 				pf_ipaddr_match(dir, token, IPV4_AND_IPV6);
1474 			} else if (tokentype == ADDR_IP) {
1475 				pf_ipaddr_match(dir, token, IPV4_ONLY);
1476 			} else {
1477 				pf_ipaddr_match(dir, token, IPV6_ONLY);
1478 			}
1479 			dir = ANY;
1480 			eaddr = 0;
1481 			opstack++;
1482 			next();
1483 			break;
1484 		}
1485 
1486 		break;	/* unknown token */
1487 	}
1488 }
1489 
1490 static void
1491 pf_alternation()
1492 {
1493 	int s = opstack;
1494 
1495 	pf_primary();
1496 	for (;;) {
1497 		if (EQ("and"))
1498 			next();
1499 		pf_primary();
1500 		if (opstack != s + 2)
1501 			break;
1502 		pf_emit(ENF_AND);
1503 		opstack--;
1504 	}
1505 }
1506 
1507 static void
1508 pf_expression()
1509 {
1510 	pf_alternation();
1511 	while (EQ("or") || EQ(",")) {
1512 		if (inBrace)
1513 			inBraceOR++;
1514 		else
1515 			foundOR++;
1516 		next();
1517 		pf_alternation();
1518 		pf_emit(ENF_OR);
1519 		opstack--;
1520 	}
1521 }
1522 
1523 /*
1524  * Attempt to compile the expression
1525  * in the string "e".  If we can generate
1526  * pf code for it then return 1 - otherwise
1527  * return 0 and leave it up to the user-level
1528  * filter.
1529  */
1530 int
1531 pf_compile(e, print)
1532 	char *e;
1533 	int print;
1534 {
1535 	char *argstr;
1536 	char *sav_str, *ptr, *sav_ptr;
1537 	int inBr = 0, aheadOR = 0;
1538 
1539 	argstr = strdup(e);
1540 	sav_str = e;
1541 	tkp = argstr;
1542 	dir = ANY;
1543 
1544 	pfp = &pf.Pf_Filter[0];
1545 	if (setjmp(env)) {
1546 		return (0);
1547 	}
1548 
1549 	/*
1550 	 * Set media specific packet offsets that this code uses.
1551 	 */
1552 	if (interface->mac_type == DL_ETHER) {
1553 		dl.dl_type = DL_ETHER;
1554 		dl.dl_match_fn = pf_match_ethertype;
1555 		dl.dl_trans_map_tbl = ether_transport_mapping_table;
1556 		dl.dl_net_map_tbl = ether_network_mapping_table;
1557 		dl.dl_link_header_len = 14;
1558 		dl.dl_link_type_offset = 12;
1559 		dl.dl_link_dest_offset = 0;
1560 		dl.dl_link_src_offset = 6;
1561 		dl.dl_link_addr_len = 6;
1562 	}
1563 
1564 	if (interface->mac_type == DL_IB) {
1565 		dl.dl_type = DL_IB;
1566 		dl.dl_link_header_len = 4;
1567 		dl.dl_link_type_offset = 0;
1568 		dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1569 		dl.dl_link_addr_len = 20;
1570 		dl.dl_match_fn = pf_match_ibtype;
1571 		dl.dl_trans_map_tbl = ib_transport_mapping_table;
1572 		dl.dl_net_map_tbl = ib_network_mapping_table;
1573 	}
1574 
1575 	if (interface->mac_type == DL_IPNET) {
1576 		dl.dl_type = DL_IPNET;
1577 		dl.dl_link_header_len = 24;
1578 		dl.dl_link_type_offset = 0;
1579 		dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1580 		dl.dl_link_addr_len = -1;
1581 		dl.dl_match_fn = pf_match_ipnettype;
1582 		dl.dl_trans_map_tbl = ipnet_transport_mapping_table;
1583 		dl.dl_net_map_tbl = ipnet_network_mapping_table;
1584 	}
1585 
1586 	next();
1587 	pf_expression();
1588 
1589 	if (tokentype != EOL) {
1590 		/*
1591 		 * The idea here is to do as much filtering as possible in
1592 		 * the kernel. So even if we find a token we don't understand,
1593 		 * we try to see if we can still set up a portion of the filter
1594 		 * in the kernel and use the userland filter to filter the
1595 		 * remaining stuff. Obviously, if our filter expression is of
1596 		 * type A AND B, we can filter A in kernel and then apply B
1597 		 * to the packets that got through. The same is not true for
1598 		 * a filter of type A OR B. We can't apply A first and then B
1599 		 * on the packets filtered through A.
1600 		 *
1601 		 * (We need to keep track of the fact when we find an OR,
1602 		 * and the fact that we are inside brackets when we find OR.
1603 		 * The variable 'foundOR' tells us if there was an OR behind,
1604 		 * 'inBraceOR' tells us if we found an OR before we could find
1605 		 * the end brace i.e. ')', and variable 'aheadOR' checks if
1606 		 * there is an OR in the expression ahead. if either of these
1607 		 * cases become true, we can't split the filtering)
1608 		 */
1609 
1610 		if (foundOR || inBraceOR) {
1611 			/* FORGET IN KERNEL FILTERING */
1612 			return (0);
1613 		} else {
1614 
1615 			/* CHECK IF NO OR AHEAD */
1616 			sav_ptr = (char *)((uintptr_t)sav_str +
1617 						(uintptr_t)sav_tkp -
1618 						(uintptr_t)argstr);
1619 			ptr = sav_ptr;
1620 			while (*ptr != '\0') {
1621 				switch (*ptr) {
1622 				case '(':
1623 					inBr++;
1624 					break;
1625 				case ')':
1626 					inBr--;
1627 					break;
1628 				case 'o':
1629 				case 'O':
1630 					if ((*(ptr + 1) == 'R' ||
1631 						*(ptr + 1) == 'r') && !inBr)
1632 						aheadOR = 1;
1633 					break;
1634 				case ',':
1635 					if (!inBr)
1636 						aheadOR = 1;
1637 					break;
1638 				}
1639 				ptr++;
1640 			}
1641 			if (!aheadOR) {
1642 				/* NO OR AHEAD, SPLIT UP THE FILTERING */
1643 				pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1644 				pf.Pf_Priority = 5;
1645 				if (print) {
1646 					pf_codeprint(&pf.Pf_Filter[0],
1647 							pf.Pf_FilterLen);
1648 				}
1649 				compile(sav_ptr, print);
1650 				return (2);
1651 			} else
1652 				return (0);
1653 		}
1654 	}
1655 
1656 	pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1657 	pf.Pf_Priority = 5;	/* unimportant, so long as > 2 */
1658 	if (print) {
1659 		pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen);
1660 	}
1661 	return (1);
1662 }
1663