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