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