17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5605445d5Sdg199075 * Common Development and Distribution License (the "License").
6605445d5Sdg199075 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
220a0e9771SDarren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
24*7d897698SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <stdio.h>
28605445d5Sdg199075 #include <stddef.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #include <sys/socket.h>
38605445d5Sdg199075 #include <sys/vlan.h>
397c478bd9Sstevel@tonic-gate #include <net/if.h>
407c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
417c478bd9Sstevel@tonic-gate #include <netinet/in.h>
427c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
437c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
447c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
457c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
46b127ac41SPhilip Kirk #include <inet/ip.h>
47b127ac41SPhilip Kirk #include <inet/ip6.h>
487c478bd9Sstevel@tonic-gate #include <netdb.h>
497c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
507c478bd9Sstevel@tonic-gate #include <setjmp.h>
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #include <sys/pfmod.h>
537c478bd9Sstevel@tonic-gate #include "snoop.h"
54605445d5Sdg199075 #include "snoop_vlan.h"
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate * This module generates code for the kernel packet filter.
587c478bd9Sstevel@tonic-gate * The kernel packet filter is more efficient since it
597c478bd9Sstevel@tonic-gate * operates without context switching or moving data into
607c478bd9Sstevel@tonic-gate * the capture buffer. On the other hand, it is limited
617c478bd9Sstevel@tonic-gate * in its filtering ability i.e. can't cope with variable
627c478bd9Sstevel@tonic-gate * length headers, can't compare the packet size, 1 and 4 octet
637c478bd9Sstevel@tonic-gate * comparisons are awkward, code space is limited to ENMAXFILTERS
647c478bd9Sstevel@tonic-gate * halfwords, etc.
657c478bd9Sstevel@tonic-gate * The parser is the same for the user-level packet filter though
667c478bd9Sstevel@tonic-gate * more limited in the variety of expressions it can generate
677c478bd9Sstevel@tonic-gate * code for. If the pf compiler finds an expression it can't
687c478bd9Sstevel@tonic-gate * handle, it tries to set up a split filter in kernel and do the
697c478bd9Sstevel@tonic-gate * remaining filtering in userland. If that also fails, it resorts
707c478bd9Sstevel@tonic-gate * to userland filter. (See additional comment in pf_compile)
717c478bd9Sstevel@tonic-gate */
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate extern struct Pf_ext_packetfilt pf;
747c478bd9Sstevel@tonic-gate static ushort_t *pfp;
757c478bd9Sstevel@tonic-gate jmp_buf env;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate int eaddr; /* need ethernet addr */
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate int opstack; /* operand stack depth */
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate #define EQ(val) (strcmp(token, val) == 0)
827c478bd9Sstevel@tonic-gate #define IPV4_ONLY 0
837c478bd9Sstevel@tonic-gate #define IPV6_ONLY 1
847c478bd9Sstevel@tonic-gate #define IPV4_AND_IPV6 2
857c478bd9Sstevel@tonic-gate
86b127ac41SPhilip Kirk typedef struct {
87b127ac41SPhilip Kirk int transport_protocol;
88b127ac41SPhilip Kirk int network_protocol;
897c478bd9Sstevel@tonic-gate /*
90b127ac41SPhilip Kirk * offset is the offset in bytes from the beginning
91b127ac41SPhilip Kirk * of the network protocol header to where the transport
92b127ac41SPhilip Kirk * protocol type is.
937c478bd9Sstevel@tonic-gate */
94b127ac41SPhilip Kirk int offset;
95041bde0aSSebastien Roy } transport_table_t;
967c478bd9Sstevel@tonic-gate
97b127ac41SPhilip Kirk typedef struct network_table {
98b127ac41SPhilip Kirk char *nmt_name;
99b127ac41SPhilip Kirk int nmt_val;
100b127ac41SPhilip Kirk } network_table_t;
101b127ac41SPhilip Kirk
102b127ac41SPhilip Kirk static network_table_t ether_network_mapping_table[] = {
103b127ac41SPhilip Kirk { "pup", ETHERTYPE_PUP },
104b127ac41SPhilip Kirk { "ip", ETHERTYPE_IP },
105b127ac41SPhilip Kirk { "arp", ETHERTYPE_ARP },
106b127ac41SPhilip Kirk { "revarp", ETHERTYPE_REVARP },
107b127ac41SPhilip Kirk { "at", ETHERTYPE_AT },
108b127ac41SPhilip Kirk { "aarp", ETHERTYPE_AARP },
109b127ac41SPhilip Kirk { "vlan", ETHERTYPE_VLAN },
110b127ac41SPhilip Kirk { "ip6", ETHERTYPE_IPV6 },
111b127ac41SPhilip Kirk { "slow", ETHERTYPE_SLOW },
112b127ac41SPhilip Kirk { "ppoed", ETHERTYPE_PPPOED },
113b127ac41SPhilip Kirk { "ppoes", ETHERTYPE_PPPOES },
114b127ac41SPhilip Kirk { "NULL", -1 }
115b127ac41SPhilip Kirk
116b127ac41SPhilip Kirk };
117b127ac41SPhilip Kirk
118b127ac41SPhilip Kirk static network_table_t ib_network_mapping_table[] = {
119b127ac41SPhilip Kirk { "pup", ETHERTYPE_PUP },
120b127ac41SPhilip Kirk { "ip", ETHERTYPE_IP },
121b127ac41SPhilip Kirk { "arp", ETHERTYPE_ARP },
122b127ac41SPhilip Kirk { "revarp", ETHERTYPE_REVARP },
123b127ac41SPhilip Kirk { "at", ETHERTYPE_AT },
124b127ac41SPhilip Kirk { "aarp", ETHERTYPE_AARP },
125b127ac41SPhilip Kirk { "vlan", ETHERTYPE_VLAN },
126b127ac41SPhilip Kirk { "ip6", ETHERTYPE_IPV6 },
127b127ac41SPhilip Kirk { "slow", ETHERTYPE_SLOW },
128b127ac41SPhilip Kirk { "ppoed", ETHERTYPE_PPPOED },
129b127ac41SPhilip Kirk { "ppoes", ETHERTYPE_PPPOES },
130b127ac41SPhilip Kirk { "NULL", -1 }
131b127ac41SPhilip Kirk
132b127ac41SPhilip Kirk };
133b127ac41SPhilip Kirk
134b127ac41SPhilip Kirk static network_table_t ipnet_network_mapping_table[] = {
1350a0e9771SDarren Reed { "ip", (DL_IPNETINFO_VERSION << 8 | AF_INET) },
1360a0e9771SDarren Reed { "ip6", (DL_IPNETINFO_VERSION << 8 | AF_INET6) },
137b127ac41SPhilip Kirk { "NULL", -1 }
138b127ac41SPhilip Kirk
139b127ac41SPhilip Kirk };
140b127ac41SPhilip Kirk
141041bde0aSSebastien Roy static transport_table_t ether_transport_mapping_table[] = {
142b127ac41SPhilip Kirk {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
143b127ac41SPhilip Kirk {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
144b127ac41SPhilip Kirk {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
145b127ac41SPhilip Kirk {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
146b127ac41SPhilip Kirk {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
147b127ac41SPhilip Kirk {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
148b127ac41SPhilip Kirk {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
149b127ac41SPhilip Kirk {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
150b127ac41SPhilip Kirk {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
151b127ac41SPhilip Kirk {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
152b127ac41SPhilip Kirk {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
153b127ac41SPhilip Kirk {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
154b127ac41SPhilip Kirk {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
155b127ac41SPhilip Kirk {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
156b127ac41SPhilip Kirk {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
157b127ac41SPhilip Kirk {-1, 0, 0} /* must be the final entry */
158b127ac41SPhilip Kirk };
159b127ac41SPhilip Kirk
160041bde0aSSebastien Roy static transport_table_t ipnet_transport_mapping_table[] = {
1610a0e9771SDarren Reed {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
162b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1630a0e9771SDarren Reed {IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
164b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
1650a0e9771SDarren Reed {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
166b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1670a0e9771SDarren Reed {IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
168b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
1690a0e9771SDarren Reed {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET),
170b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1710a0e9771SDarren Reed {IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
172b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
1730a0e9771SDarren Reed {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
174b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1750a0e9771SDarren Reed {IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
176b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
1770a0e9771SDarren Reed {IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
178b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1790a0e9771SDarren Reed {IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
180b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
1810a0e9771SDarren Reed {IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
182b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1830a0e9771SDarren Reed {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
184b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1850a0e9771SDarren Reed {IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
186b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
1870a0e9771SDarren Reed {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET),
188b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET},
1890a0e9771SDarren Reed {IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
190b127ac41SPhilip Kirk IPV6_TYPE_HEADER_OFFSET},
191b127ac41SPhilip Kirk {-1, 0, 0} /* must be the final entry */
192b127ac41SPhilip Kirk };
193b127ac41SPhilip Kirk
194041bde0aSSebastien Roy static transport_table_t ib_transport_mapping_table[] = {
195b127ac41SPhilip Kirk {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
196b127ac41SPhilip Kirk {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
197b127ac41SPhilip Kirk {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
198b127ac41SPhilip Kirk {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
199b127ac41SPhilip Kirk {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
200b127ac41SPhilip Kirk {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
201b127ac41SPhilip Kirk {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
202b127ac41SPhilip Kirk {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
203b127ac41SPhilip Kirk {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
204b127ac41SPhilip Kirk {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
205b127ac41SPhilip Kirk {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
206b127ac41SPhilip Kirk {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
207b127ac41SPhilip Kirk {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
208b127ac41SPhilip Kirk {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
209b127ac41SPhilip Kirk {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
210b127ac41SPhilip Kirk {-1, 0, 0} /* must be the final entry */
211b127ac41SPhilip Kirk };
212b127ac41SPhilip Kirk
213b127ac41SPhilip Kirk typedef struct datalink {
214b127ac41SPhilip Kirk uint_t dl_type;
215b127ac41SPhilip Kirk void (*dl_match_fn)(uint_t datatype);
216041bde0aSSebastien Roy transport_table_t *dl_trans_map_tbl;
217b127ac41SPhilip Kirk network_table_t *dl_net_map_tbl;
218b127ac41SPhilip Kirk int dl_link_header_len;
219b127ac41SPhilip Kirk int dl_link_type_offset;
220b127ac41SPhilip Kirk int dl_link_dest_offset;
221b127ac41SPhilip Kirk int dl_link_src_offset;
222b127ac41SPhilip Kirk int dl_link_addr_len;
223b127ac41SPhilip Kirk } datalink_t;
224b127ac41SPhilip Kirk
225b127ac41SPhilip Kirk datalink_t dl;
226b127ac41SPhilip Kirk
227b127ac41SPhilip Kirk #define IPV4_SRCADDR_OFFSET (dl.dl_link_header_len + 12)
228b127ac41SPhilip Kirk #define IPV4_DSTADDR_OFFSET (dl.dl_link_header_len + 16)
229b127ac41SPhilip Kirk #define IPV6_SRCADDR_OFFSET (dl.dl_link_header_len + 8)
230b127ac41SPhilip Kirk #define IPV6_DSTADDR_OFFSET (dl.dl_link_header_len + 24)
231b127ac41SPhilip Kirk
2320a0e9771SDarren Reed #define IPNET_SRCZONE_OFFSET 16
2330a0e9771SDarren Reed #define IPNET_DSTZONE_OFFSET 20
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate static int inBrace = 0, inBraceOR = 0;
2367c478bd9Sstevel@tonic-gate static int foundOR = 0;
2377c478bd9Sstevel@tonic-gate char *tkp, *sav_tkp;
2387c478bd9Sstevel@tonic-gate char *token;
2397c478bd9Sstevel@tonic-gate enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
2407c478bd9Sstevel@tonic-gate ADDR_IP6 } tokentype;
2417c478bd9Sstevel@tonic-gate uint_t tokenval;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate enum direction { ANY, TO, FROM };
2447c478bd9Sstevel@tonic-gate enum direction dir;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate extern void next();
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate static void pf_expression();
249605445d5Sdg199075 static void pf_check_vlan_tag(uint_t offset);
250605445d5Sdg199075 static void pf_clear_offset_register();
251605445d5Sdg199075 static void pf_emit_load_offset(uint_t offset);
252605445d5Sdg199075 static void pf_match_ethertype(uint_t ethertype);
253b127ac41SPhilip Kirk static void pf_match_ipnettype(uint_t type);
254b127ac41SPhilip Kirk static void pf_match_ibtype(uint_t type);
255605445d5Sdg199075 static void pf_check_transport_protocol(uint_t transport_protocol);
256605445d5Sdg199075 static void pf_compare_value_mask_generic(int offset, uint_t len,
257605445d5Sdg199075 uint_t val, int mask, uint_t op);
258041bde0aSSebastien Roy static void pf_matchfn(const char *name);
259605445d5Sdg199075
260605445d5Sdg199075 /*
261605445d5Sdg199075 * This pointer points to the function that last generated
262605445d5Sdg199075 * instructions to change the offset register. It's used
263605445d5Sdg199075 * for comparisons to see if we need to issue more instructions
264605445d5Sdg199075 * to change the register.
265605445d5Sdg199075 *
266605445d5Sdg199075 * It's initialized to pf_clear_offset_register because the offset
267605445d5Sdg199075 * register in pfmod is initialized to zero, similar to the state
268605445d5Sdg199075 * it would be in after executing the instructions issued by
269605445d5Sdg199075 * pf_clear_offset_register.
270605445d5Sdg199075 */
271605445d5Sdg199075 static void *last_offset_operation = (void*)pf_clear_offset_register;
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate static void
pf_emit(x)2747c478bd9Sstevel@tonic-gate pf_emit(x)
2757c478bd9Sstevel@tonic-gate ushort_t x;
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1])
2787c478bd9Sstevel@tonic-gate longjmp(env, 1);
2797c478bd9Sstevel@tonic-gate *pfp++ = x;
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate static void
pf_codeprint(code,len)2837c478bd9Sstevel@tonic-gate pf_codeprint(code, len)
2847c478bd9Sstevel@tonic-gate ushort_t *code;
2857c478bd9Sstevel@tonic-gate int len;
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate ushort_t *pc;
2887c478bd9Sstevel@tonic-gate ushort_t *plast = code + len;
2897c478bd9Sstevel@tonic-gate int op, action;
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate if (len > 0) {
2927c478bd9Sstevel@tonic-gate printf("Kernel Filter:\n");
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate for (pc = code; pc < plast; pc++) {
2967c478bd9Sstevel@tonic-gate printf("\t%3d: ", pc - code);
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate op = *pc & 0xfc00; /* high 10 bits */
2997c478bd9Sstevel@tonic-gate action = *pc & 0x3ff; /* low 6 bits */
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate switch (action) {
3027c478bd9Sstevel@tonic-gate case ENF_PUSHLIT:
3037c478bd9Sstevel@tonic-gate printf("PUSHLIT ");
3047c478bd9Sstevel@tonic-gate break;
3057c478bd9Sstevel@tonic-gate case ENF_PUSHZERO:
3067c478bd9Sstevel@tonic-gate printf("PUSHZERO ");
3077c478bd9Sstevel@tonic-gate break;
3087c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHONE
3097c478bd9Sstevel@tonic-gate case ENF_PUSHONE:
3107c478bd9Sstevel@tonic-gate printf("PUSHONE ");
3117c478bd9Sstevel@tonic-gate break;
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHFFFF
3147c478bd9Sstevel@tonic-gate case ENF_PUSHFFFF:
3157c478bd9Sstevel@tonic-gate printf("PUSHFFFF ");
3167c478bd9Sstevel@tonic-gate break;
3177c478bd9Sstevel@tonic-gate #endif
3187c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHFF00
3197c478bd9Sstevel@tonic-gate case ENF_PUSHFF00:
3207c478bd9Sstevel@tonic-gate printf("PUSHFF00 ");
3217c478bd9Sstevel@tonic-gate break;
3227c478bd9Sstevel@tonic-gate #endif
3237c478bd9Sstevel@tonic-gate #ifdef ENF_PUSH00FF
3247c478bd9Sstevel@tonic-gate case ENF_PUSH00FF:
3257c478bd9Sstevel@tonic-gate printf("PUSH00FF ");
3267c478bd9Sstevel@tonic-gate break;
3277c478bd9Sstevel@tonic-gate #endif
328605445d5Sdg199075 case ENF_LOAD_OFFSET:
329605445d5Sdg199075 printf("LOAD_OFFSET ");
330605445d5Sdg199075 break;
331605445d5Sdg199075 case ENF_BRTR:
332605445d5Sdg199075 printf("BRTR ");
333605445d5Sdg199075 break;
334605445d5Sdg199075 case ENF_BRFL:
335605445d5Sdg199075 printf("BRFL ");
336605445d5Sdg199075 break;
337605445d5Sdg199075 case ENF_POP:
338605445d5Sdg199075 printf("POP ");
339605445d5Sdg199075 break;
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate if (action >= ENF_PUSHWORD)
3437c478bd9Sstevel@tonic-gate printf("PUSHWORD %d ", action - ENF_PUSHWORD);
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate switch (op) {
3467c478bd9Sstevel@tonic-gate case ENF_EQ:
3477c478bd9Sstevel@tonic-gate printf("EQ ");
3487c478bd9Sstevel@tonic-gate break;
3497c478bd9Sstevel@tonic-gate case ENF_LT:
3507c478bd9Sstevel@tonic-gate printf("LT ");
3517c478bd9Sstevel@tonic-gate break;
3527c478bd9Sstevel@tonic-gate case ENF_LE:
3537c478bd9Sstevel@tonic-gate printf("LE ");
3547c478bd9Sstevel@tonic-gate break;
3557c478bd9Sstevel@tonic-gate case ENF_GT:
3567c478bd9Sstevel@tonic-gate printf("GT ");
3577c478bd9Sstevel@tonic-gate break;
3587c478bd9Sstevel@tonic-gate case ENF_GE:
3597c478bd9Sstevel@tonic-gate printf("GE ");
3607c478bd9Sstevel@tonic-gate break;
3617c478bd9Sstevel@tonic-gate case ENF_AND:
3627c478bd9Sstevel@tonic-gate printf("AND ");
3637c478bd9Sstevel@tonic-gate break;
3647c478bd9Sstevel@tonic-gate case ENF_OR:
3657c478bd9Sstevel@tonic-gate printf("OR ");
3667c478bd9Sstevel@tonic-gate break;
3677c478bd9Sstevel@tonic-gate case ENF_XOR:
3687c478bd9Sstevel@tonic-gate printf("XOR ");
3697c478bd9Sstevel@tonic-gate break;
3707c478bd9Sstevel@tonic-gate case ENF_COR:
3717c478bd9Sstevel@tonic-gate printf("COR ");
3727c478bd9Sstevel@tonic-gate break;
3737c478bd9Sstevel@tonic-gate case ENF_CAND:
3747c478bd9Sstevel@tonic-gate printf("CAND ");
3757c478bd9Sstevel@tonic-gate break;
3767c478bd9Sstevel@tonic-gate case ENF_CNOR:
3777c478bd9Sstevel@tonic-gate printf("CNOR ");
3787c478bd9Sstevel@tonic-gate break;
3797c478bd9Sstevel@tonic-gate case ENF_CNAND:
3807c478bd9Sstevel@tonic-gate printf("CNAND ");
3817c478bd9Sstevel@tonic-gate break;
3827c478bd9Sstevel@tonic-gate case ENF_NEQ:
3837c478bd9Sstevel@tonic-gate printf("NEQ ");
3847c478bd9Sstevel@tonic-gate break;
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate
387605445d5Sdg199075 if (action == ENF_PUSHLIT ||
388605445d5Sdg199075 action == ENF_LOAD_OFFSET ||
389605445d5Sdg199075 action == ENF_BRTR ||
390605445d5Sdg199075 action == ENF_BRFL) {
3917c478bd9Sstevel@tonic-gate pc++;
3927c478bd9Sstevel@tonic-gate printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate printf("\n");
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * Emit packet filter code to check a
4017c478bd9Sstevel@tonic-gate * field in the packet for a particular value.
4027c478bd9Sstevel@tonic-gate * Need different code for each field size.
4037c478bd9Sstevel@tonic-gate * Since the pf can only compare 16 bit quantities
4047c478bd9Sstevel@tonic-gate * we have to use masking to compare byte values.
4057c478bd9Sstevel@tonic-gate * Long word (32 bit) quantities have to be done
4067c478bd9Sstevel@tonic-gate * as two 16 bit comparisons.
4077c478bd9Sstevel@tonic-gate */
4087c478bd9Sstevel@tonic-gate static void
pf_compare_value(int offset,uint_t len,uint_t val)4097c478bd9Sstevel@tonic-gate pf_compare_value(int offset, uint_t len, uint_t val)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate * If the property being filtered on is absent in the media
4137c478bd9Sstevel@tonic-gate * packet, error out.
4147c478bd9Sstevel@tonic-gate */
4157c478bd9Sstevel@tonic-gate if (offset == -1)
4167c478bd9Sstevel@tonic-gate pr_err("filter option unsupported on media");
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate switch (len) {
4197c478bd9Sstevel@tonic-gate case 1:
4207c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2);
4217c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
4227c478bd9Sstevel@tonic-gate if (offset % 2)
4237c478bd9Sstevel@tonic-gate #else
4247c478bd9Sstevel@tonic-gate if (!(offset % 2))
4257c478bd9Sstevel@tonic-gate #endif
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate #ifdef ENF_PUSH00FF
4287c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSH00FF | ENF_AND);
4297c478bd9Sstevel@tonic-gate #else
4307c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
4317c478bd9Sstevel@tonic-gate pf_emit(0x00FF);
4327c478bd9Sstevel@tonic-gate #endif
4337c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ);
4347c478bd9Sstevel@tonic-gate pf_emit(val);
4357c478bd9Sstevel@tonic-gate } else {
4367c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHFF00
4377c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHFF00 | ENF_AND);
4387c478bd9Sstevel@tonic-gate #else
4397c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
4407c478bd9Sstevel@tonic-gate pf_emit(0xFF00);
4417c478bd9Sstevel@tonic-gate #endif
4427c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ);
4437c478bd9Sstevel@tonic-gate pf_emit(val << 8);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate break;
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate case 2:
4487c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2);
4497c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ);
4507c478bd9Sstevel@tonic-gate pf_emit((ushort_t)val);
4517c478bd9Sstevel@tonic-gate break;
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate case 4:
4547c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2);
4557c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ);
4567c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
4577c478bd9Sstevel@tonic-gate pf_emit(val >> 16);
4587c478bd9Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN)
4597c478bd9Sstevel@tonic-gate pf_emit(val & 0xffff);
4607c478bd9Sstevel@tonic-gate #else
4617c478bd9Sstevel@tonic-gate #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined
4627c478bd9Sstevel@tonic-gate #endif
4637c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
4647c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ);
4657c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
4667c478bd9Sstevel@tonic-gate pf_emit(val & 0xffff);
4677c478bd9Sstevel@tonic-gate #else
4687c478bd9Sstevel@tonic-gate pf_emit(val >> 16);
4697c478bd9Sstevel@tonic-gate #endif
4707c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
4717c478bd9Sstevel@tonic-gate break;
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate /*
4767c478bd9Sstevel@tonic-gate * same as pf_compare_value, but only for emiting code to
4777c478bd9Sstevel@tonic-gate * compare ipv6 addresses.
4787c478bd9Sstevel@tonic-gate */
4797c478bd9Sstevel@tonic-gate static void
pf_compare_value_v6(int offset,uint_t len,struct in6_addr val)4807c478bd9Sstevel@tonic-gate pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate int i;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate for (i = 0; i < len; i += 2) {
4857c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2 + i / 2);
4867c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_EQ);
4877c478bd9Sstevel@tonic-gate pf_emit(*(uint16_t *)&val.s6_addr[i]);
4887c478bd9Sstevel@tonic-gate if (i != 0)
4897c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate * Same as above except mask the field value
496605445d5Sdg199075 * before doing the comparison. The comparison checks
497605445d5Sdg199075 * to make sure the values are equal.
4987c478bd9Sstevel@tonic-gate */
4997c478bd9Sstevel@tonic-gate static void
pf_compare_value_mask(int offset,uint_t len,uint_t val,int mask)5007c478bd9Sstevel@tonic-gate pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
5017c478bd9Sstevel@tonic-gate {
502605445d5Sdg199075 pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ);
503605445d5Sdg199075 }
504605445d5Sdg199075
505605445d5Sdg199075 /*
506605445d5Sdg199075 * Same as above except the values are compared to see if they are not
507605445d5Sdg199075 * equal.
508605445d5Sdg199075 */
509605445d5Sdg199075 static void
pf_compare_value_mask_neq(int offset,uint_t len,uint_t val,int mask)510605445d5Sdg199075 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask)
511605445d5Sdg199075 {
512605445d5Sdg199075 pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ);
513605445d5Sdg199075 }
514605445d5Sdg199075
515605445d5Sdg199075 /*
516605445d5Sdg199075 * Similar to pf_compare_value.
517605445d5Sdg199075 *
518605445d5Sdg199075 * This is the utility function that does the actual work to compare
519605445d5Sdg199075 * two values using a mask. The comparison operation is passed into
520605445d5Sdg199075 * the function.
521605445d5Sdg199075 */
522605445d5Sdg199075 static void
pf_compare_value_mask_generic(int offset,uint_t len,uint_t val,int mask,uint_t op)523605445d5Sdg199075 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask,
524605445d5Sdg199075 uint_t op)
525605445d5Sdg199075 {
5267c478bd9Sstevel@tonic-gate /*
5277c478bd9Sstevel@tonic-gate * If the property being filtered on is absent in the media
5287c478bd9Sstevel@tonic-gate * packet, error out.
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate if (offset == -1)
5317c478bd9Sstevel@tonic-gate pr_err("filter option unsupported on media");
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate switch (len) {
5347c478bd9Sstevel@tonic-gate case 1:
5357c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2);
5367c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
5377c478bd9Sstevel@tonic-gate if (offset % 2)
5387c478bd9Sstevel@tonic-gate #else
5397c478bd9Sstevel@tonic-gate if (!offset % 2)
5407c478bd9Sstevel@tonic-gate #endif
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
5437c478bd9Sstevel@tonic-gate pf_emit(mask & 0x00ff);
544605445d5Sdg199075 pf_emit(ENF_PUSHLIT | op);
5457c478bd9Sstevel@tonic-gate pf_emit(val);
5467c478bd9Sstevel@tonic-gate } else {
5477c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
5487c478bd9Sstevel@tonic-gate pf_emit((mask << 8) & 0xff00);
549605445d5Sdg199075 pf_emit(ENF_PUSHLIT | op);
5507c478bd9Sstevel@tonic-gate pf_emit(val << 8);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate break;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate case 2:
5557c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2);
5567c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
5577c478bd9Sstevel@tonic-gate pf_emit(htons((ushort_t)mask));
558605445d5Sdg199075 pf_emit(ENF_PUSHLIT | op);
5597c478bd9Sstevel@tonic-gate pf_emit(htons((ushort_t)val));
5607c478bd9Sstevel@tonic-gate break;
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate case 4:
5637c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + offset / 2);
5647c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
5657c478bd9Sstevel@tonic-gate pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
566605445d5Sdg199075 pf_emit(ENF_PUSHLIT | op);
5677c478bd9Sstevel@tonic-gate pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
5707c478bd9Sstevel@tonic-gate pf_emit(ENF_PUSHLIT | ENF_AND);
5717c478bd9Sstevel@tonic-gate pf_emit(htons((ushort_t)(mask & 0xffff)));
572605445d5Sdg199075 pf_emit(ENF_PUSHLIT | op);
5737c478bd9Sstevel@tonic-gate pf_emit(htons((ushort_t)(val & 0xffff)));
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
5767c478bd9Sstevel@tonic-gate break;
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate /*
5810a0e9771SDarren Reed * Like pf_compare_value() but compare on a 32-bit zoneid value.
582b127ac41SPhilip Kirk * The argument val passed in is in network byte order.
583b127ac41SPhilip Kirk */
584b127ac41SPhilip Kirk static void
pf_compare_zoneid(int offset,uint32_t val)5850a0e9771SDarren Reed pf_compare_zoneid(int offset, uint32_t val)
586b127ac41SPhilip Kirk {
587b127ac41SPhilip Kirk int i;
588b127ac41SPhilip Kirk
5890a0e9771SDarren Reed for (i = 0; i < sizeof (uint32_t) / 2; i ++) {
590b127ac41SPhilip Kirk pf_emit(ENF_PUSHWORD + offset / 2 + i);
591b127ac41SPhilip Kirk pf_emit(ENF_PUSHLIT | ENF_EQ);
592b127ac41SPhilip Kirk pf_emit(((uint16_t *)&val)[i]);
593b127ac41SPhilip Kirk if (i != 0)
594b127ac41SPhilip Kirk pf_emit(ENF_AND);
595b127ac41SPhilip Kirk }
596b127ac41SPhilip Kirk }
597b127ac41SPhilip Kirk
598b127ac41SPhilip Kirk /*
5997c478bd9Sstevel@tonic-gate * Generate pf code to match an IPv4 or IPv6 address.
6007c478bd9Sstevel@tonic-gate */
6017c478bd9Sstevel@tonic-gate static void
pf_ipaddr_match(which,hostname,inet_type)6027c478bd9Sstevel@tonic-gate pf_ipaddr_match(which, hostname, inet_type)
6037c478bd9Sstevel@tonic-gate enum direction which;
6047c478bd9Sstevel@tonic-gate char *hostname;
6057c478bd9Sstevel@tonic-gate int inet_type;
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate bool_t found_host;
6087c478bd9Sstevel@tonic-gate uint_t *addr4ptr;
6097c478bd9Sstevel@tonic-gate uint_t addr4;
6107c478bd9Sstevel@tonic-gate struct in6_addr *addr6ptr;
6117c478bd9Sstevel@tonic-gate int h_addr_index;
6127c478bd9Sstevel@tonic-gate struct hostent *hp = NULL;
6137c478bd9Sstevel@tonic-gate int error_num = 0;
6147c478bd9Sstevel@tonic-gate boolean_t first = B_TRUE;
6157c478bd9Sstevel@tonic-gate int pass = 0;
616041bde0aSSebastien Roy int i;
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate /*
6197c478bd9Sstevel@tonic-gate * The addr4offset and addr6offset variables simplify the code which
6207c478bd9Sstevel@tonic-gate * generates the address comparison filter. With these two variables,
6217c478bd9Sstevel@tonic-gate * duplicate code need not exist for the TO and FROM case.
6227c478bd9Sstevel@tonic-gate * A value of -1 describes the ANY case (TO and FROM).
6237c478bd9Sstevel@tonic-gate */
6247c478bd9Sstevel@tonic-gate int addr4offset;
6257c478bd9Sstevel@tonic-gate int addr6offset;
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate found_host = 0;
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate if (tokentype == ADDR_IP) {
6307c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
6317c478bd9Sstevel@tonic-gate if (hp == NULL) {
6327c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) {
6337c478bd9Sstevel@tonic-gate pr_err("could not resolve %s (try again later)",
6347c478bd9Sstevel@tonic-gate hostname);
6357c478bd9Sstevel@tonic-gate } else {
6367c478bd9Sstevel@tonic-gate pr_err("could not resolve %s", hostname);
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate inet_type = IPV4_ONLY;
6407c478bd9Sstevel@tonic-gate } else if (tokentype == ADDR_IP6) {
6417c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
6427c478bd9Sstevel@tonic-gate if (hp == NULL) {
6437c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) {
6447c478bd9Sstevel@tonic-gate pr_err("could not resolve %s (try again later)",
6457c478bd9Sstevel@tonic-gate hostname);
6467c478bd9Sstevel@tonic-gate } else {
6477c478bd9Sstevel@tonic-gate pr_err("could not resolve %s", hostname);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate inet_type = IPV6_ONLY;
6517c478bd9Sstevel@tonic-gate } else if (tokentype == ALPHA) {
6527c478bd9Sstevel@tonic-gate /* Some hostname i.e. tokentype is ALPHA */
6537c478bd9Sstevel@tonic-gate switch (inet_type) {
6547c478bd9Sstevel@tonic-gate case IPV4_ONLY:
6557c478bd9Sstevel@tonic-gate /* Only IPv4 address is needed */
6567c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
6577c478bd9Sstevel@tonic-gate if (hp != NULL) {
6587c478bd9Sstevel@tonic-gate found_host = 1;
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate break;
6617c478bd9Sstevel@tonic-gate case IPV6_ONLY:
6627c478bd9Sstevel@tonic-gate /* Only IPv6 address is needed */
6637c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
6647c478bd9Sstevel@tonic-gate if (hp != NULL) {
6657c478bd9Sstevel@tonic-gate found_host = 1;
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate break;
6687c478bd9Sstevel@tonic-gate case IPV4_AND_IPV6:
6697c478bd9Sstevel@tonic-gate /* Both IPv4 and IPv6 are needed */
6707c478bd9Sstevel@tonic-gate hp = getipnodebyname(hostname, AF_INET6,
6717c478bd9Sstevel@tonic-gate AI_ALL | AI_V4MAPPED, &error_num);
6727c478bd9Sstevel@tonic-gate if (hp != NULL) {
6737c478bd9Sstevel@tonic-gate found_host = 1;
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate break;
6767c478bd9Sstevel@tonic-gate default:
6777c478bd9Sstevel@tonic-gate found_host = 0;
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate if (!found_host) {
6817c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) {
6827c478bd9Sstevel@tonic-gate pr_err("could not resolve %s (try again later)",
6837c478bd9Sstevel@tonic-gate hostname);
6847c478bd9Sstevel@tonic-gate } else {
6857c478bd9Sstevel@tonic-gate pr_err("could not resolve %s", hostname);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate } else {
6897c478bd9Sstevel@tonic-gate pr_err("unknown token type: %s", hostname);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
692*7d897698SMilan Jurik if (hp == NULL)
693*7d897698SMilan Jurik return;
694*7d897698SMilan Jurik
6957c478bd9Sstevel@tonic-gate switch (which) {
6967c478bd9Sstevel@tonic-gate case TO:
6977c478bd9Sstevel@tonic-gate addr4offset = IPV4_DSTADDR_OFFSET;
6987c478bd9Sstevel@tonic-gate addr6offset = IPV6_DSTADDR_OFFSET;
6997c478bd9Sstevel@tonic-gate break;
7007c478bd9Sstevel@tonic-gate case FROM:
7017c478bd9Sstevel@tonic-gate addr4offset = IPV4_SRCADDR_OFFSET;
7027c478bd9Sstevel@tonic-gate addr6offset = IPV6_SRCADDR_OFFSET;
7037c478bd9Sstevel@tonic-gate break;
7047c478bd9Sstevel@tonic-gate case ANY:
7057c478bd9Sstevel@tonic-gate addr4offset = -1;
7067c478bd9Sstevel@tonic-gate addr6offset = -1;
7077c478bd9Sstevel@tonic-gate break;
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
710*7d897698SMilan Jurik if (hp->h_addrtype == AF_INET) {
711041bde0aSSebastien Roy pf_matchfn("ip");
712b127ac41SPhilip Kirk if (dl.dl_type == DL_ETHER)
713605445d5Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
7147c478bd9Sstevel@tonic-gate h_addr_index = 0;
7157c478bd9Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
7167c478bd9Sstevel@tonic-gate while (addr4ptr != NULL) {
7177c478bd9Sstevel@tonic-gate if (addr4offset == -1) {
7187c478bd9Sstevel@tonic-gate pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
7197c478bd9Sstevel@tonic-gate *addr4ptr);
7207c478bd9Sstevel@tonic-gate if (h_addr_index != 0)
7217c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7227c478bd9Sstevel@tonic-gate pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
7237c478bd9Sstevel@tonic-gate *addr4ptr);
7247c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7257c478bd9Sstevel@tonic-gate } else {
7267c478bd9Sstevel@tonic-gate pf_compare_value(addr4offset, 4,
7277c478bd9Sstevel@tonic-gate *addr4ptr);
7287c478bd9Sstevel@tonic-gate if (h_addr_index != 0)
7297c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
7347c478bd9Sstevel@tonic-gate } else {
7357c478bd9Sstevel@tonic-gate /* first pass: IPv4 addresses */
7367c478bd9Sstevel@tonic-gate h_addr_index = 0;
7377c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
7387c478bd9Sstevel@tonic-gate first = B_TRUE;
7397c478bd9Sstevel@tonic-gate while (addr6ptr != NULL) {
7407c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
7417c478bd9Sstevel@tonic-gate if (first) {
742041bde0aSSebastien Roy pf_matchfn("ip");
743b127ac41SPhilip Kirk if (dl.dl_type == DL_ETHER) {
744605445d5Sdg199075 pf_check_vlan_tag(
745605445d5Sdg199075 ENCAP_ETHERTYPE_OFF/2);
746b127ac41SPhilip Kirk }
7477c478bd9Sstevel@tonic-gate pass++;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(addr6ptr,
7507c478bd9Sstevel@tonic-gate (struct in_addr *)&addr4);
7517c478bd9Sstevel@tonic-gate if (addr4offset == -1) {
7527c478bd9Sstevel@tonic-gate pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
7537c478bd9Sstevel@tonic-gate addr4);
7547c478bd9Sstevel@tonic-gate if (!first)
7557c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7567c478bd9Sstevel@tonic-gate pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
7577c478bd9Sstevel@tonic-gate addr4);
7587c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7597c478bd9Sstevel@tonic-gate } else {
7607c478bd9Sstevel@tonic-gate pf_compare_value(addr4offset, 4,
7617c478bd9Sstevel@tonic-gate addr4);
7627c478bd9Sstevel@tonic-gate if (!first)
7637c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate if (first)
7667c478bd9Sstevel@tonic-gate first = B_FALSE;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)
7697c478bd9Sstevel@tonic-gate hp->h_addr_list[++h_addr_index];
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate if (!first) {
7727c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate /* second pass: IPv6 addresses */
7757c478bd9Sstevel@tonic-gate h_addr_index = 0;
7767c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
7777c478bd9Sstevel@tonic-gate first = B_TRUE;
7787c478bd9Sstevel@tonic-gate while (addr6ptr != NULL) {
7797c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
7807c478bd9Sstevel@tonic-gate if (first) {
781041bde0aSSebastien Roy pf_matchfn("ip6");
782b127ac41SPhilip Kirk if (dl.dl_type == DL_ETHER) {
783605445d5Sdg199075 pf_check_vlan_tag(
784605445d5Sdg199075 ENCAP_ETHERTYPE_OFF/2);
785b127ac41SPhilip Kirk }
7867c478bd9Sstevel@tonic-gate pass++;
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate if (addr6offset == -1) {
7897c478bd9Sstevel@tonic-gate pf_compare_value_v6(IPV6_SRCADDR_OFFSET,
7907c478bd9Sstevel@tonic-gate 16, *addr6ptr);
7917c478bd9Sstevel@tonic-gate if (!first)
7927c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7937c478bd9Sstevel@tonic-gate pf_compare_value_v6(IPV6_DSTADDR_OFFSET,
7947c478bd9Sstevel@tonic-gate 16, *addr6ptr);
7957c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
7967c478bd9Sstevel@tonic-gate } else {
7977c478bd9Sstevel@tonic-gate pf_compare_value_v6(addr6offset, 16,
7987c478bd9Sstevel@tonic-gate *addr6ptr);
7997c478bd9Sstevel@tonic-gate if (!first)
8007c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate if (first)
8037c478bd9Sstevel@tonic-gate first = B_FALSE;
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate addr6ptr = (struct in6_addr *)
8067c478bd9Sstevel@tonic-gate hp->h_addr_list[++h_addr_index];
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate if (!first) {
8097c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate if (pass == 2) {
8127c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate freehostent(hp);
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate static void
pf_compare_address(int offset,uint_t len,uchar_t * addr)8217c478bd9Sstevel@tonic-gate pf_compare_address(int offset, uint_t len, uchar_t *addr)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate uint32_t val;
8247c478bd9Sstevel@tonic-gate uint16_t sval;
8257c478bd9Sstevel@tonic-gate boolean_t didone = B_FALSE;
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * If the property being filtered on is absent in the media
8297c478bd9Sstevel@tonic-gate * packet, error out.
8307c478bd9Sstevel@tonic-gate */
8317c478bd9Sstevel@tonic-gate if (offset == -1)
8327c478bd9Sstevel@tonic-gate pr_err("filter option unsupported on media");
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate while (len > 0) {
8357c478bd9Sstevel@tonic-gate if (len >= 4) {
8367c478bd9Sstevel@tonic-gate (void) memcpy(&val, addr, 4);
8377c478bd9Sstevel@tonic-gate pf_compare_value(offset, 4, val);
8387c478bd9Sstevel@tonic-gate addr += 4;
8397c478bd9Sstevel@tonic-gate offset += 4;
8407c478bd9Sstevel@tonic-gate len -= 4;
8417c478bd9Sstevel@tonic-gate } else if (len >= 2) {
8427c478bd9Sstevel@tonic-gate (void) memcpy(&sval, addr, 2);
8437c478bd9Sstevel@tonic-gate pf_compare_value(offset, 2, sval);
8447c478bd9Sstevel@tonic-gate addr += 2;
8457c478bd9Sstevel@tonic-gate offset += 2;
8467c478bd9Sstevel@tonic-gate len -= 2;
8477c478bd9Sstevel@tonic-gate } else {
8487c478bd9Sstevel@tonic-gate pf_compare_value(offset++, 1, *addr++);
8497c478bd9Sstevel@tonic-gate len--;
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate if (didone)
8527c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
8537c478bd9Sstevel@tonic-gate didone = B_TRUE;
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate * Compare ethernet addresses.
8597c478bd9Sstevel@tonic-gate */
8607c478bd9Sstevel@tonic-gate static void
pf_etheraddr_match(which,hostname)8617c478bd9Sstevel@tonic-gate pf_etheraddr_match(which, hostname)
8627c478bd9Sstevel@tonic-gate enum direction which;
8637c478bd9Sstevel@tonic-gate char *hostname;
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate struct ether_addr e, *ep = NULL;
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate if (isxdigit(*hostname))
8687c478bd9Sstevel@tonic-gate ep = ether_aton(hostname);
8697c478bd9Sstevel@tonic-gate if (ep == NULL) {
8707c478bd9Sstevel@tonic-gate if (ether_hostton(hostname, &e))
8717c478bd9Sstevel@tonic-gate if (!arp_for_ether(hostname, &e))
8727c478bd9Sstevel@tonic-gate pr_err("cannot obtain ether addr for %s",
8737c478bd9Sstevel@tonic-gate hostname);
8747c478bd9Sstevel@tonic-gate ep = &e;
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
877605445d5Sdg199075 pf_clear_offset_register();
878605445d5Sdg199075
8797c478bd9Sstevel@tonic-gate switch (which) {
8807c478bd9Sstevel@tonic-gate case TO:
881b127ac41SPhilip Kirk pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
8827c478bd9Sstevel@tonic-gate (uchar_t *)ep);
8837c478bd9Sstevel@tonic-gate break;
8847c478bd9Sstevel@tonic-gate case FROM:
885b127ac41SPhilip Kirk pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
8867c478bd9Sstevel@tonic-gate (uchar_t *)ep);
8877c478bd9Sstevel@tonic-gate break;
8887c478bd9Sstevel@tonic-gate case ANY:
889b127ac41SPhilip Kirk pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
8907c478bd9Sstevel@tonic-gate (uchar_t *)ep);
891b127ac41SPhilip Kirk pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
8927c478bd9Sstevel@tonic-gate (uchar_t *)ep);
8937c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
8947c478bd9Sstevel@tonic-gate break;
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate * Emit code to compare the network part of
9007c478bd9Sstevel@tonic-gate * an IP address.
9017c478bd9Sstevel@tonic-gate */
9027c478bd9Sstevel@tonic-gate static void
pf_netaddr_match(which,netname)9037c478bd9Sstevel@tonic-gate pf_netaddr_match(which, netname)
9047c478bd9Sstevel@tonic-gate enum direction which;
9057c478bd9Sstevel@tonic-gate char *netname;
9067c478bd9Sstevel@tonic-gate {
9077c478bd9Sstevel@tonic-gate uint_t addr;
9087c478bd9Sstevel@tonic-gate uint_t mask = 0xff000000;
9097c478bd9Sstevel@tonic-gate struct netent *np;
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate if (isdigit(*netname)) {
9127c478bd9Sstevel@tonic-gate addr = inet_network(netname);
9137c478bd9Sstevel@tonic-gate } else {
9147c478bd9Sstevel@tonic-gate np = getnetbyname(netname);
9157c478bd9Sstevel@tonic-gate if (np == NULL)
9167c478bd9Sstevel@tonic-gate pr_err("net %s not known", netname);
9177c478bd9Sstevel@tonic-gate addr = np->n_net;
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate /*
9217c478bd9Sstevel@tonic-gate * Left justify the address and figure
9227c478bd9Sstevel@tonic-gate * out a mask based on the supplied address.
9237c478bd9Sstevel@tonic-gate * Set the mask according to the number of zero
9247c478bd9Sstevel@tonic-gate * low-order bytes.
9257c478bd9Sstevel@tonic-gate * Note: this works only for whole octet masks.
9267c478bd9Sstevel@tonic-gate */
9277c478bd9Sstevel@tonic-gate if (addr) {
9287c478bd9Sstevel@tonic-gate while ((addr & ~mask) != 0) {
9297c478bd9Sstevel@tonic-gate mask |= (mask >> 8);
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate
933605445d5Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
934605445d5Sdg199075
9357c478bd9Sstevel@tonic-gate switch (which) {
9367c478bd9Sstevel@tonic-gate case TO:
9377c478bd9Sstevel@tonic-gate pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
9387c478bd9Sstevel@tonic-gate break;
9397c478bd9Sstevel@tonic-gate case FROM:
9407c478bd9Sstevel@tonic-gate pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
9417c478bd9Sstevel@tonic-gate break;
9427c478bd9Sstevel@tonic-gate case ANY:
9437c478bd9Sstevel@tonic-gate pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
9447c478bd9Sstevel@tonic-gate pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
9457c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
9467c478bd9Sstevel@tonic-gate break;
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate
950605445d5Sdg199075 /*
951b127ac41SPhilip Kirk * Emit code to match on src or destination zoneid.
952b127ac41SPhilip Kirk * The zoneid passed in is in network byte order.
953b127ac41SPhilip Kirk */
954b127ac41SPhilip Kirk static void
pf_match_zone(enum direction which,uint32_t zoneid)9550a0e9771SDarren Reed pf_match_zone(enum direction which, uint32_t zoneid)
956b127ac41SPhilip Kirk {
957b127ac41SPhilip Kirk if (dl.dl_type != DL_IPNET)
958b127ac41SPhilip Kirk pr_err("zone filter option unsupported on media");
959b127ac41SPhilip Kirk
960b127ac41SPhilip Kirk switch (which) {
961b127ac41SPhilip Kirk case TO:
962b127ac41SPhilip Kirk pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
963b127ac41SPhilip Kirk break;
964b127ac41SPhilip Kirk case FROM:
965b127ac41SPhilip Kirk pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
966b127ac41SPhilip Kirk break;
967b127ac41SPhilip Kirk case ANY:
968b127ac41SPhilip Kirk pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
969b127ac41SPhilip Kirk pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
970b127ac41SPhilip Kirk pf_emit(ENF_OR);
971b127ac41SPhilip Kirk break;
972b127ac41SPhilip Kirk }
973b127ac41SPhilip Kirk }
974b127ac41SPhilip Kirk
975b127ac41SPhilip Kirk /*
976605445d5Sdg199075 * A helper function to keep the code to emit instructions
977605445d5Sdg199075 * to change the offset register in one place.
978605445d5Sdg199075 *
979605445d5Sdg199075 * INPUTS: offset - An value representing an offset in 16-bit
980605445d5Sdg199075 * words.
981605445d5Sdg199075 * OUTPUTS: If there is enough room in the storage for the
982605445d5Sdg199075 * packet filtering program, instructions to load
983605445d5Sdg199075 * a constant to the offset register. Otherwise,
984605445d5Sdg199075 * nothing.
985605445d5Sdg199075 */
986605445d5Sdg199075 static void
pf_emit_load_offset(uint_t offset)987605445d5Sdg199075 pf_emit_load_offset(uint_t offset)
988605445d5Sdg199075 {
989605445d5Sdg199075 pf_emit(ENF_LOAD_OFFSET | ENF_NOP);
990605445d5Sdg199075 pf_emit(offset);
991605445d5Sdg199075 }
992605445d5Sdg199075
993605445d5Sdg199075 /*
994605445d5Sdg199075 * Clear pfmod's offset register.
995605445d5Sdg199075 *
996605445d5Sdg199075 * INPUTS: none
997605445d5Sdg199075 * OUTPUTS: Instructions to clear the offset register if
998605445d5Sdg199075 * there is enough space remaining in the packet
999605445d5Sdg199075 * filtering program structure's storage, and
1000605445d5Sdg199075 * the last thing done to the offset register was
1001605445d5Sdg199075 * not clearing the offset register. Otherwise,
1002605445d5Sdg199075 * nothing.
1003605445d5Sdg199075 */
1004605445d5Sdg199075 static void
pf_clear_offset_register()1005605445d5Sdg199075 pf_clear_offset_register()
1006605445d5Sdg199075 {
1007605445d5Sdg199075 if (last_offset_operation != (void*)pf_clear_offset_register) {
1008605445d5Sdg199075 pf_emit_load_offset(0);
1009605445d5Sdg199075 last_offset_operation = (void*)pf_clear_offset_register;
1010605445d5Sdg199075 }
1011605445d5Sdg199075 }
1012605445d5Sdg199075
1013605445d5Sdg199075 /*
1014605445d5Sdg199075 * This function will issue opcodes to check if a packet
1015605445d5Sdg199075 * is VLAN tagged, and if so, update the offset register
1016605445d5Sdg199075 * with the appropriate offset.
1017605445d5Sdg199075 *
1018605445d5Sdg199075 * Note that if the packet is not VLAN tagged, then the offset
1019605445d5Sdg199075 * register will be cleared.
1020605445d5Sdg199075 *
1021605445d5Sdg199075 * If the interface type is not an ethernet type, then this
1022605445d5Sdg199075 * function returns without doing anything.
1023605445d5Sdg199075 *
1024605445d5Sdg199075 * If the last attempt to change the offset register occured because
1025605445d5Sdg199075 * of a call to this function that was called with the same offset,
1026605445d5Sdg199075 * then we don't issue packet filtering instructions.
1027605445d5Sdg199075 *
1028605445d5Sdg199075 * INPUTS: offset - an offset in 16 bit words. The function
1029605445d5Sdg199075 * will set the offset register to this
1030605445d5Sdg199075 * value if the packet is VLAN tagged.
1031605445d5Sdg199075 * OUTPUTS: If the conditions are met, packet filtering instructions.
1032605445d5Sdg199075 */
1033605445d5Sdg199075 static void
pf_check_vlan_tag(uint_t offset)1034605445d5Sdg199075 pf_check_vlan_tag(uint_t offset)
1035605445d5Sdg199075 {
1036605445d5Sdg199075 static uint_t last_offset = 0;
1037605445d5Sdg199075
1038605445d5Sdg199075 if ((interface->mac_type == DL_ETHER ||
1039605445d5Sdg199075 interface->mac_type == DL_CSMACD) &&
1040605445d5Sdg199075 (last_offset_operation != (void*)pf_check_vlan_tag ||
1041605445d5Sdg199075 last_offset != offset)) {
1042605445d5Sdg199075 /*
1043605445d5Sdg199075 * First thing is to clear the offset register.
1044605445d5Sdg199075 * We don't know what state it is in, and if it
1045605445d5Sdg199075 * is not zero, then we have no idea what we load
1046605445d5Sdg199075 * when we execute ENF_PUSHWORD.
1047605445d5Sdg199075 */
1048605445d5Sdg199075 pf_clear_offset_register();
1049605445d5Sdg199075
1050605445d5Sdg199075 /*
1051605445d5Sdg199075 * Check the ethertype.
1052605445d5Sdg199075 */
1053b127ac41SPhilip Kirk pf_compare_value(dl.dl_link_type_offset, 2,
1054b127ac41SPhilip Kirk htons(ETHERTYPE_VLAN));
1055605445d5Sdg199075
1056605445d5Sdg199075 /*
1057605445d5Sdg199075 * And if it's not VLAN, don't load offset to the offset
1058605445d5Sdg199075 * register.
1059605445d5Sdg199075 */
1060605445d5Sdg199075 pf_emit(ENF_BRFL | ENF_NOP);
1061605445d5Sdg199075 pf_emit(3);
1062605445d5Sdg199075
1063605445d5Sdg199075 /*
1064605445d5Sdg199075 * Otherwise, load offset to the offset register.
1065605445d5Sdg199075 */
1066605445d5Sdg199075 pf_emit_load_offset(offset);
1067605445d5Sdg199075
1068605445d5Sdg199075 /*
1069605445d5Sdg199075 * Now get rid of the results of the comparison,
1070605445d5Sdg199075 * we don't want the results of the comparison to affect
1071605445d5Sdg199075 * other logic in the packet filtering program.
1072605445d5Sdg199075 */
1073605445d5Sdg199075 pf_emit(ENF_POP | ENF_NOP);
1074605445d5Sdg199075
1075605445d5Sdg199075 /*
1076605445d5Sdg199075 * Set the last operation at the end, or any time
1077605445d5Sdg199075 * after the call to pf_clear_offset because
1078605445d5Sdg199075 * pf_clear_offset uses it.
1079605445d5Sdg199075 */
1080605445d5Sdg199075 last_offset_operation = (void*)pf_check_vlan_tag;
1081605445d5Sdg199075 last_offset = offset;
1082605445d5Sdg199075 }
1083605445d5Sdg199075 }
1084605445d5Sdg199075
1085605445d5Sdg199075 /*
1086605445d5Sdg199075 * Utility function used to emit packet filtering code
1087605445d5Sdg199075 * to match an ethertype.
1088605445d5Sdg199075 *
1089605445d5Sdg199075 * INPUTS: ethertype - The ethertype we want to check for.
1090605445d5Sdg199075 * Don't call htons on the ethertype before
1091605445d5Sdg199075 * calling this function.
1092605445d5Sdg199075 * OUTPUTS: If there is sufficient storage available, packet
1093605445d5Sdg199075 * filtering code to check an ethertype. Otherwise,
1094605445d5Sdg199075 * nothing.
1095605445d5Sdg199075 */
1096605445d5Sdg199075 static void
pf_match_ethertype(uint_t ethertype)1097605445d5Sdg199075 pf_match_ethertype(uint_t ethertype)
1098605445d5Sdg199075 {
1099605445d5Sdg199075 /*
1100605445d5Sdg199075 * If the user wants to filter on ethertype VLAN,
1101605445d5Sdg199075 * then clear the offset register so that the offset
1102605445d5Sdg199075 * for ENF_PUSHWORD points to the right place in the
1103605445d5Sdg199075 * packet.
1104605445d5Sdg199075 *
1105605445d5Sdg199075 * Otherwise, call pf_check_vlan_tag to set the offset
1106605445d5Sdg199075 * register such that the contents of the offset register
1107605445d5Sdg199075 * plus the argument for ENF_PUSHWORD point to the right
1108605445d5Sdg199075 * part of the packet, whether or not the packet is VLAN
1109605445d5Sdg199075 * tagged. We call pf_check_vlan_tag with an offset of
1110605445d5Sdg199075 * two words because if the packet is VLAN tagged, we have
1111605445d5Sdg199075 * to move past the ethertype in the ethernet header, and
1112605445d5Sdg199075 * past the lower two octets of the VLAN header to get to
1113605445d5Sdg199075 * the ethertype in the VLAN header.
1114605445d5Sdg199075 */
1115605445d5Sdg199075 if (ethertype == ETHERTYPE_VLAN)
1116605445d5Sdg199075 pf_clear_offset_register();
1117605445d5Sdg199075 else
1118605445d5Sdg199075 pf_check_vlan_tag(2);
1119605445d5Sdg199075
1120b127ac41SPhilip Kirk pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype));
1121605445d5Sdg199075 }
1122605445d5Sdg199075
1123b127ac41SPhilip Kirk static void
pf_match_ipnettype(uint_t type)1124b127ac41SPhilip Kirk pf_match_ipnettype(uint_t type)
1125b127ac41SPhilip Kirk {
1126b127ac41SPhilip Kirk pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1127b127ac41SPhilip Kirk }
1128605445d5Sdg199075
1129b127ac41SPhilip Kirk static void
pf_match_ibtype(uint_t type)1130b127ac41SPhilip Kirk pf_match_ibtype(uint_t type)
1131b127ac41SPhilip Kirk {
1132b127ac41SPhilip Kirk pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1133b127ac41SPhilip Kirk }
1134605445d5Sdg199075
1135605445d5Sdg199075 /*
1136605445d5Sdg199075 * This function uses the table above to generate a
1137605445d5Sdg199075 * piece of a packet filtering program to check a transport
1138605445d5Sdg199075 * protocol type.
1139605445d5Sdg199075 *
1140605445d5Sdg199075 * INPUTS: tranport_protocol - the transport protocol we're
1141605445d5Sdg199075 * interested in.
1142605445d5Sdg199075 * OUTPUTS: If there is sufficient storage, then packet filtering
1143605445d5Sdg199075 * code to check a transport protocol type. Otherwise,
1144605445d5Sdg199075 * nothing.
1145605445d5Sdg199075 */
1146605445d5Sdg199075 static void
pf_check_transport_protocol(uint_t transport_protocol)1147605445d5Sdg199075 pf_check_transport_protocol(uint_t transport_protocol)
1148605445d5Sdg199075 {
1149041bde0aSSebastien Roy int i;
1150605445d5Sdg199075 uint_t number_of_matches = 0;
1151605445d5Sdg199075
1152041bde0aSSebastien Roy for (i = 0; dl.dl_trans_map_tbl[i].transport_protocol != -1; i++) {
1153605445d5Sdg199075 if (transport_protocol ==
1154041bde0aSSebastien Roy (uint_t)dl.dl_trans_map_tbl[i].transport_protocol) {
1155605445d5Sdg199075 number_of_matches++;
1156041bde0aSSebastien Roy dl.dl_match_fn(dl.dl_trans_map_tbl[i].network_protocol);
1157605445d5Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1158041bde0aSSebastien Roy pf_compare_value(dl.dl_trans_map_tbl[i].offset +
1159b127ac41SPhilip Kirk dl.dl_link_header_len, 1,
1160605445d5Sdg199075 transport_protocol);
1161605445d5Sdg199075 pf_emit(ENF_AND);
1162605445d5Sdg199075 if (number_of_matches > 1) {
1163605445d5Sdg199075 /*
1164605445d5Sdg199075 * Since we have two or more matches, in
1165605445d5Sdg199075 * order to have a correct and complete
1166605445d5Sdg199075 * program we need to OR the result of
1167605445d5Sdg199075 * each block of comparisons together.
1168605445d5Sdg199075 */
1169605445d5Sdg199075 pf_emit(ENF_OR);
1170605445d5Sdg199075 }
1171605445d5Sdg199075 }
1172605445d5Sdg199075 }
1173605445d5Sdg199075 }
1174605445d5Sdg199075
11757c478bd9Sstevel@tonic-gate static void
pf_matchfn(const char * proto)1176041bde0aSSebastien Roy pf_matchfn(const char *proto)
1177b127ac41SPhilip Kirk {
1178041bde0aSSebastien Roy int i;
1179041bde0aSSebastien Roy
1180041bde0aSSebastien Roy for (i = 0; dl.dl_net_map_tbl[i].nmt_val != -1; i++) {
1181041bde0aSSebastien Roy if (strcmp(proto, dl.dl_net_map_tbl[i].nmt_name) == 0) {
1182041bde0aSSebastien Roy dl.dl_match_fn(dl.dl_net_map_tbl[i].nmt_val);
1183041bde0aSSebastien Roy break;
1184041bde0aSSebastien Roy }
1185b127ac41SPhilip Kirk }
1186b127ac41SPhilip Kirk }
1187b127ac41SPhilip Kirk
1188b127ac41SPhilip Kirk static void
pf_primary()11897c478bd9Sstevel@tonic-gate pf_primary()
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate for (;;) {
11927c478bd9Sstevel@tonic-gate if (tokentype == FIELD)
11937c478bd9Sstevel@tonic-gate break;
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate if (EQ("ip")) {
1196b127ac41SPhilip Kirk pf_matchfn("ip");
11977c478bd9Sstevel@tonic-gate opstack++;
11987c478bd9Sstevel@tonic-gate next();
11997c478bd9Sstevel@tonic-gate break;
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate if (EQ("ip6")) {
1203b127ac41SPhilip Kirk pf_matchfn("ip6");
12047c478bd9Sstevel@tonic-gate opstack++;
12057c478bd9Sstevel@tonic-gate next();
12067c478bd9Sstevel@tonic-gate break;
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate if (EQ("pppoe")) {
1210b127ac41SPhilip Kirk pf_matchfn("pppoe");
1211605445d5Sdg199075 pf_match_ethertype(ETHERTYPE_PPPOES);
12127c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
12137c478bd9Sstevel@tonic-gate opstack++;
12147c478bd9Sstevel@tonic-gate next();
12157c478bd9Sstevel@tonic-gate break;
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate if (EQ("pppoed")) {
1219b127ac41SPhilip Kirk pf_matchfn("pppoed");
12207c478bd9Sstevel@tonic-gate opstack++;
12217c478bd9Sstevel@tonic-gate next();
12227c478bd9Sstevel@tonic-gate break;
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate if (EQ("pppoes")) {
1226b127ac41SPhilip Kirk pf_matchfn("pppoes");
12277c478bd9Sstevel@tonic-gate opstack++;
12287c478bd9Sstevel@tonic-gate next();
12297c478bd9Sstevel@tonic-gate break;
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate if (EQ("arp")) {
1233b127ac41SPhilip Kirk pf_matchfn("arp");
1234605445d5Sdg199075 opstack++;
1235605445d5Sdg199075 next();
1236605445d5Sdg199075 break;
1237605445d5Sdg199075 }
1238605445d5Sdg199075
1239605445d5Sdg199075 if (EQ("vlan")) {
1240b127ac41SPhilip Kirk pf_matchfn("vlan");
1241605445d5Sdg199075 pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2,
1242605445d5Sdg199075 0, VLAN_ID_MASK);
1243605445d5Sdg199075 pf_emit(ENF_AND);
1244605445d5Sdg199075 opstack++;
1245605445d5Sdg199075 next();
1246605445d5Sdg199075 break;
1247605445d5Sdg199075 }
1248605445d5Sdg199075
1249605445d5Sdg199075 if (EQ("vlan-id")) {
1250605445d5Sdg199075 next();
1251605445d5Sdg199075 if (tokentype != NUMBER)
1252605445d5Sdg199075 pr_err("VLAN ID expected");
1253b127ac41SPhilip Kirk pf_matchfn("vlan-id");
1254605445d5Sdg199075 pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
1255605445d5Sdg199075 VLAN_ID_MASK);
1256605445d5Sdg199075 pf_emit(ENF_AND);
12577c478bd9Sstevel@tonic-gate opstack++;
12587c478bd9Sstevel@tonic-gate next();
12597c478bd9Sstevel@tonic-gate break;
12607c478bd9Sstevel@tonic-gate }
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate if (EQ("rarp")) {
1263b127ac41SPhilip Kirk pf_matchfn("rarp");
12647c478bd9Sstevel@tonic-gate opstack++;
12657c478bd9Sstevel@tonic-gate next();
12667c478bd9Sstevel@tonic-gate break;
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate if (EQ("tcp")) {
1270605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_TCP);
12717c478bd9Sstevel@tonic-gate opstack++;
12727c478bd9Sstevel@tonic-gate next();
12737c478bd9Sstevel@tonic-gate break;
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate if (EQ("udp")) {
1277605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_UDP);
12787c478bd9Sstevel@tonic-gate opstack++;
12797c478bd9Sstevel@tonic-gate next();
12807c478bd9Sstevel@tonic-gate break;
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate if (EQ("ospf")) {
1284605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_OSPF);
12857c478bd9Sstevel@tonic-gate opstack++;
12867c478bd9Sstevel@tonic-gate next();
12877c478bd9Sstevel@tonic-gate break;
12887c478bd9Sstevel@tonic-gate }
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate if (EQ("sctp")) {
1292605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_SCTP);
12937c478bd9Sstevel@tonic-gate opstack++;
12947c478bd9Sstevel@tonic-gate next();
12957c478bd9Sstevel@tonic-gate break;
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate if (EQ("icmp")) {
1299605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_ICMP);
13007c478bd9Sstevel@tonic-gate opstack++;
13017c478bd9Sstevel@tonic-gate next();
13027c478bd9Sstevel@tonic-gate break;
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate
13057c478bd9Sstevel@tonic-gate if (EQ("icmp6")) {
1306605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_ICMPV6);
13077c478bd9Sstevel@tonic-gate opstack++;
13087c478bd9Sstevel@tonic-gate next();
13097c478bd9Sstevel@tonic-gate break;
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate if (EQ("ip-in-ip")) {
1313605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_ENCAP);
13147c478bd9Sstevel@tonic-gate opstack++;
13157c478bd9Sstevel@tonic-gate next();
13167c478bd9Sstevel@tonic-gate break;
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate
13197c478bd9Sstevel@tonic-gate if (EQ("esp")) {
1320605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_ESP);
13217c478bd9Sstevel@tonic-gate opstack++;
13227c478bd9Sstevel@tonic-gate next();
13237c478bd9Sstevel@tonic-gate break;
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate
13267c478bd9Sstevel@tonic-gate if (EQ("ah")) {
1327605445d5Sdg199075 pf_check_transport_protocol(IPPROTO_AH);
13287c478bd9Sstevel@tonic-gate opstack++;
13297c478bd9Sstevel@tonic-gate next();
13307c478bd9Sstevel@tonic-gate break;
13317c478bd9Sstevel@tonic-gate }
13327c478bd9Sstevel@tonic-gate
13337c478bd9Sstevel@tonic-gate if (EQ("(")) {
13347c478bd9Sstevel@tonic-gate inBrace++;
13357c478bd9Sstevel@tonic-gate next();
13367c478bd9Sstevel@tonic-gate pf_expression();
13377c478bd9Sstevel@tonic-gate if (EQ(")")) {
13387c478bd9Sstevel@tonic-gate if (inBrace)
13397c478bd9Sstevel@tonic-gate inBraceOR--;
13407c478bd9Sstevel@tonic-gate inBrace--;
13417c478bd9Sstevel@tonic-gate next();
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate break;
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate
13467c478bd9Sstevel@tonic-gate if (EQ("to") || EQ("dst")) {
13477c478bd9Sstevel@tonic-gate dir = TO;
13487c478bd9Sstevel@tonic-gate next();
13497c478bd9Sstevel@tonic-gate continue;
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate
13527c478bd9Sstevel@tonic-gate if (EQ("from") || EQ("src")) {
13537c478bd9Sstevel@tonic-gate dir = FROM;
13547c478bd9Sstevel@tonic-gate next();
13557c478bd9Sstevel@tonic-gate continue;
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate
13587c478bd9Sstevel@tonic-gate if (EQ("ether")) {
13597c478bd9Sstevel@tonic-gate eaddr = 1;
13607c478bd9Sstevel@tonic-gate next();
13617c478bd9Sstevel@tonic-gate continue;
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate if (EQ("inet")) {
13657c478bd9Sstevel@tonic-gate next();
13667c478bd9Sstevel@tonic-gate if (EQ("host"))
13677c478bd9Sstevel@tonic-gate next();
13687c478bd9Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP)
13697c478bd9Sstevel@tonic-gate pr_err("host/IPv4 addr expected after inet");
13707c478bd9Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_ONLY);
13717c478bd9Sstevel@tonic-gate opstack++;
13727c478bd9Sstevel@tonic-gate next();
13737c478bd9Sstevel@tonic-gate break;
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate if (EQ("inet6")) {
13777c478bd9Sstevel@tonic-gate next();
13787c478bd9Sstevel@tonic-gate if (EQ("host"))
13797c478bd9Sstevel@tonic-gate next();
13807c478bd9Sstevel@tonic-gate if (tokentype != ALPHA && tokentype != ADDR_IP6)
13817c478bd9Sstevel@tonic-gate pr_err("host/IPv6 addr expected after inet6");
13827c478bd9Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV6_ONLY);
13837c478bd9Sstevel@tonic-gate opstack++;
13847c478bd9Sstevel@tonic-gate next();
13857c478bd9Sstevel@tonic-gate break;
13867c478bd9Sstevel@tonic-gate }
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate if (EQ("proto")) {
13897c478bd9Sstevel@tonic-gate next();
13907c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
13917c478bd9Sstevel@tonic-gate pr_err("IP proto type expected");
1392605445d5Sdg199075 pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
13930990bc30Sdg199075 pf_compare_value(
1394b127ac41SPhilip Kirk IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1,
13950990bc30Sdg199075 tokenval);
13967c478bd9Sstevel@tonic-gate opstack++;
13977c478bd9Sstevel@tonic-gate next();
13987c478bd9Sstevel@tonic-gate break;
13997c478bd9Sstevel@tonic-gate }
14007c478bd9Sstevel@tonic-gate
14017c478bd9Sstevel@tonic-gate if (EQ("broadcast")) {
1402605445d5Sdg199075 pf_clear_offset_register();
1403b127ac41SPhilip Kirk pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff);
14047c478bd9Sstevel@tonic-gate opstack++;
14057c478bd9Sstevel@tonic-gate next();
14067c478bd9Sstevel@tonic-gate break;
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate if (EQ("multicast")) {
1410605445d5Sdg199075 pf_clear_offset_register();
1411b127ac41SPhilip Kirk pf_compare_value_mask(
1412b127ac41SPhilip Kirk dl.dl_link_dest_offset, 1, 0x01, 0x01);
14137c478bd9Sstevel@tonic-gate opstack++;
14147c478bd9Sstevel@tonic-gate next();
14157c478bd9Sstevel@tonic-gate break;
14167c478bd9Sstevel@tonic-gate }
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate if (EQ("ethertype")) {
14197c478bd9Sstevel@tonic-gate next();
14207c478bd9Sstevel@tonic-gate if (tokentype != NUMBER)
14217c478bd9Sstevel@tonic-gate pr_err("ether type expected");
1422605445d5Sdg199075 pf_match_ethertype(tokenval);
14237c478bd9Sstevel@tonic-gate opstack++;
14247c478bd9Sstevel@tonic-gate next();
14257c478bd9Sstevel@tonic-gate break;
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
14297c478bd9Sstevel@tonic-gate if (EQ("dstnet"))
14307c478bd9Sstevel@tonic-gate dir = TO;
14317c478bd9Sstevel@tonic-gate else if (EQ("srcnet"))
14327c478bd9Sstevel@tonic-gate dir = FROM;
14337c478bd9Sstevel@tonic-gate next();
14347c478bd9Sstevel@tonic-gate pf_netaddr_match(dir, token);
14357c478bd9Sstevel@tonic-gate dir = ANY;
14367c478bd9Sstevel@tonic-gate opstack++;
14377c478bd9Sstevel@tonic-gate next();
14387c478bd9Sstevel@tonic-gate break;
14397c478bd9Sstevel@tonic-gate }
14407c478bd9Sstevel@tonic-gate
1441b127ac41SPhilip Kirk if (EQ("zone")) {
1442b127ac41SPhilip Kirk next();
1443b127ac41SPhilip Kirk if (tokentype != NUMBER)
1444b127ac41SPhilip Kirk pr_err("zoneid expected after inet");
14450a0e9771SDarren Reed pf_match_zone(dir, BE_32((uint32_t)(tokenval)));
1446b127ac41SPhilip Kirk opstack++;
1447b127ac41SPhilip Kirk next();
1448b127ac41SPhilip Kirk break;
1449b127ac41SPhilip Kirk }
1450b127ac41SPhilip Kirk
14517c478bd9Sstevel@tonic-gate /*
14527c478bd9Sstevel@tonic-gate * Give up on anything that's obviously
14537c478bd9Sstevel@tonic-gate * not a primary.
14547c478bd9Sstevel@tonic-gate */
14557c478bd9Sstevel@tonic-gate if (EQ("and") || EQ("or") ||
14567c478bd9Sstevel@tonic-gate EQ("not") || EQ("decnet") || EQ("apple") ||
14577c478bd9Sstevel@tonic-gate EQ("length") || EQ("less") || EQ("greater") ||
14587c478bd9Sstevel@tonic-gate EQ("port") || EQ("srcport") || EQ("dstport") ||
14597c478bd9Sstevel@tonic-gate EQ("rpc") || EQ("gateway") || EQ("nofrag") ||
1460d04ccbb3Scarlsonj EQ("bootp") || EQ("dhcp") || EQ("dhcp6") ||
1461d04ccbb3Scarlsonj EQ("slp") || EQ("ldap")) {
14627c478bd9Sstevel@tonic-gate break;
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate if (EQ("host") || EQ("between") ||
14667c478bd9Sstevel@tonic-gate tokentype == ALPHA || /* assume its a hostname */
14677c478bd9Sstevel@tonic-gate tokentype == ADDR_IP ||
14687c478bd9Sstevel@tonic-gate tokentype == ADDR_IP6 ||
14697c478bd9Sstevel@tonic-gate tokentype == ADDR_ETHER) {
14707c478bd9Sstevel@tonic-gate if (EQ("host") || EQ("between"))
14717c478bd9Sstevel@tonic-gate next();
14727c478bd9Sstevel@tonic-gate if (eaddr || tokentype == ADDR_ETHER) {
14737c478bd9Sstevel@tonic-gate pf_etheraddr_match(dir, token);
14747c478bd9Sstevel@tonic-gate } else if (tokentype == ALPHA) {
14757c478bd9Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_AND_IPV6);
14767c478bd9Sstevel@tonic-gate } else if (tokentype == ADDR_IP) {
14777c478bd9Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV4_ONLY);
14787c478bd9Sstevel@tonic-gate } else {
14797c478bd9Sstevel@tonic-gate pf_ipaddr_match(dir, token, IPV6_ONLY);
14807c478bd9Sstevel@tonic-gate }
14817c478bd9Sstevel@tonic-gate dir = ANY;
14827c478bd9Sstevel@tonic-gate eaddr = 0;
14837c478bd9Sstevel@tonic-gate opstack++;
14847c478bd9Sstevel@tonic-gate next();
14857c478bd9Sstevel@tonic-gate break;
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate
14887c478bd9Sstevel@tonic-gate break; /* unknown token */
14897c478bd9Sstevel@tonic-gate }
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate
14927c478bd9Sstevel@tonic-gate static void
pf_alternation()14937c478bd9Sstevel@tonic-gate pf_alternation()
14947c478bd9Sstevel@tonic-gate {
14957c478bd9Sstevel@tonic-gate int s = opstack;
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate pf_primary();
14987c478bd9Sstevel@tonic-gate for (;;) {
14997c478bd9Sstevel@tonic-gate if (EQ("and"))
15007c478bd9Sstevel@tonic-gate next();
15017c478bd9Sstevel@tonic-gate pf_primary();
15027c478bd9Sstevel@tonic-gate if (opstack != s + 2)
15037c478bd9Sstevel@tonic-gate break;
15047c478bd9Sstevel@tonic-gate pf_emit(ENF_AND);
15057c478bd9Sstevel@tonic-gate opstack--;
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate static void
pf_expression()15107c478bd9Sstevel@tonic-gate pf_expression()
15117c478bd9Sstevel@tonic-gate {
15127c478bd9Sstevel@tonic-gate pf_alternation();
15137c478bd9Sstevel@tonic-gate while (EQ("or") || EQ(",")) {
15147c478bd9Sstevel@tonic-gate if (inBrace)
15157c478bd9Sstevel@tonic-gate inBraceOR++;
15167c478bd9Sstevel@tonic-gate else
15177c478bd9Sstevel@tonic-gate foundOR++;
15187c478bd9Sstevel@tonic-gate next();
15197c478bd9Sstevel@tonic-gate pf_alternation();
15207c478bd9Sstevel@tonic-gate pf_emit(ENF_OR);
15217c478bd9Sstevel@tonic-gate opstack--;
15227c478bd9Sstevel@tonic-gate }
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate /*
15267c478bd9Sstevel@tonic-gate * Attempt to compile the expression
15277c478bd9Sstevel@tonic-gate * in the string "e". If we can generate
15287c478bd9Sstevel@tonic-gate * pf code for it then return 1 - otherwise
15297c478bd9Sstevel@tonic-gate * return 0 and leave it up to the user-level
15307c478bd9Sstevel@tonic-gate * filter.
15317c478bd9Sstevel@tonic-gate */
15327c478bd9Sstevel@tonic-gate int
pf_compile(e,print)15337c478bd9Sstevel@tonic-gate pf_compile(e, print)
15347c478bd9Sstevel@tonic-gate char *e;
15357c478bd9Sstevel@tonic-gate int print;
15367c478bd9Sstevel@tonic-gate {
15377c478bd9Sstevel@tonic-gate char *argstr;
15387c478bd9Sstevel@tonic-gate char *sav_str, *ptr, *sav_ptr;
15397c478bd9Sstevel@tonic-gate int inBr = 0, aheadOR = 0;
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate argstr = strdup(e);
15427c478bd9Sstevel@tonic-gate sav_str = e;
15437c478bd9Sstevel@tonic-gate tkp = argstr;
15447c478bd9Sstevel@tonic-gate dir = ANY;
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate pfp = &pf.Pf_Filter[0];
15477c478bd9Sstevel@tonic-gate if (setjmp(env)) {
15487c478bd9Sstevel@tonic-gate return (0);
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate /*
15527c478bd9Sstevel@tonic-gate * Set media specific packet offsets that this code uses.
15537c478bd9Sstevel@tonic-gate */
1554b127ac41SPhilip Kirk if (interface->mac_type == DL_ETHER) {
1555b127ac41SPhilip Kirk dl.dl_type = DL_ETHER;
1556b127ac41SPhilip Kirk dl.dl_match_fn = pf_match_ethertype;
1557041bde0aSSebastien Roy dl.dl_trans_map_tbl = ether_transport_mapping_table;
1558041bde0aSSebastien Roy dl.dl_net_map_tbl = ether_network_mapping_table;
1559b127ac41SPhilip Kirk dl.dl_link_header_len = 14;
1560b127ac41SPhilip Kirk dl.dl_link_type_offset = 12;
1561b127ac41SPhilip Kirk dl.dl_link_dest_offset = 0;
1562b127ac41SPhilip Kirk dl.dl_link_src_offset = 6;
1563b127ac41SPhilip Kirk dl.dl_link_addr_len = 6;
1564b127ac41SPhilip Kirk }
1565b127ac41SPhilip Kirk
15667c478bd9Sstevel@tonic-gate if (interface->mac_type == DL_IB) {
1567b127ac41SPhilip Kirk dl.dl_type = DL_IB;
1568b127ac41SPhilip Kirk dl.dl_link_header_len = 4;
1569b127ac41SPhilip Kirk dl.dl_link_type_offset = 0;
1570b127ac41SPhilip Kirk dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1571b127ac41SPhilip Kirk dl.dl_link_addr_len = 20;
1572b127ac41SPhilip Kirk dl.dl_match_fn = pf_match_ibtype;
1573041bde0aSSebastien Roy dl.dl_trans_map_tbl = ib_transport_mapping_table;
1574041bde0aSSebastien Roy dl.dl_net_map_tbl = ib_network_mapping_table;
1575b127ac41SPhilip Kirk }
1576b127ac41SPhilip Kirk
1577b127ac41SPhilip Kirk if (interface->mac_type == DL_IPNET) {
1578b127ac41SPhilip Kirk dl.dl_type = DL_IPNET;
1579b127ac41SPhilip Kirk dl.dl_link_header_len = 24;
1580b127ac41SPhilip Kirk dl.dl_link_type_offset = 0;
1581b127ac41SPhilip Kirk dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1582b127ac41SPhilip Kirk dl.dl_link_addr_len = -1;
1583b127ac41SPhilip Kirk dl.dl_match_fn = pf_match_ipnettype;
1584041bde0aSSebastien Roy dl.dl_trans_map_tbl = ipnet_transport_mapping_table;
1585041bde0aSSebastien Roy dl.dl_net_map_tbl = ipnet_network_mapping_table;
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate
15887c478bd9Sstevel@tonic-gate next();
15897c478bd9Sstevel@tonic-gate pf_expression();
15907c478bd9Sstevel@tonic-gate
15917c478bd9Sstevel@tonic-gate if (tokentype != EOL) {
15927c478bd9Sstevel@tonic-gate /*
15937c478bd9Sstevel@tonic-gate * The idea here is to do as much filtering as possible in
15947c478bd9Sstevel@tonic-gate * the kernel. So even if we find a token we don't understand,
15957c478bd9Sstevel@tonic-gate * we try to see if we can still set up a portion of the filter
15967c478bd9Sstevel@tonic-gate * in the kernel and use the userland filter to filter the
15977c478bd9Sstevel@tonic-gate * remaining stuff. Obviously, if our filter expression is of
15987c478bd9Sstevel@tonic-gate * type A AND B, we can filter A in kernel and then apply B
15997c478bd9Sstevel@tonic-gate * to the packets that got through. The same is not true for
16007c478bd9Sstevel@tonic-gate * a filter of type A OR B. We can't apply A first and then B
16017c478bd9Sstevel@tonic-gate * on the packets filtered through A.
16027c478bd9Sstevel@tonic-gate *
16037c478bd9Sstevel@tonic-gate * (We need to keep track of the fact when we find an OR,
16047c478bd9Sstevel@tonic-gate * and the fact that we are inside brackets when we find OR.
16057c478bd9Sstevel@tonic-gate * The variable 'foundOR' tells us if there was an OR behind,
16067c478bd9Sstevel@tonic-gate * 'inBraceOR' tells us if we found an OR before we could find
16077c478bd9Sstevel@tonic-gate * the end brace i.e. ')', and variable 'aheadOR' checks if
16087c478bd9Sstevel@tonic-gate * there is an OR in the expression ahead. if either of these
16097c478bd9Sstevel@tonic-gate * cases become true, we can't split the filtering)
16107c478bd9Sstevel@tonic-gate */
16117c478bd9Sstevel@tonic-gate
16127c478bd9Sstevel@tonic-gate if (foundOR || inBraceOR) {
16137c478bd9Sstevel@tonic-gate /* FORGET IN KERNEL FILTERING */
16147c478bd9Sstevel@tonic-gate return (0);
16157c478bd9Sstevel@tonic-gate } else {
16167c478bd9Sstevel@tonic-gate
16177c478bd9Sstevel@tonic-gate /* CHECK IF NO OR AHEAD */
16187c478bd9Sstevel@tonic-gate sav_ptr = (char *)((uintptr_t)sav_str +
16197c478bd9Sstevel@tonic-gate (uintptr_t)sav_tkp -
16207c478bd9Sstevel@tonic-gate (uintptr_t)argstr);
16217c478bd9Sstevel@tonic-gate ptr = sav_ptr;
16227c478bd9Sstevel@tonic-gate while (*ptr != '\0') {
16237c478bd9Sstevel@tonic-gate switch (*ptr) {
16247c478bd9Sstevel@tonic-gate case '(':
16257c478bd9Sstevel@tonic-gate inBr++;
16267c478bd9Sstevel@tonic-gate break;
16277c478bd9Sstevel@tonic-gate case ')':
16287c478bd9Sstevel@tonic-gate inBr--;
16297c478bd9Sstevel@tonic-gate break;
16307c478bd9Sstevel@tonic-gate case 'o':
16317c478bd9Sstevel@tonic-gate case 'O':
16327c478bd9Sstevel@tonic-gate if ((*(ptr + 1) == 'R' ||
16337c478bd9Sstevel@tonic-gate *(ptr + 1) == 'r') && !inBr)
16347c478bd9Sstevel@tonic-gate aheadOR = 1;
16357c478bd9Sstevel@tonic-gate break;
16367c478bd9Sstevel@tonic-gate case ',':
16377c478bd9Sstevel@tonic-gate if (!inBr)
16387c478bd9Sstevel@tonic-gate aheadOR = 1;
16397c478bd9Sstevel@tonic-gate break;
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate ptr++;
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate if (!aheadOR) {
16447c478bd9Sstevel@tonic-gate /* NO OR AHEAD, SPLIT UP THE FILTERING */
16457c478bd9Sstevel@tonic-gate pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
16467c478bd9Sstevel@tonic-gate pf.Pf_Priority = 5;
16477c478bd9Sstevel@tonic-gate if (print) {
16487c478bd9Sstevel@tonic-gate pf_codeprint(&pf.Pf_Filter[0],
16497c478bd9Sstevel@tonic-gate pf.Pf_FilterLen);
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate compile(sav_ptr, print);
16527c478bd9Sstevel@tonic-gate return (2);
16537c478bd9Sstevel@tonic-gate } else
16547c478bd9Sstevel@tonic-gate return (0);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
16597c478bd9Sstevel@tonic-gate pf.Pf_Priority = 5; /* unimportant, so long as > 2 */
16607c478bd9Sstevel@tonic-gate if (print) {
16617c478bd9Sstevel@tonic-gate pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen);
16627c478bd9Sstevel@tonic-gate }
16637c478bd9Sstevel@tonic-gate return (1);
16647c478bd9Sstevel@tonic-gate }
1665