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