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