]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_fw2_compat.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / bsd / netinet / ip_fw2_compat.c
1 /*
2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* IPFW2 Backward Compatibility */
29
30 /* Convert to and from IPFW2 structures. */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37
38 #include <sys/types.h>
39
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/ip.h>
44 #include <netinet/ip_icmp.h>
45 #include <netinet/ip_fw.h>
46 #include <netinet/tcp.h>
47
48 #include "ip_fw2_compat.h"
49
50 #define FW2_DEBUG_VERBOSE 0
51
52 /*
53 * _s_x is a structure that stores a string <-> token pairs, used in
54 * various places in the parser. Entries are stored in arrays,
55 * with an entry with s=NULL as terminator.
56 * The search routines are match_token() and match_value().
57 * Often, an element with x=0 contains an error string.
58 *
59 */
60 struct _s_x {
61 char const *s;
62 int x;
63 };
64
65 #define NO_VERSION_STR "IP_FW_VERSION_NONE"
66 #define VERSION_ZERO_STR "IP_FW_VERSION_0"
67 #define VERSION_ONE_STR "IP_FW_VERSION_1"
68 #define CURRENT_API_VERSION_STR "IP_FW_CURRENT_API_VERSION"
69
70 #if FW2_DEBUG_VERBOSE
71
72 static struct _s_x f_tcpflags[] = {
73 { "syn", TH_SYN },
74 { "fin", TH_FIN },
75 { "ack", TH_ACK },
76 { "psh", TH_PUSH },
77 { "rst", TH_RST },
78 { "urg", TH_URG },
79 { "tcp flag", 0 },
80 { NULL, 0 }
81 };
82
83 static struct _s_x f_tcpopts[] = {
84 { "mss", IP_FW_TCPOPT_MSS },
85 { "maxseg", IP_FW_TCPOPT_MSS },
86 { "window", IP_FW_TCPOPT_WINDOW },
87 { "sack", IP_FW_TCPOPT_SACK },
88 { "ts", IP_FW_TCPOPT_TS },
89 { "timestamp", IP_FW_TCPOPT_TS },
90 { "cc", IP_FW_TCPOPT_CC },
91 { "tcp option", 0 },
92 { NULL, 0 }
93 };
94
95
96 /*
97 * IP options span the range 0 to 255 so we need to remap them
98 * (though in fact only the low 5 bits are significant).
99 */
100 static struct _s_x f_ipopts[] = {
101 { "ssrr", IP_FW_IPOPT_SSRR},
102 { "lsrr", IP_FW_IPOPT_LSRR},
103 { "rr", IP_FW_IPOPT_RR},
104 { "ts", IP_FW_IPOPT_TS},
105 { "ip option", 0 },
106 { NULL, 0 }
107 };
108
109 static struct _s_x f_iptos[] = {
110 { "lowdelay", IPTOS_LOWDELAY},
111 { "throughput", IPTOS_THROUGHPUT},
112 { "reliability", IPTOS_RELIABILITY},
113 { "mincost", IPTOS_MINCOST},
114 { "congestion", IPTOS_CE},
115 { "ecntransport", IPTOS_ECT},
116 { "ip tos option", 0},
117 { NULL, 0 }
118 };
119
120 static struct _s_x limit_masks[] = {
121 {"all", DYN_SRC_ADDR | DYN_SRC_PORT | DYN_DST_ADDR | DYN_DST_PORT},
122 {"src-addr", DYN_SRC_ADDR},
123 {"src-port", DYN_SRC_PORT},
124 {"dst-addr", DYN_DST_ADDR},
125 {"dst-port", DYN_DST_PORT},
126 {NULL, 0}
127 };
128
129 #endif /* !FW2_DEBUG_VERBOSE */
130
131 #if 0 /* version #1 */
132
133 static void
134 ipfw_print_fw_flags(u_int flags)
135 {
136 /* print action */
137 switch (flags & IP_FW_F_COMMAND_COMPAT) {
138 case IP_FW_F_ACCEPT_COMPAT:
139 printf("IP_FW_F_ACCEPT_COMPAT\n");
140 break;
141 case IP_FW_F_COUNT_COMPAT:
142 printf("IP_FW_F_COUNT_COMPAT\n");
143 break;
144 case IP_FW_F_PIPE_COMPAT:
145 printf("IP_FW_F_PIPE_COMPAT\n");
146 break;
147 case IP_FW_F_QUEUE_COMPAT:
148 printf("IP_FW_F_QUEUE_COMPAT\n");
149 break;
150 case IP_FW_F_SKIPTO_COMPAT:
151 printf("IP_FW_F_SKIPTO_COMPAT\n");
152 break;
153 case IP_FW_F_DIVERT_COMPAT:
154 printf("IP_FW_F_DIVERT_COMPAT\n");
155 break;
156 case IP_FW_F_TEE_COMPAT:
157 printf("IP_FW_F_TEE_COMPAT\n");
158 break;
159 case IP_FW_F_FWD_COMPAT:
160 printf("IP_FW_F_FWD_COMPAT\n");
161 break;
162 case IP_FW_F_DENY_COMPAT:
163 printf("IP_FW_F_DENY_COMPAT\n");
164 break;
165 case IP_FW_F_REJECT_COMPAT:
166 printf("IP_FW_F_REJECT_COMPAT\n");
167 break;
168 case IP_FW_F_CHECK_S_COMPAT:
169 printf("IP_FW_F_CHECK_S_COMPAT\n");
170 break;
171 default:
172 printf("No action given\n");
173 break;
174 }
175
176 /* print commands */
177 if (flags & IP_FW_F_IN_COMPAT) {
178 printf("IP_FW_F_IN_COMPAT\n");
179 }
180 if (flags & IP_FW_F_OUT_COMPAT) {
181 printf("IP_FW_F_OUT_COMPAT\n");
182 }
183 if (flags & IP_FW_F_IIFACE_COMPAT) {
184 printf("IP_FW_F_IIFACE_COMPAT\n");
185 }
186 if (flags & IP_FW_F_OIFACE_COMPAT) {
187 printf("IP_FW_F_OIFACE_COMPAT\n");
188 }
189 if (flags & IP_FW_F_PRN_COMPAT) {
190 printf("IP_FW_F_PRN_COMPAT\n");
191 }
192 if (flags & IP_FW_F_SRNG_COMPAT) {
193 printf("IP_FW_F_SRNG_COMPAT\n");
194 }
195 if (flags & IP_FW_F_DRNG_COMPAT) {
196 printf("IP_FW_F_DRNG_COMPAT\n");
197 }
198 if (flags & IP_FW_F_FRAG_COMPAT) {
199 printf("IP_FW_F_FRAG_COMPAT\n");
200 }
201 if (flags & IP_FW_F_IIFNAME_COMPAT) {
202 printf("IP_FW_F_IIFNAME_COMPAT\n");
203 }
204 if (flags & IP_FW_F_OIFNAME_COMPAT) {
205 printf("IP_FW_F_OIFNAME_COMPAT\n");
206 }
207 if (flags & IP_FW_F_INVSRC_COMPAT) {
208 printf("IP_FW_F_INVSRC_COMPAT\n");
209 }
210 if (flags & IP_FW_F_INVDST_COMPAT) {
211 printf("IP_FW_F_INVDST_COMPAT\n");
212 }
213 if (flags & IP_FW_F_ICMPBIT_COMPAT) {
214 printf("IP_FW_F_ICMPBIT_COMPAT\n");
215 }
216 if (flags & IP_FW_F_UID_COMPAT) {
217 printf("IP_FW_F_UID_COMPAT\n");
218 }
219 if (flags & IP_FW_F_RND_MATCH_COMPAT) {
220 printf("IP_FW_F_RND_MATCH_COMPAT\n");
221 }
222 if (flags & IP_FW_F_SMSK_COMPAT) {
223 printf("IP_FW_F_SMSK_COMPAT\n");
224 }
225 if (flags & IP_FW_F_DMSK_COMPAT) {
226 printf("IP_FW_F_DMSK_COMPAT\n");
227 }
228 if (flags & IP_FW_BRIDGED_COMPAT) {
229 printf("IP_FW_BRIDGED_COMPAT\n");
230 }
231 if (flags & IP_FW_F_KEEP_S_COMPAT) {
232 printf("IP_FW_F_KEEP_S_COMPAT\n");
233 }
234 if (flags & IP_FW_F_CHECK_S_COMPAT) {
235 printf("IP_FW_F_CHECK_S_COMPAT\n");
236 }
237 if (flags & IP_FW_F_SME_COMPAT) {
238 printf("IP_FW_F_SME_COMPAT\n");
239 }
240 if (flags & IP_FW_F_DME_COMPAT) {
241 printf("IP_FW_F_DME_COMPAT\n");
242 }
243 }
244
245 static void
246 print_fw_version(u_int32_t api_version)
247 {
248 switch (api_version) {
249 case IP_FW_VERSION_0:
250 printf("Version: %s\n", VERSION_ZERO_STR);
251 break;
252 case IP_FW_VERSION_1:
253 printf("Version: %s\n", VERSION_ONE_STR);
254 break;
255 case IP_FW_CURRENT_API_VERSION:
256 printf("Version: %s\n", CURRENT_API_VERSION_STR);
257 break;
258 case IP_FW_VERSION_NONE:
259 printf("Version: %s\n", NO_VERSION_STR);
260 break;
261 default:
262 printf("Unrecognized version\n");
263 break;
264 }
265 }
266
267 static void
268 print_icmptypes(ipfw_insn_u32 *cmd)
269 {
270 int i;
271 char sep = ' ';
272
273 printf(" icmptypes");
274 for (i = 0; i < 32; i++) {
275 if ((cmd->d[0] & (1 << (i))) == 0) {
276 continue;
277 }
278 printf("%c%d", sep, i);
279 sep = ',';
280 }
281 }
282
283 /*
284 * print flags set/clear in the two bitmasks passed as parameters.
285 * There is a specialized check for f_tcpflags.
286 */
287 static void
288 print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
289 {
290 char const *comma = "";
291 int i;
292 uint8_t set = cmd->arg1 & 0xff;
293 uint8_t clear = (cmd->arg1 >> 8) & 0xff;
294
295 if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
296 printf(" setup");
297 return;
298 }
299
300 printf(" %s ", name);
301 for (i = 0; list[i].x != 0; i++) {
302 if (set & list[i].x) {
303 set &= ~list[i].x;
304 printf("%s%s", comma, list[i].s);
305 comma = ",";
306 }
307 if (clear & list[i].x) {
308 clear &= ~list[i].x;
309 printf("%s!%s", comma, list[i].s);
310 comma = ",";
311 }
312 }
313 }
314
315 static int
316 contigmask(uint8_t *p, int len)
317 {
318 int i, n;
319
320 for (i = 0; i < len; i++) {
321 if ((p[i / 8] & (1 << (7 - (i % 8)))) == 0) { /* first bit unset */
322 break;
323 }
324 }
325 for (n = i + 1; n < len; n++) {
326 if ((p[n / 8] & (1 << (7 - (n % 8)))) != 0) {
327 return -1; /* mask not contiguous */
328 }
329 }
330 return i;
331 }
332
333 /*
334 * Print the ip address contained in a command.
335 */
336 static void
337 print_ip(ipfw_insn_ip *cmd)
338 {
339 int len = F_LEN((ipfw_insn *)cmd);
340 uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
341 char ipv4str[MAX_IPv4_STR_LEN];
342
343 printf("%s ", cmd->o.len & F_NOT ? " not": "");
344
345 if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
346 printf("me");
347 return;
348 }
349
350 /*
351 * len == 2 indicates a single IP, whereas lists of 1 or more
352 * addr/mask pairs have len = (2n+1). We convert len to n so we
353 * use that to count the number of entries.
354 */
355 for (len = len / 2; len > 0; len--, a += 2) {
356 int mb = /* mask length */
357 (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?
358 32 : contigmask((uint8_t *)&(a[1]), 32);
359 if (mb == 0) { /* any */
360 printf("any");
361 } else { /* numeric IP followed by some kind of mask */
362 printf("%s", inet_ntop(AF_INET, &a[0], ipv4str, sizeof(ipv4str)));
363 if (mb < 0) {
364 printf(":%s", inet_ntop(AF_INET, &a[1], ipv4str, sizeof(ipv4str)));
365 } else if (mb < 32) {
366 printf("/%d", mb);
367 }
368 }
369 if (len > 1) {
370 printf(",");
371 }
372 }
373 }
374
375 /*
376 * prints a MAC address/mask pair
377 */
378 static void
379 print_mac(uint8_t *addr, uint8_t *mask)
380 {
381 int l = contigmask(mask, 48);
382
383 if (l == 0) {
384 printf(" any");
385 } else {
386 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
387 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
388 if (l == -1) {
389 printf("&%02x:%02x:%02x:%02x:%02x:%02x",
390 mask[0], mask[1], mask[2],
391 mask[3], mask[4], mask[5]);
392 } else if (l < 48) {
393 printf("/%d", l);
394 }
395 }
396 }
397
398 #endif /* !version #1 */
399
400 #if FW2_DEBUG_VERBOSE
401 static void
402 ipfw_print_vers2_struct(struct ip_fw *vers2_rule)
403 {
404 int l;
405 ipfw_insn *cmd;
406 ipfw_insn_log *logptr = NULL;
407 char ipv4str[MAX_IPv4_STR_LEN];
408
409 print_fw_version(vers2_rule->version);
410
411 printf("act_ofs: %d\n", vers2_rule->act_ofs);
412 printf("cmd_len: %d\n", vers2_rule->cmd_len);
413 printf("rulenum: %d\n", vers2_rule->rulenum);
414 printf("set: %d\n", vers2_rule->set);
415 printf("pcnt: %llu\n", vers2_rule->pcnt);
416 printf("bcnt: %llu\n", vers2_rule->bcnt);
417 printf("timestamp: %d\n", vers2_rule->timestamp);
418
419 /*
420 * first print actions
421 */
422 for (l = vers2_rule->cmd_len - vers2_rule->act_ofs, cmd = ACTION_PTR(vers2_rule);
423 l > 0; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
424 switch (cmd->opcode) {
425 case O_CHECK_STATE:
426 printf("check-state");
427 break;
428
429 case O_ACCEPT:
430 printf("allow");
431 break;
432
433 case O_COUNT:
434 printf("count");
435 break;
436
437 case O_DENY:
438 printf("deny");
439 break;
440
441 case O_REJECT:
442 if (cmd->arg1 == ICMP_REJECT_RST) {
443 printf("reset");
444 } else if (cmd->arg1 == ICMP_UNREACH_HOST) {
445 printf("reject");
446 } else {
447 printf("unreach %u", cmd->arg1);
448 }
449 break;
450
451 case O_SKIPTO:
452 printf("skipto %u", cmd->arg1);
453 break;
454
455 case O_PIPE:
456 printf("pipe %u", cmd->arg1);
457 break;
458
459 case O_QUEUE:
460 printf("queue %u", cmd->arg1);
461 break;
462
463 case O_DIVERT:
464 printf("divert %u", cmd->arg1);
465 break;
466
467 case O_TEE:
468 printf("tee %u", cmd->arg1);
469 break;
470
471 case O_FORWARD_IP:
472 {
473 ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
474
475 printf("fwd %s",
476 inet_ntop(AF_INET, &s->sa.sin_addr, ipv4str,
477 sizeof(ipv4str)));
478 if (s->sa.sin_port) {
479 printf(",%d", s->sa.sin_port);
480 }
481 break;
482 }
483
484 case O_LOG: /* O_LOG is printed last */
485 logptr = (ipfw_insn_log *)cmd;
486 break;
487
488 default:
489 printf("** unrecognized action %d len %d",
490 cmd->opcode, cmd->len);
491 }
492 }
493 if (logptr) {
494 if (logptr->max_log > 0) {
495 printf(" log logamount %d", logptr->max_log);
496 } else {
497 printf(" log");
498 }
499 }
500
501 /*
502 * then print the body.
503 */
504 for (l = vers2_rule->act_ofs, cmd = vers2_rule->cmd;
505 l > 0; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
506 /* useful alias */
507 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
508
509 switch (cmd->opcode) {
510 case O_PROB:
511 break; /* done already */
512
513 case O_PROBE_STATE:
514 break; /* no need to print anything here */
515
516 case O_MACADDR2:
517 {
518 ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
519
520 if (cmd->len & F_NOT) {
521 printf(" not");
522 }
523 printf(" MAC");
524 print_mac(m->addr, m->mask);
525 print_mac(m->addr + 6, m->mask + 6);
526 printf("\n");
527 break;
528 }
529 case O_MAC_TYPE:
530 {
531 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
532 int i;
533
534 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
535 printf("0x%04x", p[0]);
536 if (p[0] != p[1]) {
537 printf("-");
538 printf("0x%04x", p[1]);
539 }
540 printf(",");
541 }
542 break;
543 }
544 case O_IP_SRC:
545 case O_IP_SRC_MASK:
546 case O_IP_SRC_ME:
547 print_ip((ipfw_insn_ip *)cmd);
548 break;
549
550 case O_IP_DST:
551 case O_IP_DST_MASK:
552 case O_IP_DST_ME:
553 print_ip((ipfw_insn_ip *)cmd);
554 break;
555
556 case O_IP_DSTPORT:
557 case O_IP_SRCPORT:
558 {
559 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
560 int i;
561
562 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
563 printf("0x%04x", p[0]);
564 if (p[0] != p[1]) {
565 printf("-");
566 printf("0x%04x", p[1]);
567 }
568 printf(",");
569 }
570 break;
571 }
572 case O_PROTO:
573 {
574 printf("O_PROTO");
575
576 if (cmd->len & F_NOT) {
577 printf(" not");
578 }
579
580 printf(" %u", cmd->arg1);
581
582 break;
583 }
584
585 default: /*options ... */
586 {
587 if (cmd->len & F_NOT && cmd->opcode != O_IN) {
588 printf(" not");
589 }
590 switch (cmd->opcode) {
591 case O_FRAG:
592 printf("O_FRAG");
593 break;
594
595 case O_IN:
596 printf(cmd->len & F_NOT ? " out" : " O_IN");
597 break;
598
599 case O_LAYER2:
600 printf(" O_LAYER2");
601 break;
602 case O_XMIT:
603 case O_RECV:
604 case O_VIA:
605 {
606 char const *s;
607 ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
608
609 if (cmd->opcode == O_XMIT) {
610 s = "O_XMIT";
611 } else if (cmd->opcode == O_RECV) {
612 s = "O_RECV";
613 } else { /* if (cmd->opcode == O_VIA) */
614 s = "O_VIA";
615 }
616 if (cmdif->name[0] == '\0') {
617 printf(" %s %s", s,
618 inet_ntop(AF_INET, &cmdif->p.ip, ipv4str,
619 sizeof(ipv4str)));
620 } else if (cmdif->p.unit == -1) {
621 printf(" %s %s*", s, cmdif->name);
622 } else {
623 printf(" %s %s%d", s, cmdif->name,
624 cmdif->p.unit);
625 }
626 }
627 break;
628
629 case O_IPID:
630 if (F_LEN(cmd) == 1) {
631 printf(" ipid %u", cmd->arg1 );
632 } else {
633 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
634 int i;
635
636 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
637 printf("0x%04x", p[0]);
638 if (p[0] != p[1]) {
639 printf("-");
640 printf("0x%04x", p[1]);
641 }
642 printf(",");
643 }
644 }
645
646 break;
647
648 case O_IPTTL:
649 if (F_LEN(cmd) == 1) {
650 printf(" ipttl %u", cmd->arg1 );
651 } else {
652 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
653 int i;
654
655 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
656 printf("0x%04x", p[0]);
657 if (p[0] != p[1]) {
658 printf("-");
659 printf("0x%04x", p[1]);
660 }
661 printf(",");
662 }
663 }
664
665 break;
666
667 case O_IPVER:
668 printf(" ipver %u", cmd->arg1 );
669 break;
670
671 case O_IPPRECEDENCE:
672 printf(" ipprecedence %u", (cmd->arg1) >> 5 );
673 break;
674
675 case O_IPLEN:
676 if (F_LEN(cmd) == 1) {
677 printf(" iplen %u", cmd->arg1 );
678 } else {
679 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
680 int i;
681
682 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
683 printf("0x%04x", p[0]);
684 if (p[0] != p[1]) {
685 printf("-");
686 printf("0x%04x", p[1]);
687 }
688 printf(",");
689 }
690 }
691
692 break;
693
694 case O_IPOPT:
695 print_flags("ipoptions", cmd, f_ipopts);
696 break;
697
698 case O_IPTOS:
699 print_flags("iptos", cmd, f_iptos);
700 break;
701
702 case O_ICMPTYPE:
703 print_icmptypes((ipfw_insn_u32 *)cmd);
704 break;
705
706 case O_ESTAB:
707 printf(" established");
708 break;
709
710 case O_TCPFLAGS:
711 print_flags("tcpflags", cmd, f_tcpflags);
712 break;
713
714 case O_TCPOPTS:
715 print_flags("tcpoptions", cmd, f_tcpopts);
716 break;
717
718 case O_TCPWIN:
719 printf(" tcpwin %d", ntohs(cmd->arg1));
720 break;
721
722 case O_TCPACK:
723 printf(" tcpack %u", ntohl(cmd32->d[0]));
724 break;
725
726 case O_TCPSEQ:
727 printf(" tcpseq %u", ntohl(cmd32->d[0]));
728 break;
729
730 case O_UID:
731 printf(" uid %u", cmd32->d[0]);
732 break;
733
734 case O_GID:
735 printf(" gid %u", cmd32->d[0]);
736 break;
737
738 case O_VERREVPATH:
739 printf(" verrevpath");
740 break;
741
742 case O_IPSEC:
743 printf(" ipsec");
744 break;
745
746 case O_NOP:
747 break;
748
749 case O_KEEP_STATE:
750 printf(" keep-state");
751 break;
752
753 case O_LIMIT:
754 {
755 struct _s_x *p = limit_masks;
756 ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
757 uint8_t x = c->limit_mask;
758 char const *comma = " ";
759
760 printf(" limit");
761 for (; p->x != 0; p++) {
762 if ((x & p->x) == p->x) {
763 x &= ~p->x;
764 printf("%s%s", comma, p->s);
765 comma = ",";
766 }
767 }
768 printf(" %d", c->conn_limit);
769
770 break;
771 }
772
773 default:
774 printf(" [opcode %d len %d]",
775 cmd->opcode, cmd->len);
776 } /* switch */
777 } /* default */
778 } /* switch */
779 } /* for */
780 }
781
782 #endif /* !FW2_DEBUG_VERBOSE */
783
784
785 /*
786 * helper function, updates the pointer to cmd with the length
787 * of the current command, and also cleans up the first word of
788 * the new command in case it has been clobbered before.
789 * from ipfw2.c
790 */
791 static ipfw_insn *
792 next_cmd(ipfw_insn *cmd)
793 {
794 cmd += F_LEN(cmd);
795 bzero(cmd, sizeof(*cmd));
796 return cmd;
797 }
798
799 /*
800 * A function to fill simple commands of size 1.
801 * Existing flags are preserved.
802 * from ipfw2.c
803 */
804 static void
805 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, uint16_t arg)
806 {
807 cmd->opcode = opcode;
808 cmd->len = ((cmd->len) & (F_NOT | F_OR)) | 1;
809 cmd->arg1 = arg;
810 }
811
812
813 static u_int32_t
814 fill_compat_tcpflags(u_int32_t flags)
815 {
816 u_int32_t flags_compat = 0;
817
818 if (flags & TH_FIN) {
819 flags_compat |= IP_FW_TCPF_FIN_COMPAT;
820 }
821 if (flags & TH_SYN) {
822 flags_compat |= IP_FW_TCPF_SYN_COMPAT;
823 }
824 if (flags & TH_RST) {
825 flags_compat |= IP_FW_TCPF_RST_COMPAT;
826 }
827 if (flags & TH_PUSH) {
828 flags_compat |= IP_FW_TCPF_PSH_COMPAT;
829 }
830 if (flags & TH_ACK) {
831 flags_compat |= IP_FW_TCPF_ACK_COMPAT;
832 }
833 if (flags & TH_URG) {
834 flags_compat |= IP_FW_TCPF_URG_COMPAT;
835 }
836
837 return flags_compat;
838 }
839
840
841 /* ********************************************
842 * *********** Convert from Latest ************
843 * ********************************************/
844
845 /*
846 * Things we're actively ignoring:
847 * sets, sets of addresses, blocks (NOT, OR)
848 */
849 static void
850 ipfw_map_from_cmds_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
851 {
852 int l;
853 ipfw_insn *cmd;
854
855 for (l = curr_rule->act_ofs, cmd = curr_rule->cmd;
856 l > 0;
857 l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
858 /* useful alias */
859 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
860
861 switch (cmd->opcode) {
862 case O_PROTO:
863 /* protocol */
864 compat_rule->fw_prot = cmd->arg1;
865 break;
866
867 case O_IP_SRC_ME:
868 compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
869 if (cmd->len & F_NOT) {
870 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
871 }
872 break;
873
874 case O_IP_SRC_MASK:
875 {
876 /* addr/mask */
877 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
878
879 compat_rule->fw_src = ip->addr;
880 compat_rule->fw_smsk = ip->mask;
881 if (cmd->len & F_NOT) {
882 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
883 }
884 break;
885 }
886
887 case O_IP_SRC:
888 /* one IP */
889 /* source -
890 * for now we only deal with one address
891 * per rule and ignore sets of addresses
892 */
893 compat_rule->fw_src.s_addr = cmd32->d[0];
894 if (cmd->len & F_NOT) {
895 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
896 }
897 break;
898
899 case O_IP_SRCPORT:
900 {
901 /* source ports */
902 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
903 uint16_t *p = ports->ports;
904 int i, j;
905
906 /* copy list of ports */
907 for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
908 if (p[0] != p[1]) {
909 /* this is a range */
910 compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
911 compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
912 compat_rule->fw_uar_compat.fw_pts[j] = p[1];
913 } else {
914 compat_rule->fw_uar_compat.fw_pts[j] = p[0];
915 }
916 }
917 IP_FW_SETNSRCP_COMPAT(compat_rule, j);
918
919 break;
920 }
921
922 case O_IP_DST_ME:
923 /* destination */
924 compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
925 if (cmd->len & F_NOT) {
926 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
927 }
928 break;
929
930 case O_IP_DST_MASK:
931 {
932 /* addr/mask */
933 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
934
935 compat_rule->fw_dst = ip->addr;
936 compat_rule->fw_dmsk = ip->mask;
937 if (cmd->len & F_NOT) {
938 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
939 }
940 break;
941 }
942 case O_IP_DST:
943 /* one IP */
944 /* dest -
945 * for now we only deal with one address
946 * per rule, and ignore sets of addresses
947 */
948 compat_rule->fw_dst.s_addr = cmd32->d[0];
949 if (cmd->len & F_NOT) {
950 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
951 }
952 break;
953
954 case O_IP_DSTPORT:
955 {
956 /* dest. ports */
957 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
958 uint16_t *p = ports->ports;
959 int i,
960 j = IP_FW_GETNSRCP_COMPAT(compat_rule);
961
962 /* copy list of ports */
963 for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
964 if (p[0] != p[1]) {
965 /* this is a range */
966 compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
967 compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
968 compat_rule->fw_uar_compat.fw_pts[j] = p[1];
969 } else {
970 compat_rule->fw_uar_compat.fw_pts[j] = p[0];
971 }
972 }
973 IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
974
975 break;
976 }
977
978 case O_LOG:
979 {
980 ipfw_insn_log *c = (ipfw_insn_log *)cmd;
981
982 compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
983 compat_rule->fw_logamount = c->max_log;
984 break;
985 }
986 case O_UID:
987 compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
988 compat_rule->fw_uid = cmd32->d[0];
989 break;
990
991 case O_IN:
992 if (cmd->len & F_NOT) {
993 compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
994 } else {
995 compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
996 }
997 break;
998
999 case O_KEEP_STATE:
1000 compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
1001 break;
1002
1003 case O_LAYER2:
1004 compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
1005 break;
1006
1007 case O_XMIT:
1008 {
1009 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1010 union ip_fw_if_compat ifu;
1011
1012 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1013 /* any */
1014 compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1015 ifu.fu_via_ip.s_addr = 0;
1016 } else if (ifcmd->p.ip.s_addr != 0) {
1017 compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1018 ifu.fu_via_ip = ifcmd->p.ip;
1019 } else {
1020 compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
1021 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1022 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1023 }
1024 compat_rule->fw_out_if = ifu;
1025
1026 break;
1027 }
1028
1029 case O_RECV:
1030 {
1031 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1032 union ip_fw_if_compat ifu;
1033
1034 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1035 /* any */
1036 compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1037 ifu.fu_via_ip.s_addr = 0;
1038 } else if (ifcmd->p.ip.s_addr != 0) {
1039 compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1040 ifu.fu_via_ip = ifcmd->p.ip;
1041 } else {
1042 compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1043 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1044 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1045 }
1046 compat_rule->fw_in_if = ifu;
1047
1048 break;
1049 }
1050
1051 case O_VIA:
1052 {
1053 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1054 union ip_fw_if_compat ifu;
1055
1056 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1057 /* any */
1058 ifu.fu_via_ip.s_addr = 0;
1059 } else if (ifcmd->name[0] != '\0') {
1060 compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1061 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1062 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1063 } else {
1064 ifu.fu_via_ip = ifcmd->p.ip;
1065 }
1066 compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
1067 compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
1068
1069 break;
1070 }
1071
1072 case O_FRAG:
1073 compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
1074 break;
1075
1076 case O_IPOPT:
1077 /* IP options */
1078 compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
1079 compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
1080 break;
1081
1082 case O_TCPFLAGS:
1083 /* check for "setup" */
1084 if ((cmd->arg1 & 0xff) == TH_SYN &&
1085 ((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
1086 compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
1087 compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
1088 } else {
1089 compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
1090 compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
1091 }
1092 break;
1093
1094 case O_TCPOPTS:
1095 /* TCP options */
1096 compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
1097 compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
1098 break;
1099
1100 case O_ESTAB:
1101 compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
1102 break;
1103
1104 case O_ICMPTYPE:
1105 {
1106 /* ICMP */
1107 /* XXX: check this */
1108 int i, type;
1109
1110 compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
1111 for (i = 0; i < sizeof(uint32_t); i++) {
1112 type = cmd32->d[0] & i;
1113
1114 compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |=
1115 1 << (type % (sizeof(unsigned) * 8));
1116 }
1117 break;
1118 }
1119 default:
1120 break;
1121 } /* switch */
1122 } /* for */
1123 }
1124
1125 static void
1126 ipfw_map_from_cmds_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
1127 {
1128 int l;
1129 ipfw_insn *cmd;
1130 for (l = curr_rule->act_ofs, cmd = curr_rule->cmd;
1131 l > 0;
1132 l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1133 /* useful alias */
1134 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
1135
1136 switch (cmd->opcode) {
1137 case O_PROTO:
1138 /* protocol */
1139 compat_rule->fw_prot = cmd->arg1;
1140 break;
1141
1142 case O_IP_SRC_ME:
1143 compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
1144 if (cmd->len & F_NOT) {
1145 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
1146 }
1147 break;
1148
1149 case O_IP_SRC_MASK:
1150 {
1151 /* addr/mask */
1152 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
1153
1154 compat_rule->fw_src = ip->addr;
1155 compat_rule->fw_smsk = ip->mask;
1156 if (cmd->len & F_NOT) {
1157 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
1158 }
1159 break;
1160 }
1161
1162 case O_IP_SRC:
1163 /* one IP */
1164 /* source -
1165 * for now we only deal with one address
1166 * per rule and ignore sets of addresses
1167 */
1168 compat_rule->fw_src.s_addr = cmd32->d[0];
1169 if (cmd->len & F_NOT) {
1170 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
1171 }
1172 break;
1173
1174 case O_IP_SRCPORT:
1175 {
1176 /* source ports */
1177 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
1178 uint16_t *p = ports->ports;
1179 int i, j;
1180
1181 /* copy list of ports */
1182 for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
1183 if (p[0] != p[1]) {
1184 /* this is a range */
1185 compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
1186 compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
1187 compat_rule->fw_uar_compat.fw_pts[j] = p[1];
1188 } else {
1189 compat_rule->fw_uar_compat.fw_pts[j] = p[0];
1190 }
1191 }
1192 IP_FW_SETNSRCP_COMPAT(compat_rule, j);
1193
1194 break;
1195 }
1196
1197 case O_IP_DST_ME:
1198 /* destination */
1199 compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
1200 if (cmd->len & F_NOT) {
1201 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1202 }
1203 break;
1204
1205 case O_IP_DST_MASK:
1206 {
1207 /* addr/mask */
1208 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
1209
1210 compat_rule->fw_dst = ip->addr;
1211 compat_rule->fw_dmsk = ip->mask;
1212 if (cmd->len & F_NOT) {
1213 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1214 }
1215 break;
1216 }
1217 case O_IP_DST:
1218 /* one IP */
1219 /* dest -
1220 * for now we only deal with one address
1221 * per rule, and ignore sets of addresses
1222 */
1223 compat_rule->fw_dst.s_addr = cmd32->d[0];
1224 if (cmd->len & F_NOT) {
1225 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1226 }
1227 break;
1228
1229 case O_IP_DSTPORT:
1230 {
1231 /* dest. ports */
1232 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
1233 uint16_t *p = ports->ports;
1234 int i,
1235 j = IP_FW_GETNSRCP_COMPAT(compat_rule);
1236
1237 /* copy list of ports */
1238 for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
1239 if (p[0] != p[1]) {
1240 /* this is a range */
1241 compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
1242 compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
1243 compat_rule->fw_uar_compat.fw_pts[j] = p[1];
1244 } else {
1245 compat_rule->fw_uar_compat.fw_pts[j] = p[0];
1246 }
1247 }
1248 IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
1249
1250 break;
1251 }
1252
1253 case O_LOG:
1254 {
1255 ipfw_insn_log *c = (ipfw_insn_log *)cmd;
1256
1257 compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
1258 compat_rule->fw_logamount = c->max_log;
1259 break;
1260 }
1261 case O_UID:
1262 compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
1263 compat_rule->fw_uid = cmd32->d[0];
1264 break;
1265
1266 case O_IN:
1267 if (cmd->len & F_NOT) {
1268 compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
1269 } else {
1270 compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
1271 }
1272 break;
1273
1274 case O_KEEP_STATE:
1275 compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
1276 break;
1277
1278 case O_LAYER2:
1279 compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
1280 break;
1281
1282 case O_XMIT:
1283 {
1284 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1285 union ip_fw_if_compat ifu;
1286
1287 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1288 /* any */
1289 compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1290 ifu.fu_via_ip.s_addr = 0;
1291 } else if (ifcmd->p.ip.s_addr != 0) {
1292 compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1293 ifu.fu_via_ip = ifcmd->p.ip;
1294 } else {
1295 compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
1296 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1297 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1298 }
1299 compat_rule->fw_out_if = ifu;
1300
1301 break;
1302 }
1303
1304 case O_RECV:
1305 {
1306 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1307 union ip_fw_if_compat ifu;
1308
1309 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1310 /* any */
1311 compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1312 ifu.fu_via_ip.s_addr = 0;
1313 } else if (ifcmd->p.ip.s_addr != 0) {
1314 compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1315 ifu.fu_via_ip = ifcmd->p.ip;
1316 } else {
1317 compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1318 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1319 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1320 }
1321 compat_rule->fw_in_if = ifu;
1322
1323 break;
1324 }
1325
1326 case O_VIA:
1327 {
1328 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1329 union ip_fw_if_compat ifu;
1330
1331 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1332 /* any */
1333 ifu.fu_via_ip.s_addr = 0;
1334 } else if (ifcmd->name[0] != '\0') {
1335 compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1336 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1337 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1338 } else {
1339 ifu.fu_via_ip = ifcmd->p.ip;
1340 }
1341 compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
1342 compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
1343
1344 break;
1345 }
1346
1347 case O_FRAG:
1348 compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
1349 break;
1350
1351 case O_IPOPT:
1352 /* IP options */
1353 compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
1354 compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
1355 break;
1356
1357 case O_TCPFLAGS:
1358 /* check for "setup" */
1359 if ((cmd->arg1 & 0xff) == TH_SYN &&
1360 ((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
1361 compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
1362 compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
1363 } else {
1364 compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
1365 compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
1366 }
1367 break;
1368
1369 case O_TCPOPTS:
1370 /* TCP options */
1371 compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
1372 compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
1373 break;
1374
1375 case O_ESTAB:
1376 compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
1377 break;
1378
1379 case O_ICMPTYPE:
1380 {
1381 /* ICMP */
1382 /* XXX: check this */
1383 int i, type;
1384
1385 compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
1386 for (i = 0; i < sizeof(uint32_t); i++) {
1387 type = cmd32->d[0] & i;
1388
1389 compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |=
1390 1 << (type % (sizeof(unsigned) * 8));
1391 }
1392 break;
1393 }
1394 default:
1395 break;
1396 } /* switch */
1397 } /* for */
1398 }
1399
1400 static void
1401 ipfw_map_from_actions_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
1402 {
1403 int l;
1404 ipfw_insn *cmd;
1405
1406 for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
1407 l > 0;
1408 l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1409 switch (cmd->opcode) {
1410 case O_ACCEPT:
1411 compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
1412 break;
1413 case O_COUNT:
1414 compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
1415 break;
1416 case O_PIPE:
1417 compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
1418 compat_rule->fw_divert_port_compat = cmd->arg1;
1419 break;
1420 case O_QUEUE:
1421 compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
1422 compat_rule->fw_divert_port_compat = cmd->arg1;
1423 break;
1424 case O_SKIPTO:
1425 compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
1426 compat_rule->fw_skipto_rule_compat = cmd->arg1;
1427 break;
1428 case O_DIVERT:
1429 compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
1430 compat_rule->fw_divert_port_compat = cmd->arg1;
1431 break;
1432 case O_TEE:
1433 compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
1434 compat_rule->fw_divert_port_compat = cmd->arg1;
1435 break;
1436 case O_FORWARD_IP:
1437 {
1438 ipfw_insn_sa *p = (ipfw_insn_sa *)cmd;
1439
1440 compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
1441 compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
1442 compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
1443 compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
1444 compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
1445
1446 break;
1447 }
1448 case O_DENY:
1449 compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
1450 break;
1451 case O_REJECT:
1452 compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
1453 compat_rule->fw_reject_code_compat = cmd->arg1;
1454 break;
1455 case O_CHECK_STATE:
1456 compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
1457 break;
1458 default:
1459 break;
1460 }
1461 }
1462 }
1463
1464 static void
1465 ipfw_map_from_actions_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
1466 {
1467 int l;
1468 ipfw_insn *cmd;
1469 for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
1470 l > 0;
1471 l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1472 switch (cmd->opcode) {
1473 case O_ACCEPT:
1474 compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
1475 break;
1476 case O_COUNT:
1477 compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
1478 break;
1479 case O_PIPE:
1480 compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
1481 compat_rule->fw_divert_port_compat = cmd->arg1;
1482 break;
1483 case O_QUEUE:
1484 compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
1485 compat_rule->fw_divert_port_compat = cmd->arg1;
1486 break;
1487 case O_SKIPTO:
1488 compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
1489 compat_rule->fw_skipto_rule_compat = cmd->arg1;
1490 break;
1491 case O_DIVERT:
1492 compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
1493 compat_rule->fw_divert_port_compat = cmd->arg1;
1494 break;
1495 case O_TEE:
1496 compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
1497 compat_rule->fw_divert_port_compat = cmd->arg1;
1498 break;
1499 case O_FORWARD_IP:
1500 {
1501 ipfw_insn_sa *p = (ipfw_insn_sa *)cmd;
1502
1503 compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
1504 compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
1505 compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
1506 compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
1507 compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
1508
1509 break;
1510 }
1511 case O_DENY:
1512 compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
1513 break;
1514 case O_REJECT:
1515 compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
1516 compat_rule->fw_reject_code_compat = cmd->arg1;
1517 break;
1518 case O_CHECK_STATE:
1519 compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
1520 break;
1521 default:
1522 break;
1523 }
1524 }
1525 }
1526
1527 static void
1528 ipfw_version_latest_to_one_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *rule_vers1)
1529 {
1530 if (!rule_vers1) {
1531 return;
1532 }
1533
1534 bzero(rule_vers1, sizeof(struct ip_fw_compat_32));
1535
1536 rule_vers1->version = IP_FW_VERSION_1;
1537 rule_vers1->context = CAST_DOWN_EXPLICIT(user32_addr_t, curr_rule->context);
1538 rule_vers1->fw_number = curr_rule->rulenum;
1539 rule_vers1->fw_pcnt = curr_rule->pcnt;
1540 rule_vers1->fw_bcnt = curr_rule->bcnt;
1541 rule_vers1->timestamp = curr_rule->timestamp;
1542
1543 /* convert actions */
1544 ipfw_map_from_actions_32(curr_rule, rule_vers1);
1545
1546 /* convert commands */
1547 ipfw_map_from_cmds_32(curr_rule, rule_vers1);
1548
1549 #if FW2_DEBUG_VERBOSE
1550 ipfw_print_vers1_struct_32(rule_vers1);
1551 #endif
1552 }
1553
1554 static void
1555 ipfw_version_latest_to_one_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *rule_vers1)
1556 {
1557 if (!rule_vers1) {
1558 return;
1559 }
1560
1561 bzero(rule_vers1, sizeof(struct ip_fw_compat_64));
1562
1563 rule_vers1->version = IP_FW_VERSION_1;
1564 rule_vers1->context = CAST_DOWN_EXPLICIT(__uint64_t, curr_rule->context);
1565 rule_vers1->fw_number = curr_rule->rulenum;
1566 rule_vers1->fw_pcnt = curr_rule->pcnt;
1567 rule_vers1->fw_bcnt = curr_rule->bcnt;
1568 rule_vers1->timestamp = curr_rule->timestamp;
1569
1570 /* convert actions */
1571 ipfw_map_from_actions_64(curr_rule, rule_vers1);
1572
1573 /* convert commands */
1574 ipfw_map_from_cmds_64(curr_rule, rule_vers1);
1575
1576 #if FW2_DEBUG_VERBOSE
1577 ipfw_print_vers1_struct_64(rule_vers1);
1578 #endif
1579 }
1580
1581 /* first convert to version one then to version zero */
1582 static void
1583 ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0, int is64user)
1584 {
1585 if (is64user) {
1586 struct ip_fw_compat_64 rule_vers1;
1587 ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, &rule_vers1);
1588 bzero(rule_vers0, sizeof(struct ip_old_fw));
1589 bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
1590 bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
1591 bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
1592 bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
1593 rule_vers0->fw_pcnt = rule_vers1.fw_pcnt;
1594 rule_vers0->fw_bcnt = rule_vers1.fw_bcnt;
1595 rule_vers0->fw_src = rule_vers1.fw_src;
1596 rule_vers0->fw_dst = rule_vers1.fw_dst;
1597 rule_vers0->fw_smsk = rule_vers1.fw_smsk;
1598 rule_vers0->fw_dmsk = rule_vers1.fw_dmsk;
1599 rule_vers0->fw_number = rule_vers1.fw_number;
1600 rule_vers0->fw_flg = rule_vers1.fw_flg;
1601 rule_vers0->fw_ipopt = rule_vers1.fw_ipopt;
1602 rule_vers0->fw_ipnopt = rule_vers1.fw_ipnopt;
1603 rule_vers0->fw_tcpf = rule_vers1.fw_tcpf;
1604 rule_vers0->fw_tcpnf = rule_vers1.fw_tcpnf;
1605 rule_vers0->timestamp = rule_vers1.timestamp;
1606 rule_vers0->fw_prot = rule_vers1.fw_prot;
1607 rule_vers0->fw_nports = rule_vers1.fw_nports;
1608 rule_vers0->pipe_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
1609 rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
1610
1611 if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
1612 rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
1613 }
1614 } else {
1615 struct ip_fw_compat_32 rule_vers1;
1616 ipfw_version_latest_to_one_32((struct ip_fw_32*)curr_rule, &rule_vers1);
1617 bzero(rule_vers0, sizeof(struct ip_old_fw));
1618 bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
1619 bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
1620 bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
1621 bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
1622 rule_vers0->fw_pcnt = rule_vers1.fw_pcnt;
1623 rule_vers0->fw_bcnt = rule_vers1.fw_bcnt;
1624 rule_vers0->fw_src = rule_vers1.fw_src;
1625 rule_vers0->fw_dst = rule_vers1.fw_dst;
1626 rule_vers0->fw_smsk = rule_vers1.fw_smsk;
1627 rule_vers0->fw_dmsk = rule_vers1.fw_dmsk;
1628 rule_vers0->fw_number = rule_vers1.fw_number;
1629 rule_vers0->fw_flg = rule_vers1.fw_flg;
1630 rule_vers0->fw_ipopt = rule_vers1.fw_ipopt;
1631 rule_vers0->fw_ipnopt = rule_vers1.fw_ipnopt;
1632 rule_vers0->fw_tcpf = rule_vers1.fw_tcpf;
1633 rule_vers0->fw_tcpnf = rule_vers1.fw_tcpnf;
1634 rule_vers0->timestamp = rule_vers1.timestamp;
1635 rule_vers0->fw_prot = rule_vers1.fw_prot;
1636 rule_vers0->fw_nports = rule_vers1.fw_nports;
1637 rule_vers0->pipe_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
1638 rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
1639
1640 if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
1641 rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
1642 }
1643 }
1644 }
1645
1646 void
1647 ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version, int is64user)
1648 {
1649 switch (api_version) {
1650 case IP_FW_VERSION_0:
1651 {
1652 struct ip_old_fw *rule_vers0 = old_rule;
1653
1654 ipfw_version_latest_to_zero(curr_rule, rule_vers0, is64user);
1655 break;
1656 }
1657 case IP_FW_VERSION_1:
1658 {
1659 if (is64user) {
1660 ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, (struct ip_fw_compat_64 *)old_rule);
1661 } else {
1662 ipfw_version_latest_to_one_32((struct ip_fw_32*)curr_rule, (struct ip_fw_compat_32 *)old_rule);
1663 }
1664
1665 break;
1666 }
1667 case IP_FW_CURRENT_API_VERSION:
1668 /* ipfw2 for now, don't need to do anything */
1669 break;
1670
1671 default:
1672 /* unknown version */
1673 break;
1674 }
1675 }
1676
1677
1678 /* ********************************************
1679 * *********** Convert to Latest **************
1680 * ********************************************/
1681
1682 /* from ip_fw.c */
1683 static int
1684 ipfw_check_vers1_struct_32(struct ip_fw_compat_32 *frwl)
1685 {
1686 /* Check for invalid flag bits */
1687 if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
1688 /*
1689 * printf(("%s undefined flag bits set (flags=%x)\n",
1690 * err_prefix, frwl->fw_flg));
1691 */
1692 return EINVAL;
1693 }
1694 if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
1695 /* check-state */
1696 return 0;
1697 }
1698 /* Must apply to incoming or outgoing (or both) */
1699 if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
1700 /*
1701 * printf(("%s neither in nor out\n", err_prefix));
1702 */
1703 return EINVAL;
1704 }
1705 /* Empty interface name is no good */
1706 if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
1707 && !*frwl->fw_in_if.fu_via_if_compat.name)
1708 || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
1709 && !*frwl->fw_out_if.fu_via_if_compat.name)) {
1710 /*
1711 * printf(("%s empty interface name\n", err_prefix));
1712 */
1713 return EINVAL;
1714 }
1715 /* Sanity check interface matching */
1716 if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
1717 ; /* allow "via" backwards compatibility */
1718 } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
1719 && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
1720 /*
1721 * printf(("%s outgoing interface check on incoming\n",
1722 * err_prefix));
1723 */
1724 return EINVAL;
1725 }
1726 /* Sanity check port ranges */
1727 if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
1728 /*
1729 * printf(("%s src range set but n_src_p=%d\n",
1730 * err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
1731 */
1732 return EINVAL;
1733 }
1734 if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
1735 /*
1736 * printf(("%s dst range set but n_dst_p=%d\n",
1737 * err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
1738 */
1739 return EINVAL;
1740 }
1741 if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
1742 /*
1743 * printf(("%s too many ports (%d+%d)\n",
1744 * err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
1745 */
1746 return EINVAL;
1747 }
1748 /*
1749 * Protocols other than TCP/UDP don't use port range
1750 */
1751 if ((frwl->fw_prot != IPPROTO_TCP) &&
1752 (frwl->fw_prot != IPPROTO_UDP) &&
1753 (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
1754 /*
1755 * printf(("%s port(s) specified for non TCP/UDP rule\n",
1756 * err_prefix));
1757 */
1758 return EINVAL;
1759 }
1760
1761 /*
1762 * Rather than modify the entry to make such entries work,
1763 * we reject this rule and require user level utilities
1764 * to enforce whatever policy they deem appropriate.
1765 */
1766 if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
1767 (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
1768 /*
1769 * printf(("%s rule never matches\n", err_prefix));
1770 */
1771 return EINVAL;
1772 }
1773
1774 if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
1775 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1776 if (frwl->fw_nports) {
1777 /*
1778 * printf(("%s cannot mix 'frag' and ports\n", err_prefix));
1779 */
1780 return EINVAL;
1781 }
1782 if (frwl->fw_prot == IPPROTO_TCP &&
1783 frwl->fw_tcpf != frwl->fw_tcpnf) {
1784 /*
1785 * printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
1786 */
1787 return EINVAL;
1788 }
1789 }
1790
1791 /* Check command specific stuff */
1792 switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT) {
1793 case IP_FW_F_REJECT_COMPAT:
1794 if (frwl->fw_reject_code_compat >= 0x100
1795 && !(frwl->fw_prot == IPPROTO_TCP
1796 && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
1797 /*
1798 * printf(("%s unknown reject code\n", err_prefix));
1799 */
1800 return EINVAL;
1801 }
1802 break;
1803 case IP_FW_F_DIVERT_COMPAT: /* Diverting to port zero is invalid */
1804 case IP_FW_F_TEE_COMPAT:
1805 case IP_FW_F_PIPE_COMPAT: /* piping through 0 is invalid */
1806 case IP_FW_F_QUEUE_COMPAT: /* piping through 0 is invalid */
1807 if (frwl->fw_divert_port_compat == 0) {
1808 /*
1809 * printf(("%s can't divert to port 0\n", err_prefix));
1810 */
1811 return EINVAL;
1812 }
1813 break;
1814 case IP_FW_F_DENY_COMPAT:
1815 case IP_FW_F_ACCEPT_COMPAT:
1816 case IP_FW_F_COUNT_COMPAT:
1817 case IP_FW_F_SKIPTO_COMPAT:
1818 case IP_FW_F_FWD_COMPAT:
1819 case IP_FW_F_UID_COMPAT:
1820 break;
1821 default:
1822 /*
1823 * printf(("%s invalid command\n", err_prefix));
1824 */
1825 return EINVAL;
1826 }
1827
1828 return 0;
1829 }
1830
1831 static int
1832 ipfw_check_vers1_struct_64(struct ip_fw_compat_64 *frwl)
1833 {
1834 /* Check for invalid flag bits */
1835 if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
1836 /*
1837 * printf(("%s undefined flag bits set (flags=%x)\n",
1838 * err_prefix, frwl->fw_flg));
1839 */
1840
1841 return EINVAL;
1842 }
1843 if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
1844 /* check-state */
1845 return 0;
1846 }
1847 /* Must apply to incoming or outgoing (or both) */
1848 if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
1849 /*
1850 * printf(("%s neither in nor out\n", err_prefix));
1851 */
1852
1853 return EINVAL;
1854 }
1855 /* Empty interface name is no good */
1856 if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
1857 && !*frwl->fw_in_if.fu_via_if_compat.name)
1858 || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
1859 && !*frwl->fw_out_if.fu_via_if_compat.name)) {
1860 /*
1861 * printf(("%s empty interface name\n", err_prefix));
1862 */
1863
1864 return EINVAL;
1865 }
1866 /* Sanity check interface matching */
1867 if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
1868 ; /* allow "via" backwards compatibility */
1869 } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
1870 && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
1871 /*
1872 * printf(("%s outgoing interface check on incoming\n",
1873 * err_prefix));
1874 */
1875
1876 return EINVAL;
1877 }
1878 /* Sanity check port ranges */
1879 if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
1880 /*
1881 * printf(("%s src range set but n_src_p=%d\n",
1882 * err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
1883 */
1884
1885 return EINVAL;
1886 }
1887 if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
1888 /*
1889 * printf(("%s dst range set but n_dst_p=%d\n",
1890 * err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
1891 */
1892
1893 return EINVAL;
1894 }
1895 if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
1896 /*
1897 * printf(("%s too many ports (%d+%d)\n",
1898 * err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
1899 */
1900
1901 return EINVAL;
1902 }
1903 /*
1904 * Protocols other than TCP/UDP don't use port range
1905 */
1906 if ((frwl->fw_prot != IPPROTO_TCP) &&
1907 (frwl->fw_prot != IPPROTO_UDP) &&
1908 (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
1909 /*
1910 * printf(("%s port(s) specified for non TCP/UDP rule\n",
1911 * err_prefix));
1912 */
1913
1914 return EINVAL;
1915 }
1916
1917 /*
1918 * Rather than modify the entry to make such entries work,
1919 * we reject this rule and require user level utilities
1920 * to enforce whatever policy they deem appropriate.
1921 */
1922 if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
1923 (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
1924 /*
1925 * printf(("%s rule never matches\n", err_prefix));
1926 */
1927
1928 return EINVAL;
1929 }
1930
1931 if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
1932 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1933 if (frwl->fw_nports) {
1934 /*
1935 * printf(("%s cannot mix 'frag' and ports\n", err_prefix));
1936 */
1937
1938 return EINVAL;
1939 }
1940 if (frwl->fw_prot == IPPROTO_TCP &&
1941 frwl->fw_tcpf != frwl->fw_tcpnf) {
1942 /*
1943 * printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
1944 */
1945
1946 return EINVAL;
1947 }
1948 }
1949
1950 /* Check command specific stuff */
1951 switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT) {
1952 case IP_FW_F_REJECT_COMPAT:
1953 if (frwl->fw_reject_code_compat >= 0x100
1954 && !(frwl->fw_prot == IPPROTO_TCP
1955 && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
1956 /*
1957 * printf(("%s unknown reject code\n", err_prefix));
1958 */
1959
1960 return EINVAL;
1961 }
1962 break;
1963 case IP_FW_F_DIVERT_COMPAT: /* Diverting to port zero is invalid */
1964 case IP_FW_F_TEE_COMPAT:
1965 case IP_FW_F_PIPE_COMPAT: /* piping through 0 is invalid */
1966 case IP_FW_F_QUEUE_COMPAT: /* piping through 0 is invalid */
1967 if (frwl->fw_divert_port_compat == 0) {
1968 /*
1969 * printf(("%s can't divert to port 0\n", err_prefix));
1970 */
1971
1972 return EINVAL;
1973 }
1974 break;
1975 case IP_FW_F_DENY_COMPAT:
1976 case IP_FW_F_ACCEPT_COMPAT:
1977 case IP_FW_F_COUNT_COMPAT:
1978 case IP_FW_F_SKIPTO_COMPAT:
1979 case IP_FW_F_FWD_COMPAT:
1980 case IP_FW_F_UID_COMPAT:
1981 break;
1982 default:
1983 /*
1984 * printf(("%s invalid command\n", err_prefix));
1985 */
1986
1987 return EINVAL;
1988 }
1989
1990 return 0;
1991 }
1992
1993 static void
1994 ipfw_convert_to_cmds_32(struct ip_fw *curr_rule, struct ip_fw_compat_32 *compat_rule)
1995 {
1996 int k;
1997 uint32_t actbuf[255], cmdbuf[255];
1998 ipfw_insn *action, *cmd, *src, *dst;
1999 ipfw_insn *have_state = NULL; /* track check-state or keep-state */
2000
2001 if (!compat_rule || !curr_rule) {
2002 return;
2003 }
2004
2005 /* preemptively check the old ip_fw rule to
2006 * make sure it's valid before starting to copy stuff
2007 */
2008 if (ipfw_check_vers1_struct_32(compat_rule)) {
2009 /* bad rule */
2010 return;
2011 }
2012
2013 bzero(actbuf, sizeof(actbuf)); /* actions go here */
2014 bzero(cmdbuf, sizeof(cmdbuf));
2015
2016 /* fill in action */
2017 action = (ipfw_insn *)actbuf;
2018 {
2019 u_int flag = compat_rule->fw_flg;
2020
2021 action->len = 1; /* default */
2022
2023 if (flag & IP_FW_F_CHECK_S_COMPAT) {
2024 have_state = action;
2025 action->opcode = O_CHECK_STATE;
2026 } else {
2027 switch (flag & IP_FW_F_COMMAND_COMPAT) {
2028 case IP_FW_F_ACCEPT_COMPAT:
2029 action->opcode = O_ACCEPT;
2030 break;
2031 case IP_FW_F_COUNT_COMPAT:
2032 action->opcode = O_COUNT;
2033 break;
2034 case IP_FW_F_PIPE_COMPAT:
2035 action->opcode = O_PIPE;
2036 action->len = F_INSN_SIZE(ipfw_insn_pipe);
2037 action->arg1 = compat_rule->fw_divert_port_compat;
2038 break;
2039 case IP_FW_F_QUEUE_COMPAT:
2040 action->opcode = O_QUEUE;
2041 action->len = F_INSN_SIZE(ipfw_insn_pipe);
2042 action->arg1 = compat_rule->fw_divert_port_compat;
2043 break;
2044 case IP_FW_F_SKIPTO_COMPAT:
2045 action->opcode = O_SKIPTO;
2046 action->arg1 = compat_rule->fw_skipto_rule_compat;
2047 break;
2048 case IP_FW_F_DIVERT_COMPAT:
2049 action->opcode = O_DIVERT;
2050 action->arg1 = compat_rule->fw_divert_port_compat;
2051 break;
2052 case IP_FW_F_TEE_COMPAT:
2053 action->opcode = O_TEE;
2054 action->arg1 = compat_rule->fw_divert_port_compat;
2055 break;
2056 case IP_FW_F_FWD_COMPAT:
2057 {
2058 ipfw_insn_sa *p = (ipfw_insn_sa *)action;
2059
2060 action->opcode = O_FORWARD_IP;
2061 action->len = F_INSN_SIZE(ipfw_insn_sa);
2062
2063 p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
2064 p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
2065 p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
2066 p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
2067
2068 break;
2069 }
2070 case IP_FW_F_DENY_COMPAT:
2071 action->opcode = O_DENY;
2072 action->arg1 = 0;
2073 break;
2074 case IP_FW_F_REJECT_COMPAT:
2075 action->opcode = O_REJECT;
2076 action->arg1 = compat_rule->fw_reject_code_compat;
2077 break;
2078 default:
2079 action->opcode = O_NOP;
2080 break;
2081 }
2082 }
2083
2084 /* action is mandatory */
2085 if (action->opcode == O_NOP) {
2086 return;
2087 }
2088
2089 action = next_cmd(action);
2090 } /* end actions */
2091
2092 cmd = (ipfw_insn *)cmdbuf;
2093
2094 /* this is O_CHECK_STATE, we're done */
2095 if (have_state) {
2096 goto done;
2097 }
2098
2099 {
2100 ipfw_insn *prev = NULL;
2101 u_int flag = compat_rule->fw_flg;
2102
2103 /* logging */
2104 if (flag & IP_FW_F_PRN_COMPAT) {
2105 ipfw_insn_log *c = (ipfw_insn_log *)cmd;
2106
2107 cmd->opcode = O_LOG;
2108 cmd->len |= F_INSN_SIZE(ipfw_insn_log);
2109 c->max_log = compat_rule->fw_logamount;
2110
2111 prev = cmd;
2112 cmd = next_cmd(cmd);
2113 }
2114
2115 /* protocol */
2116 if (compat_rule->fw_prot != 0) {
2117 fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
2118 prev = cmd;
2119 cmd = next_cmd(cmd);
2120 }
2121
2122 /* source */
2123 if (flag & IP_FW_F_SME_COMPAT) {
2124 cmd->opcode = O_IP_SRC_ME;
2125 cmd->len |= F_INSN_SIZE(ipfw_insn);
2126 if (flag & IP_FW_F_INVSRC_COMPAT) {
2127 cmd->len ^= F_NOT; /* toggle F_NOT */
2128 }
2129
2130 prev = cmd;
2131 cmd = next_cmd(cmd);
2132 } else {
2133 if (compat_rule->fw_smsk.s_addr != 0) {
2134 /* addr/mask */
2135 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
2136
2137 ip->addr = compat_rule->fw_src;
2138 ip->mask = compat_rule->fw_smsk;
2139 cmd->opcode = O_IP_SRC_MASK;
2140 cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2141 } else {
2142 /* one IP */
2143 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2144
2145 if (compat_rule->fw_src.s_addr == 0) {
2146 /* any */
2147 cmd32->o.len &= ~F_LEN_MASK; /* zero len */
2148 } else {
2149 cmd32->d[0] = compat_rule->fw_src.s_addr;
2150 cmd32->o.opcode = O_IP_SRC;
2151 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2152 }
2153 }
2154
2155 if (flag & IP_FW_F_INVSRC_COMPAT) {
2156 cmd->len ^= F_NOT; /* toggle F_NOT */
2157 }
2158
2159 if (F_LEN(cmd) != 0) { /* !any */
2160 prev = cmd;
2161 cmd = next_cmd(cmd);
2162 }
2163 }
2164
2165 /* source ports */
2166 {
2167 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
2168 uint16_t *p = ports->ports;
2169 int i, j = 0,
2170 nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
2171 have_range = 0;
2172
2173 cmd->opcode = O_IP_SRCPORT;
2174 for (i = 0; i < nports; i++) {
2175 if (((flag & IP_FW_F_SRNG_COMPAT) ||
2176 (flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
2177 p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2178 p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2179 have_range = 1;
2180 } else {
2181 p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2182 }
2183 p += 2;
2184 j++;
2185 }
2186
2187 if (j > 0) {
2188 ports->o.len |= j + 1; /* leave F_NOT and F_OR untouched */
2189 }
2190
2191 prev = cmd;
2192 cmd = next_cmd(cmd);
2193 }
2194
2195 /* destination */
2196 if (flag & IP_FW_F_DME_COMPAT) {
2197 cmd->opcode = O_IP_DST_ME;
2198 cmd->len |= F_INSN_SIZE(ipfw_insn);
2199 if (flag & IP_FW_F_INVDST_COMPAT) {
2200 cmd->len ^= F_NOT; /* toggle F_NOT */
2201 }
2202
2203 prev = cmd;
2204 cmd = next_cmd(cmd);
2205 } else {
2206 if (compat_rule->fw_dmsk.s_addr != 0) {
2207 /* addr/mask */
2208 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
2209
2210 ip->addr = compat_rule->fw_dst;
2211 ip->mask = compat_rule->fw_dmsk;
2212 cmd->opcode = O_IP_DST_MASK;
2213 cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2214 } else {
2215 /* one IP */
2216 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2217
2218 if (compat_rule->fw_dst.s_addr == 0) {
2219 /* any */
2220 cmd32->o.len &= ~F_LEN_MASK; /* zero len */
2221 } else {
2222 cmd32->d[0] = compat_rule->fw_dst.s_addr;
2223 cmd32->o.opcode = O_IP_DST;
2224 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2225 }
2226 }
2227
2228 if (flag & IP_FW_F_INVDST_COMPAT) {
2229 cmd->len ^= F_NOT; /* toggle F_NOT */
2230 }
2231
2232 if (F_LEN(cmd) != 0) { /* !any */
2233 prev = cmd;
2234 cmd = next_cmd(cmd);
2235 }
2236 }
2237
2238 /* dest. ports */
2239 {
2240 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
2241 uint16_t *p = ports->ports;
2242 int i = IP_FW_GETNSRCP_COMPAT(compat_rule),
2243 j = 0,
2244 nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
2245 have_range = 0;
2246
2247 cmd->opcode = O_IP_DSTPORT;
2248 for (; i < nports; i++, p += 2) {
2249 if (((flag & IP_FW_F_DRNG_COMPAT) ||
2250 (flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
2251 /* range */
2252 p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2253 p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2254 have_range = 1;
2255 } else {
2256 p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2257 }
2258 j++;
2259 }
2260
2261 if (j > 0) {
2262 ports->o.len |= j + 1; /* leave F_NOT and F_OR untouched */
2263 }
2264
2265 prev = cmd;
2266 cmd = next_cmd(cmd);
2267 }
2268
2269 if (flag & IP_FW_F_UID_COMPAT) {
2270 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2271
2272 cmd32->o.opcode = O_UID;
2273 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2274 cmd32->d[0] = compat_rule->fw_uid;
2275
2276 prev = cmd;
2277 cmd = next_cmd(cmd);
2278 }
2279
2280 if (flag & IP_FW_F_KEEP_S_COMPAT) {
2281 have_state = cmd;
2282 fill_cmd(cmd, O_KEEP_STATE, 0);
2283
2284 prev = cmd;
2285 cmd = next_cmd(cmd);
2286 }
2287 if (flag & IP_FW_BRIDGED_COMPAT) {
2288 fill_cmd(cmd, O_LAYER2, 0);
2289
2290 prev = cmd;
2291 cmd = next_cmd(cmd);
2292 }
2293
2294 if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
2295 /* via */
2296 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
2297 union ip_fw_if_compat ifu = compat_rule->fw_in_if;
2298
2299 cmd->opcode = O_VIA;
2300 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2301
2302 if (ifu.fu_via_ip.s_addr == 0) {
2303 /* "any" */
2304 ifcmd->name[0] = '\0';
2305 ifcmd->o.len = 0;
2306 } else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
2307 /* by name */
2308 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2309 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2310 } else {
2311 /* by addr */
2312 ifcmd->p.ip = ifu.fu_via_ip;
2313 }
2314
2315 prev = cmd;
2316 cmd = next_cmd(cmd);
2317 } else {
2318 if (flag & IP_FW_F_IN_COMPAT) {
2319 fill_cmd(cmd, O_IN, 0);
2320
2321 prev = cmd;
2322 cmd = next_cmd(cmd);
2323 }
2324 if (flag & IP_FW_F_OUT_COMPAT) {
2325 /* if the previous command was O_IN, and this
2326 * is being set as well, it's equivalent to not
2327 * having either command, so let's back up prev
2328 * to the cmd before it and move cmd to prev.
2329 */
2330 if (prev->opcode == O_IN) {
2331 cmd = prev;
2332 bzero(cmd, sizeof(*cmd));
2333 } else {
2334 cmd->len ^= F_NOT; /* toggle F_NOT */
2335 fill_cmd(cmd, O_IN, 0);
2336
2337 prev = cmd;
2338 cmd = next_cmd(cmd);
2339 }
2340 }
2341 if (flag & IP_FW_F_OIFACE_COMPAT) {
2342 /* xmit */
2343 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
2344 union ip_fw_if_compat ifu = compat_rule->fw_out_if;
2345
2346 cmd->opcode = O_XMIT;
2347 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2348
2349 if (ifu.fu_via_ip.s_addr == 0) {
2350 /* "any" */
2351 ifcmd->name[0] = '\0';
2352 ifcmd->o.len = 0;
2353 } else if (flag & IP_FW_F_OIFNAME_COMPAT) {
2354 /* by name */
2355 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2356 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2357 } else {
2358 /* by addr */
2359 ifcmd->p.ip = ifu.fu_via_ip;
2360 }
2361
2362 prev = cmd;
2363 cmd = next_cmd(cmd);
2364 } else if (flag & IP_FW_F_IIFACE_COMPAT) {
2365 /* recv */
2366 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
2367 union ip_fw_if_compat ifu = compat_rule->fw_in_if;
2368
2369 cmd->opcode = O_RECV;
2370 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2371
2372 if (ifu.fu_via_ip.s_addr == 0) {
2373 /* "any" */
2374 ifcmd->name[0] = '\0';
2375 ifcmd->o.len = 0;
2376 } else if (flag & IP_FW_F_IIFNAME_COMPAT) {
2377 /* by name */
2378 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2379 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2380 } else {
2381 /* by addr */
2382 ifcmd->p.ip = ifu.fu_via_ip;
2383 }
2384
2385 prev = cmd;
2386 cmd = next_cmd(cmd);
2387 }
2388 }
2389
2390 if (flag & IP_FW_F_FRAG_COMPAT) {
2391 fill_cmd(cmd, O_FRAG, 0);
2392
2393 prev = cmd;
2394 cmd = next_cmd(cmd);
2395 }
2396
2397 /* IP options */
2398 if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
2399 fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
2400 (compat_rule->fw_ipnopt & 0xff) << 8);
2401
2402 prev = cmd;
2403 cmd = next_cmd(cmd);
2404 }
2405
2406 if (compat_rule->fw_prot == IPPROTO_TCP) {
2407 if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
2408 fill_cmd(cmd, O_ESTAB, 0);
2409
2410 prev = cmd;
2411 cmd = next_cmd(cmd);
2412 }
2413
2414 /* TCP options and flags */
2415 if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
2416 if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
2417 compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
2418 fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ((TH_ACK) & 0xff) << 8);
2419
2420 prev = cmd;
2421 cmd = next_cmd(cmd);
2422 } else {
2423 fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
2424 (compat_rule->fw_tcpnf & 0xff) << 8);
2425
2426 prev = cmd;
2427 cmd = next_cmd(cmd);
2428 }
2429 }
2430 if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
2431 fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
2432 (compat_rule->fw_tcpnopt & 0xff) << 8);
2433
2434 prev = cmd;
2435 cmd = next_cmd(cmd);
2436 }
2437 }
2438
2439 /* ICMP */
2440 /* XXX: check this */
2441 if (flag & IP_FW_F_ICMPBIT_COMPAT) {
2442 int i;
2443 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2444
2445 cmd32->o.opcode = O_ICMPTYPE;
2446 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2447
2448 for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
2449 cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
2450 }
2451
2452 prev = cmd;
2453 cmd = next_cmd(cmd);
2454 }
2455 } /* end commands */
2456
2457 done:
2458 /* finally, copy everything into the current
2459 * rule buffer in the right order.
2460 */
2461 dst = curr_rule->cmd;
2462
2463 /* first, do match probability */
2464 if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
2465 dst->opcode = O_PROB;
2466 dst->len = 2;
2467 *((int32_t *)(dst + 1)) = compat_rule->pipe_ptr;
2468 dst += dst->len;
2469 }
2470
2471 /* generate O_PROBE_STATE if necessary */
2472 if (have_state && have_state->opcode != O_CHECK_STATE) {
2473 fill_cmd(dst, O_PROBE_STATE, 0);
2474 dst = next_cmd(dst);
2475 }
2476
2477 /*
2478 * copy all commands but O_LOG, O_KEEP_STATE
2479 */
2480 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
2481 k = F_LEN(src);
2482
2483 switch (src->opcode) {
2484 case O_LOG:
2485 case O_KEEP_STATE:
2486 break;
2487 default:
2488 bcopy(src, dst, k * sizeof(uint32_t));
2489 dst += k;
2490 }
2491 }
2492
2493 /*
2494 * put back the have_state command as last opcode
2495 */
2496 if (have_state && have_state->opcode != O_CHECK_STATE) {
2497 k = F_LEN(have_state);
2498 bcopy(have_state, dst, k * sizeof(uint32_t));
2499 dst += k;
2500 }
2501
2502 /*
2503 * start action section
2504 */
2505 curr_rule->act_ofs = dst - curr_rule->cmd;
2506
2507 /*
2508 * put back O_LOG if necessary
2509 */
2510 src = (ipfw_insn *)cmdbuf;
2511 if (src->opcode == O_LOG) {
2512 k = F_LEN(src);
2513 bcopy(src, dst, k * sizeof(uint32_t));
2514 dst += k;
2515 }
2516
2517 /*
2518 * copy all other actions
2519 */
2520 for (src = (ipfw_insn *)actbuf; src != action; src += k) {
2521 k = F_LEN(src);
2522 bcopy(src, dst, k * sizeof(uint32_t));
2523 dst += k;
2524 }
2525
2526 curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
2527
2528 return;
2529 }
2530
2531 static void
2532 ipfw_convert_to_cmds_64(struct ip_fw *curr_rule, struct ip_fw_compat_64 *compat_rule)
2533 {
2534 int k;
2535 uint32_t actbuf[255], cmdbuf[255];
2536 ipfw_insn *action, *cmd, *src, *dst;
2537 ipfw_insn *have_state = NULL; /* track check-state or keep-state */
2538
2539 if (!compat_rule || !curr_rule) {
2540 return;
2541 }
2542
2543 /* preemptively check the old ip_fw rule to
2544 * make sure it's valid before starting to copy stuff
2545 */
2546 if (ipfw_check_vers1_struct_64(compat_rule)) {
2547 /* bad rule */
2548 return;
2549 }
2550
2551 bzero(actbuf, sizeof(actbuf)); /* actions go here */
2552 bzero(cmdbuf, sizeof(cmdbuf));
2553 /* fill in action */
2554 action = (ipfw_insn *)actbuf;
2555 {
2556 u_int flag = compat_rule->fw_flg;
2557
2558 action->len = 1; /* default */
2559
2560 if (flag & IP_FW_F_CHECK_S_COMPAT) {
2561 have_state = action;
2562 action->opcode = O_CHECK_STATE;
2563 } else {
2564 switch (flag & IP_FW_F_COMMAND_COMPAT) {
2565 case IP_FW_F_ACCEPT_COMPAT:
2566 action->opcode = O_ACCEPT;
2567 break;
2568 case IP_FW_F_COUNT_COMPAT:
2569 action->opcode = O_COUNT;
2570 break;
2571 case IP_FW_F_PIPE_COMPAT:
2572 action->opcode = O_PIPE;
2573 action->len = F_INSN_SIZE(ipfw_insn_pipe);
2574 action->arg1 = compat_rule->fw_divert_port_compat;
2575 break;
2576 case IP_FW_F_QUEUE_COMPAT:
2577 action->opcode = O_QUEUE;
2578 action->len = F_INSN_SIZE(ipfw_insn_pipe);
2579 action->arg1 = compat_rule->fw_divert_port_compat;
2580 break;
2581 case IP_FW_F_SKIPTO_COMPAT:
2582 action->opcode = O_SKIPTO;
2583 action->arg1 = compat_rule->fw_skipto_rule_compat;
2584 break;
2585 case IP_FW_F_DIVERT_COMPAT:
2586 action->opcode = O_DIVERT;
2587 action->arg1 = compat_rule->fw_divert_port_compat;
2588 break;
2589 case IP_FW_F_TEE_COMPAT:
2590 action->opcode = O_TEE;
2591 action->arg1 = compat_rule->fw_divert_port_compat;
2592 break;
2593 case IP_FW_F_FWD_COMPAT:
2594 {
2595 ipfw_insn_sa *p = (ipfw_insn_sa *)action;
2596
2597 action->opcode = O_FORWARD_IP;
2598 action->len = F_INSN_SIZE(ipfw_insn_sa);
2599
2600 p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
2601 p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
2602 p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
2603 p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
2604
2605 break;
2606 }
2607 case IP_FW_F_DENY_COMPAT:
2608 action->opcode = O_DENY;
2609 action->arg1 = 0;
2610 break;
2611 case IP_FW_F_REJECT_COMPAT:
2612 action->opcode = O_REJECT;
2613 action->arg1 = compat_rule->fw_reject_code_compat;
2614 break;
2615 default:
2616 action->opcode = O_NOP;
2617 break;
2618 }
2619 }
2620
2621 /* action is mandatory */
2622 if (action->opcode == O_NOP) {
2623 return;
2624 }
2625
2626 action = next_cmd(action);
2627 } /* end actions */
2628
2629 cmd = (ipfw_insn *)cmdbuf;
2630
2631 /* this is O_CHECK_STATE, we're done */
2632 if (have_state) {
2633 goto done;
2634 }
2635
2636 {
2637 ipfw_insn *prev = NULL;
2638 u_int flag = compat_rule->fw_flg;
2639
2640 /* logging */
2641 if (flag & IP_FW_F_PRN_COMPAT) {
2642 ipfw_insn_log *c = (ipfw_insn_log *)cmd;
2643
2644 cmd->opcode = O_LOG;
2645 cmd->len |= F_INSN_SIZE(ipfw_insn_log);
2646 c->max_log = compat_rule->fw_logamount;
2647
2648 prev = cmd;
2649 cmd = next_cmd(cmd);
2650 }
2651
2652 /* protocol */
2653 if (compat_rule->fw_prot != 0) {
2654 fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
2655 prev = cmd;
2656 cmd = next_cmd(cmd);
2657 }
2658
2659 /* source */
2660 if (flag & IP_FW_F_SME_COMPAT) {
2661 cmd->opcode = O_IP_SRC_ME;
2662 cmd->len |= F_INSN_SIZE(ipfw_insn);
2663 if (flag & IP_FW_F_INVSRC_COMPAT) {
2664 cmd->len ^= F_NOT; /* toggle F_NOT */
2665 }
2666
2667 prev = cmd;
2668 cmd = next_cmd(cmd);
2669 } else {
2670 if (compat_rule->fw_smsk.s_addr != 0) {
2671 /* addr/mask */
2672 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
2673
2674 ip->addr = compat_rule->fw_src;
2675 ip->mask = compat_rule->fw_smsk;
2676 cmd->opcode = O_IP_SRC_MASK;
2677 cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2678 } else {
2679 /* one IP */
2680 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2681
2682 if (compat_rule->fw_src.s_addr == 0) {
2683 /* any */
2684 cmd32->o.len &= ~F_LEN_MASK; /* zero len */
2685 } else {
2686 cmd32->d[0] = compat_rule->fw_src.s_addr;
2687 cmd32->o.opcode = O_IP_SRC;
2688 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2689 }
2690 }
2691
2692 if (flag & IP_FW_F_INVSRC_COMPAT) {
2693 cmd->len ^= F_NOT; /* toggle F_NOT */
2694 }
2695
2696 if (F_LEN(cmd) != 0) { /* !any */
2697 prev = cmd;
2698 cmd = next_cmd(cmd);
2699 }
2700 }
2701
2702 /* source ports */
2703 {
2704 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
2705 uint16_t *p = ports->ports;
2706 int i, j = 0,
2707 nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
2708 have_range = 0;
2709
2710 cmd->opcode = O_IP_SRCPORT;
2711 for (i = 0; i < nports; i++) {
2712 if (((flag & IP_FW_F_SRNG_COMPAT) ||
2713 (flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
2714 p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2715 p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2716 have_range = 1;
2717 } else {
2718 p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2719 }
2720 p += 2;
2721 j++;
2722 }
2723
2724 if (j > 0) {
2725 ports->o.len |= j + 1; /* leave F_NOT and F_OR untouched */
2726 }
2727
2728 prev = cmd;
2729 cmd = next_cmd(cmd);
2730 }
2731
2732 /* destination */
2733 if (flag & IP_FW_F_DME_COMPAT) {
2734 cmd->opcode = O_IP_DST_ME;
2735 cmd->len |= F_INSN_SIZE(ipfw_insn);
2736 if (flag & IP_FW_F_INVDST_COMPAT) {
2737 cmd->len ^= F_NOT; /* toggle F_NOT */
2738 }
2739
2740 prev = cmd;
2741 cmd = next_cmd(cmd);
2742 } else {
2743 if (compat_rule->fw_dmsk.s_addr != 0) {
2744 /* addr/mask */
2745 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
2746
2747 ip->addr = compat_rule->fw_dst;
2748 ip->mask = compat_rule->fw_dmsk;
2749 cmd->opcode = O_IP_DST_MASK;
2750 cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2751 } else {
2752 /* one IP */
2753 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2754
2755 if (compat_rule->fw_dst.s_addr == 0) {
2756 /* any */
2757 cmd32->o.len &= ~F_LEN_MASK; /* zero len */
2758 } else {
2759 cmd32->d[0] = compat_rule->fw_dst.s_addr;
2760 cmd32->o.opcode = O_IP_DST;
2761 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2762 }
2763 }
2764
2765 if (flag & IP_FW_F_INVDST_COMPAT) {
2766 cmd->len ^= F_NOT; /* toggle F_NOT */
2767 }
2768
2769 if (F_LEN(cmd) != 0) { /* !any */
2770 prev = cmd;
2771 cmd = next_cmd(cmd);
2772 }
2773 }
2774
2775 /* dest. ports */
2776 {
2777 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
2778 uint16_t *p = ports->ports;
2779 int i = IP_FW_GETNSRCP_COMPAT(compat_rule),
2780 j = 0,
2781 nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
2782 have_range = 0;
2783
2784 cmd->opcode = O_IP_DSTPORT;
2785 for (; i < nports; i++, p += 2) {
2786 if (((flag & IP_FW_F_DRNG_COMPAT) ||
2787 (flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
2788 /* range */
2789 p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2790 p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2791 have_range = 1;
2792 } else {
2793 p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2794 }
2795 j++;
2796 }
2797
2798 if (j > 0) {
2799 ports->o.len |= j + 1; /* leave F_NOT and F_OR untouched */
2800 }
2801
2802 prev = cmd;
2803 cmd = next_cmd(cmd);
2804 }
2805
2806 if (flag & IP_FW_F_UID_COMPAT) {
2807 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2808
2809 cmd32->o.opcode = O_UID;
2810 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2811 cmd32->d[0] = compat_rule->fw_uid;
2812
2813 prev = cmd;
2814 cmd = next_cmd(cmd);
2815 }
2816
2817 if (flag & IP_FW_F_KEEP_S_COMPAT) {
2818 have_state = cmd;
2819 fill_cmd(cmd, O_KEEP_STATE, 0);
2820
2821 prev = cmd;
2822 cmd = next_cmd(cmd);
2823 }
2824 if (flag & IP_FW_BRIDGED_COMPAT) {
2825 fill_cmd(cmd, O_LAYER2, 0);
2826
2827 prev = cmd;
2828 cmd = next_cmd(cmd);
2829 }
2830
2831 if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
2832 /* via */
2833 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
2834 union ip_fw_if_compat ifu = compat_rule->fw_in_if;
2835
2836 cmd->opcode = O_VIA;
2837 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2838
2839 if (ifu.fu_via_ip.s_addr == 0) {
2840 /* "any" */
2841 ifcmd->name[0] = '\0';
2842 ifcmd->o.len = 0;
2843 } else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
2844 /* by name */
2845 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2846 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2847 } else {
2848 /* by addr */
2849 ifcmd->p.ip = ifu.fu_via_ip;
2850 }
2851
2852 prev = cmd;
2853 cmd = next_cmd(cmd);
2854 } else {
2855 if (flag & IP_FW_F_IN_COMPAT) {
2856 fill_cmd(cmd, O_IN, 0);
2857
2858 prev = cmd;
2859 cmd = next_cmd(cmd);
2860 }
2861 if (flag & IP_FW_F_OUT_COMPAT) {
2862 /* if the previous command was O_IN, and this
2863 * is being set as well, it's equivalent to not
2864 * having either command, so let's back up prev
2865 * to the cmd before it and move cmd to prev.
2866 */
2867 if (prev->opcode == O_IN) {
2868 cmd = prev;
2869 bzero(cmd, sizeof(*cmd));
2870 } else {
2871 cmd->len ^= F_NOT; /* toggle F_NOT */
2872 fill_cmd(cmd, O_IN, 0);
2873
2874 prev = cmd;
2875 cmd = next_cmd(cmd);
2876 }
2877 }
2878 if (flag & IP_FW_F_OIFACE_COMPAT) {
2879 /* xmit */
2880 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
2881 union ip_fw_if_compat ifu = compat_rule->fw_out_if;
2882
2883 cmd->opcode = O_XMIT;
2884 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2885
2886 if (ifu.fu_via_ip.s_addr == 0) {
2887 /* "any" */
2888 ifcmd->name[0] = '\0';
2889 ifcmd->o.len = 0;
2890 } else if (flag & IP_FW_F_OIFNAME_COMPAT) {
2891 /* by name */
2892 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2893 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2894 } else {
2895 /* by addr */
2896 ifcmd->p.ip = ifu.fu_via_ip;
2897 }
2898
2899 prev = cmd;
2900 cmd = next_cmd(cmd);
2901 } else if (flag & IP_FW_F_IIFACE_COMPAT) {
2902 /* recv */
2903 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
2904 union ip_fw_if_compat ifu = compat_rule->fw_in_if;
2905
2906 cmd->opcode = O_RECV;
2907 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2908
2909 if (ifu.fu_via_ip.s_addr == 0) {
2910 /* "any" */
2911 ifcmd->name[0] = '\0';
2912 ifcmd->o.len = 0;
2913 } else if (flag & IP_FW_F_IIFNAME_COMPAT) {
2914 /* by name */
2915 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2916 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2917 } else {
2918 /* by addr */
2919 ifcmd->p.ip = ifu.fu_via_ip;
2920 }
2921
2922 prev = cmd;
2923 cmd = next_cmd(cmd);
2924 }
2925 }
2926
2927 if (flag & IP_FW_F_FRAG_COMPAT) {
2928 fill_cmd(cmd, O_FRAG, 0);
2929
2930 prev = cmd;
2931 cmd = next_cmd(cmd);
2932 }
2933
2934 /* IP options */
2935 if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
2936 fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
2937 (compat_rule->fw_ipnopt & 0xff) << 8);
2938
2939 prev = cmd;
2940 cmd = next_cmd(cmd);
2941 }
2942
2943 if (compat_rule->fw_prot == IPPROTO_TCP) {
2944 if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
2945 fill_cmd(cmd, O_ESTAB, 0);
2946
2947 prev = cmd;
2948 cmd = next_cmd(cmd);
2949 }
2950
2951 /* TCP options and flags */
2952 if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
2953 if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
2954 compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
2955 fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ((TH_ACK) & 0xff) << 8);
2956
2957 prev = cmd;
2958 cmd = next_cmd(cmd);
2959 } else {
2960 fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
2961 (compat_rule->fw_tcpnf & 0xff) << 8);
2962
2963 prev = cmd;
2964 cmd = next_cmd(cmd);
2965 }
2966 }
2967 if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
2968 fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
2969 (compat_rule->fw_tcpnopt & 0xff) << 8);
2970
2971 prev = cmd;
2972 cmd = next_cmd(cmd);
2973 }
2974 }
2975
2976 /* ICMP */
2977 /* XXX: check this */
2978 if (flag & IP_FW_F_ICMPBIT_COMPAT) {
2979 int i;
2980 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;/* alias for cmd */
2981 cmd32->o.opcode = O_ICMPTYPE;
2982 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2983
2984 for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
2985 cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
2986 }
2987
2988 prev = cmd;
2989 cmd = next_cmd(cmd);
2990 }
2991 } /* end commands */
2992 done:
2993 /* finally, copy everything into the current
2994 * rule buffer in the right order.
2995 */
2996 dst = curr_rule->cmd;
2997
2998 /* first, do match probability */
2999 if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
3000 dst->opcode = O_PROB;
3001 dst->len = 2;
3002 *((int32_t *)(dst + 1)) = compat_rule->pipe_ptr;
3003 dst += dst->len;
3004 }
3005
3006 /* generate O_PROBE_STATE if necessary */
3007 if (have_state && have_state->opcode != O_CHECK_STATE) {
3008 fill_cmd(dst, O_PROBE_STATE, 0);
3009 dst = next_cmd(dst);
3010 }
3011
3012 /*
3013 * copy all commands but O_LOG, O_KEEP_STATE
3014 */
3015 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
3016 k = F_LEN(src);
3017 switch (src->opcode) {
3018 case O_LOG:
3019 case O_KEEP_STATE:
3020 break;
3021 default:
3022 bcopy(src, dst, k * sizeof(uint32_t));
3023 dst += k;
3024 }
3025 }
3026
3027 /*
3028 * put back the have_state command as last opcode
3029 */
3030 if (have_state && have_state->opcode != O_CHECK_STATE) {
3031 k = F_LEN(have_state);
3032 bcopy(have_state, dst, k * sizeof(uint32_t));
3033 dst += k;
3034 }
3035
3036 /*
3037 * start action section
3038 */
3039 curr_rule->act_ofs = dst - curr_rule->cmd;
3040
3041 /*
3042 * put back O_LOG if necessary
3043 */
3044 src = (ipfw_insn *)cmdbuf;
3045 if (src->opcode == O_LOG) {
3046 k = F_LEN(src);
3047 bcopy(src, dst, k * sizeof(uint32_t));
3048 dst += k;
3049 }
3050
3051 /*
3052 * copy all other actions
3053 */
3054 for (src = (ipfw_insn *)actbuf; src != action; src += k) {
3055 k = F_LEN(src);
3056 bcopy(src, dst, k * sizeof(uint32_t));
3057 dst += k;
3058 }
3059
3060 curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
3061 return;
3062 }
3063
3064 static int
3065 ipfw_version_one_to_version_two_32(struct sockopt *sopt, struct ip_fw *curr_rule,
3066 struct ip_fw_compat_32 *rule_vers1)
3067 {
3068 int err = EINVAL;
3069 struct ip_fw_compat_32 *rule_ptr;
3070 struct ip_fw_compat_32 rule;
3071
3072 if (rule_vers1) {
3073 rule_ptr = rule_vers1;
3074 err = 0;
3075 } else {
3076 /* do some basic size checking here, more extensive checking later */
3077 if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_32)) {
3078 return err;
3079 }
3080
3081 if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_32),
3082 sizeof(struct ip_fw_compat_32)))) {
3083 return err;
3084 }
3085
3086 rule_ptr = &rule;
3087 }
3088
3089 /* deal with commands */
3090 ipfw_convert_to_cmds_32(curr_rule, rule_ptr);
3091
3092 curr_rule->version = IP_FW_CURRENT_API_VERSION;
3093 curr_rule->context = CAST_DOWN_EXPLICIT(void*, rule_ptr->context);
3094 curr_rule->rulenum = rule_ptr->fw_number;
3095 curr_rule->pcnt = rule_ptr->fw_pcnt;
3096 curr_rule->bcnt = rule_ptr->fw_bcnt;
3097 curr_rule->timestamp = rule_ptr->timestamp;
3098
3099
3100 #if FW2_DEBUG_VERBOSE
3101 ipfw_print_vers2_struct(curr_rule);
3102 #endif
3103
3104 return err;
3105 }
3106
3107 static int
3108 ipfw_version_one_to_version_two_64(struct sockopt *sopt, struct ip_fw *curr_rule,
3109 struct ip_fw_compat_64 *rule_vers1)
3110 {
3111 int err = EINVAL;
3112 struct ip_fw_compat_64 *rule_ptr;
3113 struct ip_fw_compat_64 rule;
3114
3115 if (rule_vers1) {
3116 rule_ptr = rule_vers1;
3117 err = 0;
3118 } else {
3119 /* do some basic size checking here, more extensive checking later */
3120 if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_64)) {
3121 return err;
3122 }
3123
3124 if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_64),
3125 sizeof(struct ip_fw_compat_64)))) {
3126 return err;
3127 }
3128 rule_ptr = &rule;
3129 }
3130
3131 /* deal with commands */
3132 ipfw_convert_to_cmds_64(curr_rule, rule_ptr);
3133
3134 curr_rule->version = IP_FW_CURRENT_API_VERSION;
3135 curr_rule->context = CAST_DOWN_EXPLICIT( void *, rule_ptr->context);
3136 curr_rule->rulenum = rule_ptr->fw_number;
3137 curr_rule->pcnt = rule_ptr->fw_pcnt;
3138 curr_rule->bcnt = rule_ptr->fw_bcnt;
3139 curr_rule->timestamp = rule_ptr->timestamp;
3140
3141
3142 #if FW2_DEBUG_VERBOSE
3143 ipfw_print_vers2_struct(curr_rule);
3144 #endif
3145
3146 return err;
3147 }
3148
3149 /* This converts to whatever the latest version is. Currently the
3150 * latest version of the firewall is ipfw2.
3151 */
3152 static int
3153 ipfw_version_one_to_latest_32(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_32 *rule_vers1)
3154 {
3155 int err;
3156
3157 /* if rule_vers1 is not null then this is coming from
3158 * ipfw_version_zero_to_latest(), so pass that along;
3159 * otherwise let ipfw_version_one_to_version_two()
3160 * get the rule from sopt.
3161 */
3162 err = ipfw_version_one_to_version_two_32(sopt, curr_rule, rule_vers1);
3163
3164 return err;
3165 }
3166
3167 static int
3168 ipfw_version_one_to_latest_64(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_64 *rule_vers1)
3169 {
3170 int err;
3171
3172 /* if rule_vers1 is not null then this is coming from
3173 * ipfw_version_zero_to_latest(), so pass that along;
3174 * otherwise let ipfw_version_one_to_version_two()
3175 * get the rule from sopt.
3176 */
3177 err = ipfw_version_one_to_version_two_64(sopt, curr_rule, rule_vers1);
3178
3179 return err;
3180 }
3181
3182
3183 #if 0
3184
3185 /*
3186 * XXX - ipfw_version_zero_to_one
3187 *
3188 * This function is only used in version #1 of ipfw, which is now deprecated.
3189 *
3190 */
3191
3192 static void
3193 ipfw_version_zero_to_one(struct ip_old_fw *rule_vers0, struct ip_fw_compat *rule_vers1)
3194 {
3195 bzero(rule_vers1, sizeof(struct ip_fw_compat));
3196 bcopy(&rule_vers0->fw_uar, &rule_vers1->fw_uar_compat, sizeof(rule_vers0->fw_uar));
3197 bcopy(&rule_vers0->fw_in_if, &rule_vers1->fw_in_if, sizeof(rule_vers0->fw_in_if));
3198 bcopy(&rule_vers0->fw_out_if, &rule_vers1->fw_out_if, sizeof(rule_vers0->fw_out_if));
3199 bcopy(&rule_vers0->fw_un, &rule_vers1->fw_un_compat, sizeof(rule_vers0->fw_un));
3200
3201 rule_vers1->version = 10;
3202 rule_vers1->fw_pcnt = rule_vers0->fw_pcnt;
3203 rule_vers1->fw_bcnt = rule_vers0->fw_bcnt;
3204 rule_vers1->fw_src = rule_vers0->fw_src;
3205 rule_vers1->fw_dst = rule_vers0->fw_dst;
3206 rule_vers1->fw_smsk = rule_vers0->fw_smsk;
3207 rule_vers1->fw_dmsk = rule_vers0->fw_dmsk;
3208 rule_vers1->fw_number = rule_vers0->fw_number;
3209 rule_vers1->fw_flg = rule_vers0->fw_flg;
3210 rule_vers1->fw_ipopt = rule_vers0->fw_ipopt;
3211 rule_vers1->fw_ipnopt = rule_vers0->fw_ipnopt;
3212 rule_vers1->fw_tcpf = rule_vers0->fw_tcpf & ~IP_OLD_FW_TCPF_ESTAB;
3213 rule_vers1->fw_tcpnf = rule_vers0->fw_tcpnf;
3214 rule_vers1->timestamp = rule_vers0->timestamp;
3215 rule_vers1->fw_prot = rule_vers0->fw_prot;
3216 rule_vers1->fw_nports = rule_vers0->fw_nports;
3217 rule_vers1->pipe_ptr = rule_vers0->pipe_ptr;
3218 rule_vers1->next_rule_ptr = rule_vers0->next_rule_ptr;
3219 rule_vers1->fw_ipflg = (rule_vers0->fw_tcpf & IP_OLD_FW_TCPF_ESTAB) ? IP_FW_IF_TCPEST_COMPAT : 0;
3220 }
3221
3222 #endif /* !ipfw_version_zero_to_one */
3223
3224 /* rule is a u_int32_t buffer[255] into which the converted
3225 * (if necessary) rules go.
3226 */
3227 int
3228 ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version, int is64user)
3229 {
3230 int err = 0;
3231
3232 /* the following functions copy the rules passed in and
3233 * convert to latest structures based on version
3234 */
3235 switch (api_version) {
3236 case IP_FW_VERSION_0:
3237 /* we're not supporting VERSION 0 */
3238 err = EOPNOTSUPP;
3239 break;
3240
3241 case IP_FW_VERSION_1:
3242 /* this is the version supported in Panther */
3243 if (is64user) {
3244 err = ipfw_version_one_to_latest_64(sopt, curr_rule, NULL);
3245 } else {
3246 err = ipfw_version_one_to_latest_32(sopt, curr_rule, NULL);
3247 }
3248 break;
3249
3250 case IP_FW_CURRENT_API_VERSION:
3251 /* IPFW2 for now */
3252 /* do nothing here... */
3253 break;
3254
3255 default:
3256 /* unrecognized/unsupported version */
3257 err = EINVAL;
3258 break;
3259 }
3260
3261 return err;
3262 }
3263
3264 int
3265 ipfw_get_command_and_version(struct sockopt *sopt, int *command, u_int32_t *api_version)
3266 {
3267 int cmd;
3268 int err = 0;
3269 u_int32_t vers = IP_FW_VERSION_NONE;
3270
3271 /* first deal with the oldest version */
3272 if (sopt->sopt_name == IP_OLD_FW_GET) {
3273 vers = IP_FW_VERSION_0;
3274 cmd = IP_FW_GET;
3275 } else if (sopt->sopt_name == IP_OLD_FW_FLUSH) {
3276 vers = IP_FW_VERSION_0;
3277 cmd = IP_FW_FLUSH;
3278 } else if (sopt->sopt_name == IP_OLD_FW_ZERO) {
3279 vers = IP_FW_VERSION_0;
3280 cmd = IP_FW_ZERO;
3281 } else if (sopt->sopt_name == IP_OLD_FW_ADD) {
3282 vers = IP_FW_VERSION_0;
3283 cmd = IP_FW_ADD;
3284 } else if (sopt->sopt_name == IP_OLD_FW_DEL) {
3285 vers = IP_FW_VERSION_0;
3286 cmd = IP_FW_DEL;
3287 } else if (sopt->sopt_name == IP_OLD_FW_RESETLOG) {
3288 vers = IP_FW_VERSION_0;
3289 cmd = IP_FW_RESETLOG;
3290 } else {
3291 cmd = sopt->sopt_name;
3292 }
3293
3294 if (vers == IP_FW_VERSION_NONE) {
3295 /* working off the fact that the offset
3296 * is the same in both structs.
3297 */
3298 struct ip_fw_64 rule;
3299 size_t copyinsize;
3300
3301 if (proc_is64bit(sopt->sopt_p)) {
3302 copyinsize = sizeof(struct ip_fw_64);
3303 } else {
3304 copyinsize = sizeof(struct ip_fw_32);
3305 }
3306
3307 if (!sopt->sopt_val || sopt->sopt_valsize < copyinsize) {
3308 return EINVAL;
3309 }
3310 if ((err = sooptcopyin(sopt, &rule, copyinsize, copyinsize))) {
3311 return err;
3312 }
3313
3314 vers = rule.version;
3315 }
3316
3317 if (command) {
3318 *command = cmd;
3319 }
3320 if (api_version) {
3321 *api_version = vers;
3322 }
3323
3324 return err;
3325 }