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