]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_fw2_compat.c
xnu-1228.9.59.tar.gz
[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 static struct _s_x f_tcpflags[] = {
71 { "syn", TH_SYN },
72 { "fin", TH_FIN },
73 { "ack", TH_ACK },
74 { "psh", TH_PUSH },
75 { "rst", TH_RST },
76 { "urg", TH_URG },
77 { "tcp flag", 0 },
78 { NULL, 0 }
79 };
80
81 static struct _s_x f_tcpopts[] = {
82 { "mss", IP_FW_TCPOPT_MSS },
83 { "maxseg", IP_FW_TCPOPT_MSS },
84 { "window", IP_FW_TCPOPT_WINDOW },
85 { "sack", IP_FW_TCPOPT_SACK },
86 { "ts", IP_FW_TCPOPT_TS },
87 { "timestamp", IP_FW_TCPOPT_TS },
88 { "cc", IP_FW_TCPOPT_CC },
89 { "tcp option", 0 },
90 { NULL, 0 }
91 };
92
93 /*
94 * IP options span the range 0 to 255 so we need to remap them
95 * (though in fact only the low 5 bits are significant).
96 */
97 static struct _s_x f_ipopts[] = {
98 { "ssrr", IP_FW_IPOPT_SSRR},
99 { "lsrr", IP_FW_IPOPT_LSRR},
100 { "rr", IP_FW_IPOPT_RR},
101 { "ts", IP_FW_IPOPT_TS},
102 { "ip option", 0 },
103 { NULL, 0 }
104 };
105
106 static struct _s_x f_iptos[] = {
107 { "lowdelay", IPTOS_LOWDELAY},
108 { "throughput", IPTOS_THROUGHPUT},
109 { "reliability", IPTOS_RELIABILITY},
110 { "mincost", IPTOS_MINCOST},
111 { "congestion", IPTOS_CE},
112 { "ecntransport", IPTOS_ECT},
113 { "ip tos option", 0},
114 { NULL, 0 }
115 };
116
117 static struct _s_x limit_masks[] = {
118 {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
119 {"src-addr", DYN_SRC_ADDR},
120 {"src-port", DYN_SRC_PORT},
121 {"dst-addr", DYN_DST_ADDR},
122 {"dst-port", DYN_DST_PORT},
123 {NULL, 0}
124 };
125
126 static void
127 ipfw_print_fw_flags(u_int flags)
128 {
129 /* print action */
130 switch (flags & IP_FW_F_COMMAND_COMPAT) {
131 case IP_FW_F_ACCEPT_COMPAT:
132 printf("IP_FW_F_ACCEPT_COMPAT\n");
133 break;
134 case IP_FW_F_COUNT_COMPAT:
135 printf("IP_FW_F_COUNT_COMPAT\n");
136 break;
137 case IP_FW_F_PIPE_COMPAT:
138 printf("IP_FW_F_PIPE_COMPAT\n");
139 break;
140 case IP_FW_F_QUEUE_COMPAT:
141 printf("IP_FW_F_QUEUE_COMPAT\n");
142 break;
143 case IP_FW_F_SKIPTO_COMPAT:
144 printf("IP_FW_F_SKIPTO_COMPAT\n");
145 break;
146 case IP_FW_F_DIVERT_COMPAT:
147 printf("IP_FW_F_DIVERT_COMPAT\n");
148 break;
149 case IP_FW_F_TEE_COMPAT:
150 printf("IP_FW_F_TEE_COMPAT\n");
151 break;
152 case IP_FW_F_FWD_COMPAT:
153 printf("IP_FW_F_FWD_COMPAT\n");
154 break;
155 case IP_FW_F_DENY_COMPAT:
156 printf("IP_FW_F_DENY_COMPAT\n");
157 break;
158 case IP_FW_F_REJECT_COMPAT:
159 printf("IP_FW_F_REJECT_COMPAT\n");
160 break;
161 case IP_FW_F_CHECK_S_COMPAT:
162 printf("IP_FW_F_CHECK_S_COMPAT\n");
163 break;
164 default:
165 printf("No action given\n");
166 break;
167 }
168
169 /* print commands */
170 if (flags & IP_FW_F_IN_COMPAT) {
171 printf("IP_FW_F_IN_COMPAT\n");
172 }
173 if (flags & IP_FW_F_OUT_COMPAT) {
174 printf("IP_FW_F_OUT_COMPAT\n");
175 }
176 if (flags & IP_FW_F_IIFACE_COMPAT) {
177 printf("IP_FW_F_IIFACE_COMPAT\n");
178 }
179 if (flags & IP_FW_F_OIFACE_COMPAT) {
180 printf("IP_FW_F_OIFACE_COMPAT\n");
181 }
182 if (flags & IP_FW_F_PRN_COMPAT) {
183 printf("IP_FW_F_PRN_COMPAT\n");
184 }
185 if (flags & IP_FW_F_SRNG_COMPAT) {
186 printf("IP_FW_F_SRNG_COMPAT\n");
187 }
188 if (flags & IP_FW_F_DRNG_COMPAT) {
189 printf("IP_FW_F_DRNG_COMPAT\n");
190 }
191 if (flags & IP_FW_F_FRAG_COMPAT) {
192 printf("IP_FW_F_FRAG_COMPAT\n");
193 }
194 if (flags & IP_FW_F_IIFNAME_COMPAT) {
195 printf("IP_FW_F_IIFNAME_COMPAT\n");
196 }
197 if (flags & IP_FW_F_OIFNAME_COMPAT) {
198 printf("IP_FW_F_OIFNAME_COMPAT\n");
199 }
200 if (flags & IP_FW_F_INVSRC_COMPAT) {
201 printf("IP_FW_F_INVSRC_COMPAT\n");
202 }
203 if (flags & IP_FW_F_INVDST_COMPAT) {
204 printf("IP_FW_F_INVDST_COMPAT\n");
205 }
206 if (flags & IP_FW_F_ICMPBIT_COMPAT) {
207 printf("IP_FW_F_ICMPBIT_COMPAT\n");
208 }
209 if (flags & IP_FW_F_UID_COMPAT) {
210 printf("IP_FW_F_UID_COMPAT\n");
211 }
212 if (flags & IP_FW_F_RND_MATCH_COMPAT) {
213 printf("IP_FW_F_RND_MATCH_COMPAT\n");
214 }
215 if (flags & IP_FW_F_SMSK_COMPAT) {
216 printf("IP_FW_F_SMSK_COMPAT\n");
217 }
218 if (flags & IP_FW_F_DMSK_COMPAT) {
219 printf("IP_FW_F_DMSK_COMPAT\n");
220 }
221 if (flags & IP_FW_BRIDGED_COMPAT) {
222 printf("IP_FW_BRIDGED_COMPAT\n");
223 }
224 if (flags & IP_FW_F_KEEP_S_COMPAT) {
225 printf("IP_FW_F_KEEP_S_COMPAT\n");
226 }
227 if (flags & IP_FW_F_CHECK_S_COMPAT) {
228 printf("IP_FW_F_CHECK_S_COMPAT\n");
229 }
230 if (flags & IP_FW_F_SME_COMPAT) {
231 printf("IP_FW_F_SME_COMPAT\n");
232 }
233 if (flags & IP_FW_F_DME_COMPAT) {
234 printf("IP_FW_F_DME_COMPAT\n");
235 }
236 }
237
238 static void
239 print_fw_version(u_int32_t api_version)
240 {
241 switch (api_version) {
242 case IP_FW_VERSION_0:
243 printf("Version: %s\n", VERSION_ZERO_STR);
244 break;
245 case IP_FW_VERSION_1:
246 printf("Version: %s\n", VERSION_ONE_STR);
247 break;
248 case IP_FW_CURRENT_API_VERSION:
249 printf("Version: %s\n", CURRENT_API_VERSION_STR);
250 break;
251 case IP_FW_VERSION_NONE:
252 printf("Version: %s\n", NO_VERSION_STR);
253 break;
254 default:
255 printf("Unrecognized version\n");
256 break;
257 }
258 }
259
260 static void
261 ipfw_print_vers1_struct(struct ip_fw_compat *vers1_rule)
262 {
263 char ipv4str[MAX_IPv4_STR_LEN];
264 print_fw_version(vers1_rule->version);
265 printf("Rule #%d\n", vers1_rule->fw_number);
266
267 ipfw_print_fw_flags(vers1_rule->fw_flg);
268
269 printf("fw_pcnt: %llu\n", vers1_rule->fw_pcnt);
270 printf("fw_bcnt: %llu\n", vers1_rule->fw_bcnt);
271 printf("fw_src: %s\n",
272 inet_ntop(AF_INET, &vers1_rule->fw_src, ipv4str, sizeof(ipv4str)));
273 printf("fw_dst: %s\n",
274 inet_ntop(AF_INET, &vers1_rule->fw_dst, ipv4str, sizeof(ipv4str)));
275 printf("fw_smsk: %s\n",
276 inet_ntop(AF_INET, &vers1_rule->fw_smsk, ipv4str, sizeof(ipv4str)));
277 printf("fw_dmsk: %s\n",
278 inet_ntop(AF_INET, &vers1_rule->fw_dmsk, ipv4str, sizeof(ipv4str)));
279
280 if (vers1_rule->fw_flg & IP_FW_F_ICMPBIT_COMPAT) {
281 int type_index;
282 int first = 1;
283
284 printf(" icmptype");
285
286 for (type_index = 0;
287 type_index < (IP_FW_ICMPTYPES_DIM_COMPAT * sizeof(unsigned) * 8);
288 ++type_index) {
289 if (vers1_rule->fw_uar_compat.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
290 (1U << (type_index % (sizeof(unsigned) * 8)))) {
291 printf("%c%d", first == 1 ? ' ' : ',', type_index);
292 first = 0;
293 }
294 }
295 } else {
296 int i, nsp, ndp;
297
298 nsp = IP_FW_GETNSRCP_COMPAT(vers1_rule);
299 for (i = 0; i < nsp; i++) {
300 printf("source ports: fw_uar_compat.fw_pts: %04x", vers1_rule->fw_uar_compat.fw_pts[i]);
301 if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_SRNG_COMPAT))
302 printf("-");
303 else if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_SMSK_COMPAT))
304 printf(":");
305 else
306 printf(",");
307 }
308
309 printf("\n");
310
311 ndp = IP_FW_GETNDSTP_COMPAT(vers1_rule);
312 for (i = 0; i < ndp; i++) {
313 printf("source ports: fw_uar_compat.fw_pts: %04x", vers1_rule->fw_uar_compat.fw_pts[nsp+i]);
314 if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_DRNG_COMPAT))
315 printf("-");
316 else if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_DMSK_COMPAT))
317 printf(":");
318 else
319 printf(",");
320 }
321
322 printf("\n");
323 }
324
325 printf("fw_ipflg: %d\n", vers1_rule->fw_ipflg);
326 printf("fw_ipopt: %d\n", vers1_rule->fw_ipopt);
327 printf("fw_ipnopt: %d\n", vers1_rule->fw_ipnopt);
328 printf("fw_tcpopt: %d\n", vers1_rule->fw_tcpopt);
329 printf("fw_tcpnopt: %d\n", vers1_rule->fw_tcpnopt);
330 printf("fw_tcpf: %d\n", vers1_rule->fw_tcpf);
331 printf("fw_tcpnf: %d\n", vers1_rule->fw_tcpnf);
332 printf("timestamp: %ld\n", vers1_rule->timestamp);
333
334 if ((vers1_rule->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
335 printf("fw_in_if: ");
336 inet_ntop(AF_INET, &vers1_rule->fw_in_if.fu_via_ip, ipv4str,
337 sizeof(ipv4str));
338 printf("fu_via_ip: %s\n", ipv4str);
339 printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_in_if.fu_via_if_compat.name);
340 printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_in_if.fu_via_if_compat.unit);
341 } else {
342 if (vers1_rule->fw_flg & IP_FW_F_IIFACE_COMPAT) {
343 printf("fw_in_if: ");
344 printf("fu_via_ip: %s\n",
345 inet_ntop(AF_INET, &vers1_rule->fw_in_if.fu_via_ip, ipv4str,
346 sizeof(ipv4str)));
347 printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_in_if.fu_via_if_compat.name);
348 printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_in_if.fu_via_if_compat.unit);
349 }
350 if (vers1_rule->fw_flg & IP_FW_F_OIFACE_COMPAT) {
351 printf("fw_out_if: ");
352 printf("fu_via_ip: %s\n",
353 inet_ntop(AF_INET, &vers1_rule->fw_out_if.fu_via_ip,
354 ipv4str, sizeof(ipv4str)));
355 printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_out_if.fu_via_if_compat.name);
356 printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_out_if.fu_via_if_compat.unit);
357 }
358 }
359
360 printf("fw_prot: %d\n", vers1_rule->fw_prot);
361 printf("fw_nports: %d\n", vers1_rule->fw_nports);
362 printf("pipe_ptr: %p\n", vers1_rule->pipe_ptr);
363 printf("next_rule_ptr: %p\n", vers1_rule->next_rule_ptr);
364 printf("fw_uid: %d\n", vers1_rule->fw_uid);
365 printf("fw_logamount: %d\n", vers1_rule->fw_logamount);
366 printf("fw_loghighest: %llu\n", vers1_rule->fw_loghighest);
367 }
368
369 static void
370 print_icmptypes(ipfw_insn_u32 *cmd)
371 {
372 int i;
373 char sep= ' ';
374
375 printf(" icmptypes");
376 for (i = 0; i < 32; i++) {
377 if ( (cmd->d[0] & (1 << (i))) == 0)
378 continue;
379 printf("%c%d", sep, i);
380 sep = ',';
381 }
382 }
383
384 /*
385 * print flags set/clear in the two bitmasks passed as parameters.
386 * There is a specialized check for f_tcpflags.
387 */
388 static void
389 print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
390 {
391 char const *comma = "";
392 int i;
393 uint8_t set = cmd->arg1 & 0xff;
394 uint8_t clear = (cmd->arg1 >> 8) & 0xff;
395
396 if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
397 printf(" setup");
398 return;
399 }
400
401 printf(" %s ", name);
402 for (i=0; list[i].x != 0; i++) {
403 if (set & list[i].x) {
404 set &= ~list[i].x;
405 printf("%s%s", comma, list[i].s);
406 comma = ",";
407 }
408 if (clear & list[i].x) {
409 clear &= ~list[i].x;
410 printf("%s!%s", comma, list[i].s);
411 comma = ",";
412 }
413 }
414 }
415
416 static int
417 contigmask(uint8_t *p, int len)
418 {
419 int i, n;
420
421 for (i=0; i<len ; i++)
422 if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
423 break;
424 for (n=i+1; n < len; n++)
425 if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
426 return -1; /* mask not contiguous */
427 return i;
428 }
429
430 /*
431 * Print the ip address contained in a command.
432 */
433 static void
434 print_ip(ipfw_insn_ip *cmd)
435 {
436 int len = F_LEN((ipfw_insn *)cmd);
437 uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
438 char ipv4str[MAX_IPv4_STR_LEN];
439
440 printf("%s ", cmd->o.len & F_NOT ? " not": "");
441
442 if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
443 printf("me");
444 return;
445 }
446
447 /*
448 * len == 2 indicates a single IP, whereas lists of 1 or more
449 * addr/mask pairs have len = (2n+1). We convert len to n so we
450 * use that to count the number of entries.
451 */
452 for (len = len / 2; len > 0; len--, a += 2) {
453 int mb = /* mask length */
454 (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?
455 32 : contigmask((uint8_t *)&(a[1]), 32);
456 if (mb == 0) { /* any */
457 printf("any");
458 } else { /* numeric IP followed by some kind of mask */
459 printf("%s", inet_ntop(AF_INET, &a[0], ipv4str, sizeof(ipv4str)));
460 if (mb < 0)
461 printf(":%s", inet_ntop(AF_INET, &a[1], ipv4str, sizeof(ipv4str)));
462 else if (mb < 32)
463 printf("/%d", mb);
464 }
465 if (len > 1)
466 printf(",");
467 }
468 }
469
470 /*
471 * prints a MAC address/mask pair
472 */
473 static void
474 print_mac(uint8_t *addr, uint8_t *mask)
475 {
476 int l = contigmask(mask, 48);
477
478 if (l == 0)
479 printf(" any");
480 else {
481 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
482 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
483 if (l == -1)
484 printf("&%02x:%02x:%02x:%02x:%02x:%02x",
485 mask[0], mask[1], mask[2],
486 mask[3], mask[4], mask[5]);
487 else if (l < 48)
488 printf("/%d", l);
489 }
490 }
491
492 static void
493 ipfw_print_vers2_struct(struct ip_fw *vers2_rule)
494 {
495 int l;
496 ipfw_insn *cmd;
497 ipfw_insn_log *logptr = NULL;
498 char ipv4str[MAX_IPv4_STR_LEN];
499
500 print_fw_version(vers2_rule->version);
501
502 printf("act_ofs: %d\n", vers2_rule->act_ofs);
503 printf("cmd_len: %d\n", vers2_rule->cmd_len);
504 printf("rulenum: %d\n", vers2_rule->rulenum);
505 printf("set: %d\n", vers2_rule->set);
506 printf("pcnt: %llu\n", vers2_rule->pcnt);
507 printf("bcnt: %llu\n", vers2_rule->bcnt);
508 printf("timestamp: %d\n", vers2_rule->timestamp);
509
510 /*
511 * first print actions
512 */
513 for (l = vers2_rule->cmd_len - vers2_rule->act_ofs, cmd = ACTION_PTR(vers2_rule);
514 l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
515 switch(cmd->opcode) {
516 case O_CHECK_STATE:
517 printf("check-state");
518 break;
519
520 case O_ACCEPT:
521 printf("allow");
522 break;
523
524 case O_COUNT:
525 printf("count");
526 break;
527
528 case O_DENY:
529 printf("deny");
530 break;
531
532 case O_REJECT:
533 if (cmd->arg1 == ICMP_REJECT_RST)
534 printf("reset");
535 else if (cmd->arg1 == ICMP_UNREACH_HOST)
536 printf("reject");
537 else
538 printf("unreach %u", cmd->arg1);
539 break;
540
541 case O_SKIPTO:
542 printf("skipto %u", cmd->arg1);
543 break;
544
545 case O_PIPE:
546 printf("pipe %u", cmd->arg1);
547 break;
548
549 case O_QUEUE:
550 printf("queue %u", cmd->arg1);
551 break;
552
553 case O_DIVERT:
554 printf("divert %u", cmd->arg1);
555 break;
556
557 case O_TEE:
558 printf("tee %u", cmd->arg1);
559 break;
560
561 case O_FORWARD_IP:
562 {
563 ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
564
565 printf("fwd %s",
566 inet_ntop(AF_INET, &s->sa.sin_addr, ipv4str,
567 sizeof(ipv4str)));
568 if (s->sa.sin_port)
569 printf(",%d", s->sa.sin_port);
570 break;
571 }
572
573 case O_LOG: /* O_LOG is printed last */
574 logptr = (ipfw_insn_log *)cmd;
575 break;
576
577 default:
578 printf("** unrecognized action %d len %d",
579 cmd->opcode, cmd->len);
580 }
581 }
582 if (logptr) {
583 if (logptr->max_log > 0)
584 printf(" log logamount %d", logptr->max_log);
585 else
586 printf(" log");
587 }
588
589 /*
590 * then print the body.
591 */
592 for (l = vers2_rule->act_ofs, cmd = vers2_rule->cmd ;
593 l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
594 /* useful alias */
595 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
596
597 switch(cmd->opcode) {
598 case O_PROB:
599 break; /* done already */
600
601 case O_PROBE_STATE:
602 break; /* no need to print anything here */
603
604 case O_MACADDR2:
605 {
606 ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
607
608 if (cmd->len & F_NOT)
609 printf(" not");
610 printf(" MAC");
611 print_mac(m->addr, m->mask);
612 print_mac(m->addr + 6, m->mask + 6);
613 printf("\n");
614 break;
615 }
616 case O_MAC_TYPE:
617 {
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 break;
630 }
631 case O_IP_SRC:
632 case O_IP_SRC_MASK:
633 case O_IP_SRC_ME:
634 print_ip((ipfw_insn_ip *)cmd);
635 break;
636
637 case O_IP_DST:
638 case O_IP_DST_MASK:
639 case O_IP_DST_ME:
640 print_ip((ipfw_insn_ip *)cmd);
641 break;
642
643 case O_IP_DSTPORT:
644 case O_IP_SRCPORT:
645 {
646 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
647 int i;
648
649 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
650 printf("0x%04x", p[0]);
651 if (p[0] != p[1]) {
652 printf("-");
653 printf("0x%04x", p[1]);
654 }
655 printf(",");
656 }
657 break;
658 }
659 case O_PROTO:
660 {
661 printf("O_PROTO");
662
663 if (cmd->len & F_NOT)
664 printf(" not");
665
666 printf(" %u", cmd->arg1);
667
668 break;
669 }
670
671 default: /*options ... */
672 {
673 if (cmd->len & F_NOT && cmd->opcode != O_IN)
674 printf(" not");
675 switch(cmd->opcode) {
676 case O_FRAG:
677 printf("O_FRAG");
678 break;
679
680 case O_IN:
681 printf(cmd->len & F_NOT ? " out" : " O_IN");
682 break;
683
684 case O_LAYER2:
685 printf(" O_LAYER2");
686 break;
687 case O_XMIT:
688 case O_RECV:
689 case O_VIA:
690 {
691 char const *s;
692 ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
693
694 if (cmd->opcode == O_XMIT)
695 s = "O_XMIT";
696 else if (cmd->opcode == O_RECV)
697 s = "O_RECV";
698 else /* if (cmd->opcode == O_VIA) */
699 s = "O_VIA";
700 if (cmdif->name[0] == '\0') {
701 printf(" %s %s", s,
702 inet_ntop(AF_INET, &cmdif->p.ip, ipv4str,
703 sizeof(ipv4str)));
704 }
705 else if (cmdif->p.unit == -1)
706 printf(" %s %s*", s, cmdif->name);
707 else
708 printf(" %s %s%d", s, cmdif->name,
709 cmdif->p.unit);
710 }
711 break;
712
713 case O_IPID:
714 if (F_LEN(cmd) == 1)
715 printf(" ipid %u", cmd->arg1 );
716 else {
717 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
718 int i;
719
720 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
721 printf("0x%04x", p[0]);
722 if (p[0] != p[1]) {
723 printf("-");
724 printf("0x%04x", p[1]);
725 }
726 printf(",");
727 }
728 }
729
730 break;
731
732 case O_IPTTL:
733 if (F_LEN(cmd) == 1)
734 printf(" ipttl %u", cmd->arg1 );
735 else {
736 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
737 int i;
738
739 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
740 printf("0x%04x", p[0]);
741 if (p[0] != p[1]) {
742 printf("-");
743 printf("0x%04x", p[1]);
744 }
745 printf(",");
746 }
747 }
748
749 break;
750
751 case O_IPVER:
752 printf(" ipver %u", cmd->arg1 );
753 break;
754
755 case O_IPPRECEDENCE:
756 printf(" ipprecedence %u", (cmd->arg1) >> 5 );
757 break;
758
759 case O_IPLEN:
760 if (F_LEN(cmd) == 1)
761 printf(" iplen %u", cmd->arg1 );
762 else {
763 uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
764 int i;
765
766 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
767 printf("0x%04x", p[0]);
768 if (p[0] != p[1]) {
769 printf("-");
770 printf("0x%04x", p[1]);
771 }
772 printf(",");
773 }
774 }
775
776 break;
777
778 case O_IPOPT:
779 print_flags("ipoptions", cmd, f_ipopts);
780 break;
781
782 case O_IPTOS:
783 print_flags("iptos", cmd, f_iptos);
784 break;
785
786 case O_ICMPTYPE:
787 print_icmptypes((ipfw_insn_u32 *)cmd);
788 break;
789
790 case O_ESTAB:
791 printf(" established");
792 break;
793
794 case O_TCPFLAGS:
795 print_flags("tcpflags", cmd, f_tcpflags);
796 break;
797
798 case O_TCPOPTS:
799 print_flags("tcpoptions", cmd, f_tcpopts);
800 break;
801
802 case O_TCPWIN:
803 printf(" tcpwin %d", ntohs(cmd->arg1));
804 break;
805
806 case O_TCPACK:
807 printf(" tcpack %u", ntohl(cmd32->d[0]));
808 break;
809
810 case O_TCPSEQ:
811 printf(" tcpseq %u", ntohl(cmd32->d[0]));
812 break;
813
814 case O_UID:
815 printf(" uid %u", cmd32->d[0]);
816 break;
817
818 case O_GID:
819 printf(" gid %u", cmd32->d[0]);
820 break;
821
822 case O_VERREVPATH:
823 printf(" verrevpath");
824 break;
825
826 case O_IPSEC:
827 printf(" ipsec");
828 break;
829
830 case O_NOP:
831 break;
832
833 case O_KEEP_STATE:
834 printf(" keep-state");
835 break;
836
837 case O_LIMIT:
838 {
839 struct _s_x *p = limit_masks;
840 ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
841 uint8_t x = c->limit_mask;
842 char const *comma = " ";
843
844 printf(" limit");
845 for (; p->x != 0 ; p++)
846 if ((x & p->x) == p->x) {
847 x &= ~p->x;
848 printf("%s%s", comma, p->s);
849 comma = ",";
850 }
851 printf(" %d", c->conn_limit);
852
853 break;
854 }
855
856 default:
857 printf(" [opcode %d len %d]",
858 cmd->opcode, cmd->len);
859 } /* switch */
860 } /* default */
861 } /* switch */
862 } /* for */
863 }
864
865 /*
866 * helper function, updates the pointer to cmd with the length
867 * of the current command, and also cleans up the first word of
868 * the new command in case it has been clobbered before.
869 * from ipfw2.c
870 */
871 static ipfw_insn *
872 next_cmd(ipfw_insn *cmd)
873 {
874 cmd += F_LEN(cmd);
875 bzero(cmd, sizeof(*cmd));
876 return cmd;
877 }
878
879 /*
880 * A function to fill simple commands of size 1.
881 * Existing flags are preserved.
882 * from ipfw2.c
883 */
884 static void
885 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, uint16_t arg)
886 {
887 cmd->opcode = opcode;
888 cmd->len = ((cmd->len) & (F_NOT | F_OR)) | 1;
889 cmd->arg1 = arg;
890 }
891
892
893 static u_int32_t
894 fill_compat_tcpflags(u_int32_t flags) {
895 u_int32_t flags_compat = 0;
896
897 if (flags & TH_FIN)
898 flags_compat |= IP_FW_TCPF_FIN_COMPAT;
899 if (flags & TH_SYN)
900 flags_compat |= IP_FW_TCPF_SYN_COMPAT;
901 if (flags & TH_RST)
902 flags_compat |= IP_FW_TCPF_RST_COMPAT;
903 if (flags & TH_PUSH)
904 flags_compat |= IP_FW_TCPF_PSH_COMPAT;
905 if (flags & TH_ACK)
906 flags_compat |= IP_FW_TCPF_ACK_COMPAT;
907 if (flags & TH_URG)
908 flags_compat |= IP_FW_TCPF_URG_COMPAT;
909
910 return flags_compat;
911 }
912
913
914 /* ********************************************
915 * *********** Convert from Latest ************
916 * ********************************************/
917
918 /*
919 * Things we're actively ignoring:
920 * sets, sets of addresses, blocks (NOT, OR)
921 */
922 static void
923 ipfw_map_from_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
924 {
925 int l;
926 ipfw_insn *cmd;
927
928 for (l = curr_rule->act_ofs, cmd = curr_rule->cmd ;
929 l > 0 ;
930 l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
931 /* useful alias */
932 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
933
934 switch (cmd->opcode) {
935 case O_PROTO:
936 /* protocol */
937 compat_rule->fw_prot = cmd->arg1;
938 break;
939
940 case O_IP_SRC_ME:
941 compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
942 if (cmd->len & F_NOT) {
943 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
944 }
945 break;
946
947 case O_IP_SRC_MASK:
948 {
949 /* addr/mask */
950 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
951
952 compat_rule->fw_src = ip->addr;
953 compat_rule->fw_smsk = ip->mask;
954 if (cmd->len & F_NOT) {
955 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
956 }
957 break;
958 }
959
960 case O_IP_SRC:
961 /* one IP */
962 /* source -
963 * for now we only deal with one address
964 * per rule and ignore sets of addresses
965 */
966 compat_rule->fw_src.s_addr = cmd32->d[0];
967 if (cmd->len & F_NOT) {
968 compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
969 }
970 break;
971
972 case O_IP_SRCPORT:
973 {
974 /* source ports */
975 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
976 uint16_t *p = ports->ports;
977 int i, j;
978
979 /* copy list of ports */
980 for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
981 if (p[0] != p[1]) {
982 /* this is a range */
983 compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
984 compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
985 compat_rule->fw_uar_compat.fw_pts[j] = p[1];
986 } else {
987 compat_rule->fw_uar_compat.fw_pts[j] = p[0];
988 }
989 }
990 IP_FW_SETNSRCP_COMPAT(compat_rule, j);
991
992 break;
993 }
994
995 case O_IP_DST_ME:
996 /* destination */
997 compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
998 if (cmd->len & F_NOT) {
999 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1000 }
1001 break;
1002
1003 case O_IP_DST_MASK:
1004 {
1005 /* addr/mask */
1006 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
1007
1008 compat_rule->fw_dst = ip->addr;
1009 compat_rule->fw_dmsk = ip->mask;
1010 if (cmd->len & F_NOT) {
1011 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1012 }
1013 break;
1014 }
1015 case O_IP_DST:
1016 /* one IP */
1017 /* dest -
1018 * for now we only deal with one address
1019 * per rule, and ignore sets of addresses
1020 */
1021 compat_rule->fw_dst.s_addr = cmd32->d[0];
1022 if (cmd->len & F_NOT) {
1023 compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1024 }
1025 break;
1026
1027 case O_IP_DSTPORT:
1028 {
1029 /* dest. ports */
1030 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
1031 uint16_t *p = ports->ports;
1032 int i,
1033 j = IP_FW_GETNSRCP_COMPAT(compat_rule);
1034
1035 /* copy list of ports */
1036 for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
1037 if (p[0] != p[1]) {
1038 /* this is a range */
1039 compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
1040 compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
1041 compat_rule->fw_uar_compat.fw_pts[j] = p[1];
1042 } else {
1043 compat_rule->fw_uar_compat.fw_pts[j] = p[0];
1044 }
1045 }
1046 IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
1047
1048 break;
1049 }
1050
1051 case O_LOG:
1052 {
1053 ipfw_insn_log *c = (ipfw_insn_log *)cmd;
1054
1055 compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
1056 compat_rule->fw_logamount = c->max_log;
1057 break;
1058 }
1059 case O_UID:
1060 compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
1061 compat_rule->fw_uid = cmd32->d[0];
1062 break;
1063
1064 case O_IN:
1065 if (cmd->len & F_NOT) {
1066 compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
1067 } else {
1068 compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
1069 }
1070 break;
1071
1072 case O_KEEP_STATE:
1073 compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
1074 break;
1075
1076 case O_LAYER2:
1077 compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
1078 break;
1079
1080 case O_XMIT:
1081 {
1082 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1083 union ip_fw_if_compat ifu;
1084
1085 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1086 /* any */
1087 compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1088 ifu.fu_via_ip.s_addr = 0;
1089 }
1090 else if (ifcmd->p.ip.s_addr != 0) {
1091 compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1092 ifu.fu_via_ip = ifcmd->p.ip;
1093 } else {
1094 compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
1095 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1096 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1097 }
1098 compat_rule->fw_out_if = ifu;
1099
1100 break;
1101 }
1102
1103 case O_RECV:
1104 {
1105 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1106 union ip_fw_if_compat ifu;
1107
1108 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1109 /* any */
1110 compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1111 ifu.fu_via_ip.s_addr = 0;
1112 }
1113 else if (ifcmd->p.ip.s_addr != 0) {
1114 compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1115 ifu.fu_via_ip = ifcmd->p.ip;
1116 } else {
1117 compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1118 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1119 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1120 }
1121 compat_rule->fw_in_if = ifu;
1122
1123 break;
1124 }
1125
1126 case O_VIA:
1127 {
1128 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1129 union ip_fw_if_compat ifu;
1130
1131 if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1132 /* any */
1133 ifu.fu_via_ip.s_addr = 0;
1134 }
1135 else if (ifcmd->name[0] != '\0') {
1136 compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1137 strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1138 ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1139 } else {
1140 ifu.fu_via_ip = ifcmd->p.ip;
1141 }
1142 compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
1143 compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
1144
1145 break;
1146 }
1147
1148 case O_FRAG:
1149 compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
1150 break;
1151
1152 case O_IPOPT:
1153 /* IP options */
1154 compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
1155 compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
1156 break;
1157
1158 case O_TCPFLAGS:
1159 /* check for "setup" */
1160 if ((cmd->arg1 & 0xff) == TH_SYN &&
1161 ((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
1162 compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
1163 compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
1164 }
1165 else {
1166 compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
1167 compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
1168 }
1169 break;
1170
1171 case O_TCPOPTS:
1172 /* TCP options */
1173 compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
1174 compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
1175 break;
1176
1177 case O_ESTAB:
1178 compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
1179 break;
1180
1181 case O_ICMPTYPE:
1182 {
1183 /* ICMP */
1184 /* XXX: check this */
1185 int i, type;
1186
1187 compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
1188 for (i = 0; i < sizeof(uint32_t) ; i++) {
1189 type = cmd32->d[0] & i;
1190
1191 compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |=
1192 1 << (type % (sizeof(unsigned) * 8));
1193 }
1194 break;
1195 }
1196 default:
1197 break;
1198 } /* switch */
1199 } /* for */
1200 }
1201
1202 static void
1203 ipfw_map_from_actions(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
1204 {
1205 int l;
1206 ipfw_insn *cmd;
1207
1208 for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
1209 l > 0 ;
1210 l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1211 switch (cmd->opcode) {
1212 case O_ACCEPT:
1213 compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
1214 break;
1215 case O_COUNT:
1216 compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
1217 break;
1218 case O_PIPE:
1219 compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
1220 compat_rule->fw_divert_port_compat = cmd->arg1;
1221 break;
1222 case O_QUEUE:
1223 compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
1224 compat_rule->fw_divert_port_compat = cmd->arg1;
1225 break;
1226 case O_SKIPTO:
1227 compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
1228 compat_rule->fw_skipto_rule_compat = cmd->arg1;
1229 break;
1230 case O_DIVERT:
1231 compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
1232 compat_rule->fw_divert_port_compat = cmd->arg1;
1233 break;
1234 case O_TEE:
1235 compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
1236 compat_rule->fw_divert_port_compat = cmd->arg1;
1237 break;
1238 case O_FORWARD_IP:
1239 {
1240 ipfw_insn_sa *p = (ipfw_insn_sa *)cmd;
1241
1242 compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
1243 compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
1244 compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
1245 compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
1246 compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
1247
1248 break;
1249 }
1250 case O_DENY:
1251 compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
1252 break;
1253 case O_REJECT:
1254 compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
1255 compat_rule->fw_reject_code_compat = cmd->arg1;
1256 break;
1257 case O_CHECK_STATE:
1258 compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
1259 break;
1260 default:
1261 break;
1262 }
1263 }
1264 }
1265
1266 static void
1267 ipfw_version_latest_to_one(struct ip_fw *curr_rule, struct ip_fw_compat *rule_vers1)
1268 {
1269 if (!rule_vers1)
1270 return;
1271
1272 bzero(rule_vers1, sizeof(struct ip_fw_compat));
1273
1274 rule_vers1->version = IP_FW_VERSION_1;
1275 rule_vers1->context = curr_rule->context;
1276 rule_vers1->fw_number = curr_rule->rulenum;
1277 rule_vers1->fw_pcnt = curr_rule->pcnt;
1278 rule_vers1->fw_bcnt = curr_rule->bcnt;
1279 rule_vers1->timestamp = curr_rule->timestamp;
1280
1281 /* convert actions */
1282 ipfw_map_from_actions(curr_rule, rule_vers1);
1283
1284 /* convert commands */
1285 ipfw_map_from_cmds(curr_rule, rule_vers1);
1286
1287 #if FW2_DEBUG_VERBOSE
1288 ipfw_print_vers1_struct(rule_vers1);
1289 #endif
1290 }
1291
1292 /* first convert to version one then to version zero */
1293 static void
1294 ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0)
1295 {
1296 struct ip_fw_compat rule_vers1;
1297
1298 ipfw_version_latest_to_one(curr_rule, &rule_vers1);
1299
1300 bzero(rule_vers0, sizeof(struct ip_old_fw));
1301 bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
1302 bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
1303 bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
1304 bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
1305
1306 rule_vers0->fw_pcnt = rule_vers1.fw_pcnt;
1307 rule_vers0->fw_bcnt = rule_vers1.fw_bcnt;
1308 rule_vers0->fw_src = rule_vers1.fw_src;
1309 rule_vers0->fw_dst = rule_vers1.fw_dst;
1310 rule_vers0->fw_smsk = rule_vers1.fw_smsk;
1311 rule_vers0->fw_dmsk = rule_vers1.fw_dmsk;
1312 rule_vers0->fw_number = rule_vers1.fw_number;
1313 rule_vers0->fw_flg = rule_vers1.fw_flg;
1314 rule_vers0->fw_ipopt = rule_vers1.fw_ipopt;
1315 rule_vers0->fw_ipnopt = rule_vers1.fw_ipnopt;
1316 rule_vers0->fw_tcpf = rule_vers1.fw_tcpf;
1317 rule_vers0->fw_tcpnf = rule_vers1.fw_tcpnf;
1318 rule_vers0->timestamp = rule_vers1.timestamp;
1319 rule_vers0->fw_prot = rule_vers1.fw_prot;
1320 rule_vers0->fw_nports = rule_vers1.fw_nports;
1321 rule_vers0->pipe_ptr = rule_vers1.pipe_ptr;
1322 rule_vers0->next_rule_ptr = rule_vers1.next_rule_ptr;
1323
1324 if (rule_vers1.fw_ipflg && IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
1325 }
1326
1327 void
1328 ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version)
1329 {
1330 switch (api_version) {
1331 case IP_FW_VERSION_0:
1332 {
1333 struct ip_old_fw *rule_vers0 = old_rule;
1334
1335 ipfw_version_latest_to_zero(curr_rule, rule_vers0);
1336 break;
1337 }
1338 case IP_FW_VERSION_1:
1339 {
1340 struct ip_fw_compat *rule_vers1 = old_rule;
1341
1342 ipfw_version_latest_to_one(curr_rule, rule_vers1);
1343 break;
1344 }
1345 case IP_FW_CURRENT_API_VERSION:
1346 /* ipfw2 for now, don't need to do anything */
1347 break;
1348
1349 default:
1350 /* unknown version */
1351 break;
1352 }
1353 }
1354
1355
1356 /* ********************************************
1357 * *********** Convert to Latest **************
1358 * ********************************************/
1359
1360 /* from ip_fw.c */
1361 static int
1362 ipfw_check_vers1_struct(struct ip_fw_compat *frwl)
1363 {
1364 /* Check for invalid flag bits */
1365 if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
1366 /*
1367 printf(("%s undefined flag bits set (flags=%x)\n",
1368 err_prefix, frwl->fw_flg));
1369 */
1370 return (EINVAL);
1371 }
1372 if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
1373 /* check-state */
1374 return 0 ;
1375 }
1376 /* Must apply to incoming or outgoing (or both) */
1377 if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
1378 /*
1379 printf(("%s neither in nor out\n", err_prefix));
1380 */
1381 return (EINVAL);
1382 }
1383 /* Empty interface name is no good */
1384 if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
1385 && !*frwl->fw_in_if.fu_via_if_compat.name)
1386 || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
1387 && !*frwl->fw_out_if.fu_via_if_compat.name)) {
1388 /*
1389 printf(("%s empty interface name\n", err_prefix));
1390 */
1391 return (EINVAL);
1392 }
1393 /* Sanity check interface matching */
1394 if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
1395 ; /* allow "via" backwards compatibility */
1396 } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
1397 && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
1398 /*
1399 printf(("%s outgoing interface check on incoming\n",
1400 err_prefix));
1401 */
1402 return (EINVAL);
1403 }
1404 /* Sanity check port ranges */
1405 if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
1406 /*
1407 printf(("%s src range set but n_src_p=%d\n",
1408 err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
1409 */
1410 return (EINVAL);
1411 }
1412 if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
1413 /*
1414 printf(("%s dst range set but n_dst_p=%d\n",
1415 err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
1416 */
1417 return (EINVAL);
1418 }
1419 if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
1420 /*
1421 printf(("%s too many ports (%d+%d)\n",
1422 err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
1423 */
1424 return (EINVAL);
1425 }
1426 /*
1427 * Protocols other than TCP/UDP don't use port range
1428 */
1429 if ((frwl->fw_prot != IPPROTO_TCP) &&
1430 (frwl->fw_prot != IPPROTO_UDP) &&
1431 (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
1432 /*
1433 printf(("%s port(s) specified for non TCP/UDP rule\n",
1434 err_prefix));
1435 */
1436 return (EINVAL);
1437 }
1438
1439 /*
1440 * Rather than modify the entry to make such entries work,
1441 * we reject this rule and require user level utilities
1442 * to enforce whatever policy they deem appropriate.
1443 */
1444 if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
1445 (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
1446 /*
1447 printf(("%s rule never matches\n", err_prefix));
1448 */
1449 return (EINVAL);
1450 }
1451
1452 if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
1453 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1454 if (frwl->fw_nports) {
1455 /*
1456 printf(("%s cannot mix 'frag' and ports\n", err_prefix));
1457 */
1458 return (EINVAL);
1459 }
1460 if (frwl->fw_prot == IPPROTO_TCP &&
1461 frwl->fw_tcpf != frwl->fw_tcpnf) {
1462 /*
1463 printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
1464 */
1465 return (EINVAL);
1466 }
1467 }
1468
1469 /* Check command specific stuff */
1470 switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
1471 {
1472 case IP_FW_F_REJECT_COMPAT:
1473 if (frwl->fw_reject_code_compat >= 0x100
1474 && !(frwl->fw_prot == IPPROTO_TCP
1475 && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
1476 /*
1477 printf(("%s unknown reject code\n", err_prefix));
1478 */
1479 return (EINVAL);
1480 }
1481 break;
1482 case IP_FW_F_DIVERT_COMPAT: /* Diverting to port zero is invalid */
1483 case IP_FW_F_TEE_COMPAT:
1484 case IP_FW_F_PIPE_COMPAT: /* piping through 0 is invalid */
1485 case IP_FW_F_QUEUE_COMPAT: /* piping through 0 is invalid */
1486 if (frwl->fw_divert_port_compat == 0) {
1487 /*
1488 printf(("%s can't divert to port 0\n", err_prefix));
1489 */
1490 return (EINVAL);
1491 }
1492 break;
1493 case IP_FW_F_DENY_COMPAT:
1494 case IP_FW_F_ACCEPT_COMPAT:
1495 case IP_FW_F_COUNT_COMPAT:
1496 case IP_FW_F_SKIPTO_COMPAT:
1497 case IP_FW_F_FWD_COMPAT:
1498 case IP_FW_F_UID_COMPAT:
1499 break;
1500 default:
1501 /*
1502 printf(("%s invalid command\n", err_prefix));
1503 */
1504 return (EINVAL);
1505 }
1506
1507 return 0;
1508 }
1509
1510 static void
1511 ipfw_convert_to_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
1512 {
1513 int k;
1514 uint32_t actbuf[255], cmdbuf[255];
1515 ipfw_insn *action, *cmd, *src, *dst;
1516 ipfw_insn *have_state = NULL; /* track check-state or keep-state */
1517
1518 if (!compat_rule || !curr_rule || !(curr_rule->cmd)) {
1519 return;
1520 }
1521
1522 /* preemptively check the old ip_fw rule to
1523 * make sure it's valid before starting to copy stuff
1524 */
1525 if (ipfw_check_vers1_struct(compat_rule)) {
1526 /* bad rule */
1527 return;
1528 }
1529
1530 bzero(actbuf, sizeof(actbuf)); /* actions go here */
1531 bzero(cmdbuf, sizeof(cmdbuf));
1532
1533 /* fill in action */
1534 action = (ipfw_insn *)actbuf;
1535 {
1536 u_int flag = compat_rule->fw_flg;
1537
1538 action->len = 1; /* default */
1539
1540 if (flag & IP_FW_F_CHECK_S_COMPAT) {
1541 have_state = action;
1542 action->opcode = O_CHECK_STATE;
1543 }
1544 else {
1545 switch (flag & IP_FW_F_COMMAND_COMPAT) {
1546 case IP_FW_F_ACCEPT_COMPAT:
1547 action->opcode = O_ACCEPT;
1548 break;
1549 case IP_FW_F_COUNT_COMPAT:
1550 action->opcode = O_COUNT;
1551 break;
1552 case IP_FW_F_PIPE_COMPAT:
1553 action->opcode = O_PIPE;
1554 action->len = F_INSN_SIZE(ipfw_insn_pipe);
1555 action->arg1 = compat_rule->fw_divert_port_compat;
1556 break;
1557 case IP_FW_F_QUEUE_COMPAT:
1558 action->opcode = O_QUEUE;
1559 action->len = F_INSN_SIZE(ipfw_insn_pipe);
1560 action->arg1 = compat_rule->fw_divert_port_compat;
1561 break;
1562 case IP_FW_F_SKIPTO_COMPAT:
1563 action->opcode = O_SKIPTO;
1564 action->arg1 = compat_rule->fw_skipto_rule_compat;
1565 break;
1566 case IP_FW_F_DIVERT_COMPAT:
1567 action->opcode = O_DIVERT;
1568 action->arg1 = compat_rule->fw_divert_port_compat;
1569 break;
1570 case IP_FW_F_TEE_COMPAT:
1571 action->opcode = O_TEE;
1572 action->arg1 = compat_rule->fw_divert_port_compat;
1573 break;
1574 case IP_FW_F_FWD_COMPAT:
1575 {
1576 ipfw_insn_sa *p = (ipfw_insn_sa *)action;
1577
1578 action->opcode = O_FORWARD_IP;
1579 action->len = F_INSN_SIZE(ipfw_insn_sa);
1580
1581 p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
1582 p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
1583 p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
1584 p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
1585
1586 break;
1587 }
1588 case IP_FW_F_DENY_COMPAT:
1589 action->opcode = O_DENY;
1590 action->arg1 = 0;
1591 break;
1592 case IP_FW_F_REJECT_COMPAT:
1593 action->opcode = O_REJECT;
1594 action->arg1 = compat_rule->fw_reject_code_compat;
1595 break;
1596 default:
1597 action->opcode = O_NOP;
1598 break;
1599 }
1600 }
1601
1602 /* action is mandatory */
1603 if (action->opcode == O_NOP) {
1604 return;
1605 }
1606
1607 action = next_cmd(action);
1608 } /* end actions */
1609
1610 cmd = (ipfw_insn *)cmdbuf;
1611
1612 /* this is O_CHECK_STATE, we're done */
1613 if (have_state) {
1614 goto done;
1615 }
1616
1617 {
1618 ipfw_insn *prev = NULL;
1619 u_int flag = compat_rule->fw_flg;
1620
1621 /* logging */
1622 if (flag & IP_FW_F_PRN_COMPAT) {
1623 ipfw_insn_log *c = (ipfw_insn_log *)cmd;
1624
1625 cmd->opcode = O_LOG;
1626 cmd->len |= F_INSN_SIZE(ipfw_insn_log);
1627 c->max_log = compat_rule->fw_logamount;
1628
1629 prev = cmd;
1630 cmd = next_cmd(cmd);
1631 }
1632
1633 /* protocol */
1634 if (compat_rule->fw_prot != 0) {
1635 fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
1636 prev = cmd;
1637 cmd = next_cmd(cmd);
1638 }
1639
1640 /* source */
1641 if (flag & IP_FW_F_SME_COMPAT) {
1642 cmd->opcode = O_IP_SRC_ME;
1643 cmd->len |= F_INSN_SIZE(ipfw_insn);
1644 if (flag & IP_FW_F_INVSRC_COMPAT) {
1645 cmd->len ^= F_NOT; /* toggle F_NOT */
1646 }
1647
1648 prev = cmd;
1649 cmd = next_cmd(cmd);
1650 } else {
1651 if (compat_rule->fw_smsk.s_addr != 0) {
1652 /* addr/mask */
1653 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
1654
1655 ip->addr = compat_rule->fw_src;
1656 ip->mask = compat_rule->fw_smsk;
1657 cmd->opcode = O_IP_SRC_MASK;
1658 cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
1659 } else {
1660 /* one IP */
1661 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
1662
1663 if (compat_rule->fw_src.s_addr == 0) {
1664 /* any */
1665 cmd32->o.len &= ~F_LEN_MASK; /* zero len */
1666 } else {
1667 cmd32->d[0] = compat_rule->fw_src.s_addr;
1668 cmd32->o.opcode = O_IP_SRC;
1669 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
1670 }
1671 }
1672
1673 if (flag & IP_FW_F_INVSRC_COMPAT) {
1674 cmd->len ^= F_NOT; /* toggle F_NOT */
1675 }
1676
1677 if (F_LEN(cmd) != 0) { /* !any */
1678 prev = cmd;
1679 cmd = next_cmd(cmd);
1680 }
1681 }
1682
1683 /* source ports */
1684 {
1685 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
1686 uint16_t *p = ports->ports;
1687 int i, j = 0,
1688 nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
1689 have_range = 0;
1690
1691 cmd->opcode = O_IP_SRCPORT;
1692 for (i = 0; i < nports; i++) {
1693 if (((flag & IP_FW_F_SRNG_COMPAT) ||
1694 (flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
1695 p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
1696 p[1] = compat_rule->fw_uar_compat.fw_pts[i];
1697 have_range = 1;
1698 } else {
1699 p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
1700 }
1701 p += 2;
1702 j++;
1703 }
1704
1705 if (j > 0) {
1706 ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
1707 }
1708
1709 prev = cmd;
1710 cmd = next_cmd(cmd);
1711 }
1712
1713 /* destination */
1714 if (flag & IP_FW_F_DME_COMPAT) {
1715 cmd->opcode = O_IP_DST_ME;
1716 cmd->len |= F_INSN_SIZE(ipfw_insn);
1717 if (flag & IP_FW_F_INVDST_COMPAT) {
1718 cmd->len ^= F_NOT; /* toggle F_NOT */
1719 }
1720
1721 prev = cmd;
1722 cmd = next_cmd(cmd);
1723 } else {
1724 if (compat_rule->fw_dmsk.s_addr != 0) {
1725 /* addr/mask */
1726 ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
1727
1728 ip->addr = compat_rule->fw_dst;
1729 ip->mask = compat_rule->fw_dmsk;
1730 cmd->opcode = O_IP_DST_MASK;
1731 cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
1732 } else {
1733 /* one IP */
1734 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
1735
1736 if (compat_rule->fw_dst.s_addr == 0) {
1737 /* any */
1738 cmd32->o.len &= ~F_LEN_MASK; /* zero len */
1739 } else {
1740 cmd32->d[0] = compat_rule->fw_dst.s_addr;
1741 cmd32->o.opcode = O_IP_DST;
1742 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
1743 }
1744 }
1745
1746 if (flag & IP_FW_F_INVDST_COMPAT) {
1747 cmd->len ^= F_NOT; /* toggle F_NOT */
1748 }
1749
1750 if (F_LEN(cmd) != 0) { /* !any */
1751 prev = cmd;
1752 cmd = next_cmd(cmd);
1753 }
1754 }
1755
1756 /* dest. ports */
1757 {
1758 ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
1759 uint16_t *p = ports->ports;
1760 int i = IP_FW_GETNSRCP_COMPAT(compat_rule),
1761 j = 0,
1762 nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
1763 have_range = 0;
1764
1765 cmd->opcode = O_IP_DSTPORT;
1766 for (; i < nports; i++, p += 2) {
1767 if (((flag & IP_FW_F_DRNG_COMPAT) ||
1768 (flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
1769 /* range */
1770 p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
1771 p[1] = compat_rule->fw_uar_compat.fw_pts[i];
1772 have_range = 1;
1773 } else {
1774 p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
1775 }
1776 j++;
1777 }
1778
1779 if (j > 0) {
1780 ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
1781 }
1782
1783 prev = cmd;
1784 cmd = next_cmd(cmd);
1785 }
1786
1787 if (flag & IP_FW_F_UID_COMPAT) {
1788 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
1789
1790 cmd32->o.opcode = O_UID;
1791 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
1792 cmd32->d[0] = compat_rule->fw_uid;
1793
1794 prev = cmd;
1795 cmd = next_cmd(cmd);
1796 }
1797
1798 if (flag & IP_FW_F_KEEP_S_COMPAT) {
1799 have_state = cmd;
1800 fill_cmd(cmd, O_KEEP_STATE, 0);
1801
1802 prev = cmd;
1803 cmd = next_cmd(cmd);
1804 }
1805 if (flag & IP_FW_BRIDGED_COMPAT) {
1806 fill_cmd(cmd, O_LAYER2, 0);
1807
1808 prev = cmd;
1809 cmd = next_cmd(cmd);
1810 }
1811
1812 if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
1813 /* via */
1814 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1815 union ip_fw_if_compat ifu = compat_rule->fw_in_if;
1816
1817 cmd->opcode = O_VIA;
1818 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
1819
1820 if (ifu.fu_via_ip.s_addr == 0) {
1821 /* "any" */
1822 ifcmd->name[0] = '\0';
1823 ifcmd->o.len = 0;
1824 }
1825 else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
1826 /* by name */
1827 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
1828 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
1829 } else {
1830 /* by addr */
1831 ifcmd->p.ip = ifu.fu_via_ip;
1832 }
1833
1834 prev = cmd;
1835 cmd = next_cmd(cmd);
1836 } else {
1837 if (flag & IP_FW_F_IN_COMPAT) {
1838 fill_cmd(cmd, O_IN, 0);
1839
1840 prev = cmd;
1841 cmd = next_cmd(cmd);
1842 }
1843 if (flag & IP_FW_F_OUT_COMPAT) {
1844 /* if the previous command was O_IN, and this
1845 * is being set as well, it's equivalent to not
1846 * having either command, so let's back up prev
1847 * to the cmd before it and move cmd to prev.
1848 */
1849 if (prev->opcode == O_IN) {
1850 cmd = prev;
1851 bzero(cmd, sizeof(*cmd));
1852 } else {
1853 cmd->len ^= F_NOT; /* toggle F_NOT */
1854 fill_cmd(cmd, O_IN, 0);
1855
1856 prev = cmd;
1857 cmd = next_cmd(cmd);
1858 }
1859 }
1860 if (flag & IP_FW_F_OIFACE_COMPAT) {
1861 /* xmit */
1862 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1863 union ip_fw_if_compat ifu = compat_rule->fw_out_if;
1864
1865 cmd->opcode = O_XMIT;
1866 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
1867
1868 if (ifu.fu_via_ip.s_addr == 0) {
1869 /* "any" */
1870 ifcmd->name[0] = '\0';
1871 ifcmd->o.len = 0;
1872 }
1873 else if (flag & IP_FW_F_OIFNAME_COMPAT) {
1874 /* by name */
1875 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
1876 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
1877 } else {
1878 /* by addr */
1879 ifcmd->p.ip = ifu.fu_via_ip;
1880 }
1881
1882 prev = cmd;
1883 cmd = next_cmd(cmd);
1884 }
1885 else if (flag & IP_FW_F_IIFACE_COMPAT) {
1886 /* recv */
1887 ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
1888 union ip_fw_if_compat ifu = compat_rule->fw_in_if;
1889
1890 cmd->opcode = O_RECV;
1891 ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
1892
1893 if (ifu.fu_via_ip.s_addr == 0) {
1894 /* "any" */
1895 ifcmd->name[0] = '\0';
1896 ifcmd->o.len = 0;
1897 }
1898 else if (flag & IP_FW_F_IIFNAME_COMPAT) {
1899 /* by name */
1900 strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
1901 ifcmd->p.unit = ifu.fu_via_if_compat.unit;
1902 } else {
1903 /* by addr */
1904 ifcmd->p.ip = ifu.fu_via_ip;
1905 }
1906
1907 prev = cmd;
1908 cmd = next_cmd(cmd);
1909 }
1910 }
1911
1912 if (flag & IP_FW_F_FRAG_COMPAT) {
1913 fill_cmd(cmd, O_FRAG, 0);
1914
1915 prev = cmd;
1916 cmd = next_cmd(cmd);
1917 }
1918
1919 /* IP options */
1920 if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
1921 fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
1922 (compat_rule->fw_ipnopt & 0xff) << 8);
1923
1924 prev = cmd;
1925 cmd = next_cmd(cmd);
1926 }
1927
1928 if (compat_rule->fw_prot == IPPROTO_TCP) {
1929 if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
1930 fill_cmd(cmd, O_ESTAB, 0);
1931
1932 prev = cmd;
1933 cmd = next_cmd(cmd);
1934 }
1935
1936 /* TCP options and flags */
1937 if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
1938 if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
1939 compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
1940 fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ( (TH_ACK) & 0xff) <<8);
1941
1942 prev = cmd;
1943 cmd = next_cmd(cmd);
1944 }
1945 else {
1946 fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
1947 (compat_rule->fw_tcpnf & 0xff) << 8);
1948
1949 prev = cmd;
1950 cmd = next_cmd(cmd);
1951 }
1952 }
1953 if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
1954 fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
1955 (compat_rule->fw_tcpnopt & 0xff) << 8);
1956
1957 prev = cmd;
1958 cmd = next_cmd(cmd);
1959 }
1960 }
1961
1962 /* ICMP */
1963 /* XXX: check this */
1964 if (flag & IP_FW_F_ICMPBIT_COMPAT) {
1965 int i;
1966 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
1967
1968 cmd32->o.opcode = O_ICMPTYPE;
1969 cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
1970
1971 for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
1972 cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
1973 }
1974
1975 prev = cmd;
1976 cmd = next_cmd(cmd);
1977 }
1978 } /* end commands */
1979
1980 done:
1981 /* finally, copy everything into the current
1982 * rule buffer in the right order.
1983 */
1984 dst = curr_rule->cmd;
1985
1986 /* first, do match probability */
1987 if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
1988 dst->opcode = O_PROB;
1989 dst->len = 2;
1990 *((int32_t *)(dst+1)) = compat_rule->pipe_ptr;
1991 dst += dst->len;
1992 }
1993
1994 /* generate O_PROBE_STATE if necessary */
1995 if (have_state && have_state->opcode != O_CHECK_STATE) {
1996 fill_cmd(dst, O_PROBE_STATE, 0);
1997 dst = next_cmd(dst);
1998 }
1999
2000 /*
2001 * copy all commands but O_LOG, O_KEEP_STATE
2002 */
2003 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
2004 k = F_LEN(src);
2005
2006 switch (src->opcode) {
2007 case O_LOG:
2008 case O_KEEP_STATE:
2009 break;
2010 default:
2011 bcopy(src, dst, k * sizeof(uint32_t));
2012 dst += k;
2013 }
2014 }
2015
2016 /*
2017 * put back the have_state command as last opcode
2018 */
2019 if (have_state && have_state->opcode != O_CHECK_STATE) {
2020 k = F_LEN(have_state);
2021 bcopy(have_state, dst, k * sizeof(uint32_t));
2022 dst += k;
2023 }
2024
2025 /*
2026 * start action section
2027 */
2028 curr_rule->act_ofs = dst - curr_rule->cmd;
2029
2030 /*
2031 * put back O_LOG if necessary
2032 */
2033 src = (ipfw_insn *)cmdbuf;
2034 if (src->opcode == O_LOG) {
2035 k = F_LEN(src);
2036 bcopy(src, dst, k * sizeof(uint32_t));
2037 dst += k;
2038 }
2039
2040 /*
2041 * copy all other actions
2042 */
2043 for (src = (ipfw_insn *)actbuf; src != action; src += k) {
2044 k = F_LEN(src);
2045 bcopy(src, dst, k * sizeof(uint32_t));
2046 dst += k;
2047 }
2048
2049 curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
2050
2051 return;
2052 }
2053
2054 static int
2055 ipfw_version_one_to_version_two(struct sockopt *sopt, struct ip_fw *curr_rule,
2056 struct ip_fw_compat *rule_vers1)
2057 {
2058 int err = EINVAL;
2059 struct ip_fw_compat *rule_ptr;
2060 struct ip_fw_compat rule;
2061
2062 if (rule_vers1) {
2063 rule_ptr = rule_vers1;
2064 err = 0;
2065 } else {
2066 /* do some basic size checking here, more extensive checking later */
2067 if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat))
2068 return err;
2069
2070 if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat),
2071 sizeof(struct ip_fw_compat)))) {
2072 return err;
2073 }
2074
2075 rule_ptr = &rule;
2076 }
2077
2078 /* deal with commands */
2079 ipfw_convert_to_cmds(curr_rule, rule_ptr);
2080
2081 curr_rule->version = IP_FW_CURRENT_API_VERSION;
2082 curr_rule->context = rule_ptr->context;
2083 curr_rule->rulenum = rule_ptr->fw_number;
2084 curr_rule->pcnt = rule_ptr->fw_pcnt;
2085 curr_rule->bcnt = rule_ptr->fw_bcnt;
2086 curr_rule->timestamp = rule_ptr->timestamp;
2087
2088
2089 #if FW2_DEBUG_VERBOSE
2090 ipfw_print_vers2_struct(curr_rule);
2091 #endif /* FW2_DEBUG_VERBOSE */
2092
2093 return err;
2094 }
2095
2096 /* This converts to whatever the latest version is. Currently the
2097 * latest version of the firewall is ipfw2.
2098 */
2099 static int
2100 ipfw_version_one_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat *rule_vers1)
2101 {
2102 int err;
2103
2104 /* if rule_vers1 is not null then this is coming from
2105 * ipfw_version_zero_to_latest(), so pass that along;
2106 * otherwise let ipfw_version_one_to_version_two()
2107 * get the rule from sopt.
2108 */
2109 err = ipfw_version_one_to_version_two(sopt, curr_rule, rule_vers1);
2110
2111 return err;
2112 }
2113
2114 static void
2115 ipfw_version_zero_to_one(struct ip_old_fw *rule_vers0, struct ip_fw_compat *rule_vers1)
2116 {
2117 bzero(rule_vers1, sizeof(struct ip_fw_compat));
2118 bcopy(&rule_vers0->fw_uar, &rule_vers1->fw_uar_compat, sizeof(rule_vers0->fw_uar));
2119 bcopy(&rule_vers0->fw_in_if, &rule_vers1->fw_in_if, sizeof(rule_vers0->fw_in_if));
2120 bcopy(&rule_vers0->fw_out_if, &rule_vers1->fw_out_if, sizeof(rule_vers0->fw_out_if));
2121 bcopy(&rule_vers0->fw_un, &rule_vers1->fw_un_compat, sizeof(rule_vers0->fw_un));
2122
2123 rule_vers1->version = 10;
2124 rule_vers1->fw_pcnt = rule_vers0->fw_pcnt;
2125 rule_vers1->fw_bcnt = rule_vers0->fw_bcnt;
2126 rule_vers1->fw_src = rule_vers0->fw_src;
2127 rule_vers1->fw_dst = rule_vers0->fw_dst;
2128 rule_vers1->fw_smsk = rule_vers0->fw_smsk;
2129 rule_vers1->fw_dmsk = rule_vers0->fw_dmsk;
2130 rule_vers1->fw_number = rule_vers0->fw_number;
2131 rule_vers1->fw_flg = rule_vers0->fw_flg;
2132 rule_vers1->fw_ipopt = rule_vers0->fw_ipopt;
2133 rule_vers1->fw_ipnopt = rule_vers0->fw_ipnopt;
2134 rule_vers1->fw_tcpf = rule_vers0->fw_tcpf & ~IP_OLD_FW_TCPF_ESTAB;
2135 rule_vers1->fw_tcpnf = rule_vers0->fw_tcpnf;
2136 rule_vers1->timestamp = rule_vers0->timestamp;
2137 rule_vers1->fw_prot = rule_vers0->fw_prot;
2138 rule_vers1->fw_nports = rule_vers0->fw_nports;
2139 rule_vers1->pipe_ptr = rule_vers0->pipe_ptr;
2140 rule_vers1->next_rule_ptr = rule_vers0->next_rule_ptr;
2141 rule_vers1->fw_ipflg = (rule_vers0->fw_tcpf & IP_OLD_FW_TCPF_ESTAB) ? IP_FW_IF_TCPEST_COMPAT : 0;
2142 }
2143
2144 /* first convert to version one, then to version two */
2145 static int
2146 ipfw_version_zero_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule)
2147 {
2148 int err;
2149 struct ip_old_fw rule_vers0;
2150 struct ip_fw_compat rule_vers1;
2151
2152 if (sopt->sopt_name == IP_OLD_FW_GET ||
2153 sopt->sopt_name == IP_OLD_FW_FLUSH ||
2154 sopt->sopt_val == USER_ADDR_NULL) {
2155 /* In the old-style API, it was legal to not pass in a rule
2156 * structure for certain firewall operations (e.g. flush,
2157 * reset log). If that's the situation, we pretend we received
2158 * a blank structure. */
2159 bzero(curr_rule, sizeof(struct ip_fw));
2160 curr_rule->version = 10;
2161 }
2162 else {
2163 if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_old_fw)) {
2164 return EINVAL;
2165 }
2166
2167 err = sooptcopyin(sopt, &rule_vers0, sizeof(struct ip_old_fw),
2168 sizeof(struct ip_old_fw));
2169 if (err) {
2170 return err;
2171 }
2172
2173 ipfw_version_zero_to_one(&rule_vers0, &rule_vers1);
2174 }
2175
2176 return (ipfw_version_one_to_latest(sopt, curr_rule, &rule_vers1));
2177 }
2178
2179 /* rule is a u_int32_t buffer[255] into which the converted
2180 * (if necessary) rules go.
2181 */
2182 int
2183 ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version)
2184 {
2185 int err = 0;
2186
2187 /* the following functions copy the rules passed in and
2188 * convert to latest structures based on version
2189 */
2190 switch (api_version) {
2191 case IP_FW_VERSION_0:
2192 /* this is the oldest version we support */
2193 err = ipfw_version_zero_to_latest(sopt, curr_rule);
2194 break;
2195
2196 case IP_FW_VERSION_1:
2197 /* this is the version supported in Panther */
2198 err = ipfw_version_one_to_latest(sopt, curr_rule, NULL);
2199 break;
2200
2201 case IP_FW_CURRENT_API_VERSION:
2202 /* IPFW2 for now */
2203 /* do nothing here... */
2204 break;
2205
2206 default:
2207 /* unrecognized/unsupported version */
2208 err = EINVAL;
2209 break;
2210 }
2211
2212 return err;
2213 }
2214
2215 int
2216 ipfw_get_command_and_version(struct sockopt *sopt, int *command, u_int32_t *api_version)
2217 {
2218 int cmd;
2219 int err = 0;
2220 u_int32_t vers = IP_FW_VERSION_NONE;
2221
2222 /* first deal with the oldest version */
2223 if (sopt->sopt_name == IP_OLD_FW_GET) {
2224 vers = IP_FW_VERSION_0;
2225 cmd = IP_FW_GET;
2226 }
2227 else if (sopt->sopt_name == IP_OLD_FW_FLUSH) {
2228 vers = IP_FW_VERSION_0;
2229 cmd = IP_FW_FLUSH;
2230 }
2231 else if (sopt->sopt_name == IP_OLD_FW_ZERO) {
2232 vers = IP_FW_VERSION_0;
2233 cmd = IP_FW_ZERO;
2234 }
2235 else if (sopt->sopt_name == IP_OLD_FW_ADD) {
2236 vers = IP_FW_VERSION_0;
2237 cmd = IP_FW_ADD;
2238 }
2239 else if (sopt->sopt_name == IP_OLD_FW_DEL) {
2240 vers = IP_FW_VERSION_0;
2241 cmd = IP_FW_DEL;
2242 }
2243 else if (sopt->sopt_name == IP_OLD_FW_RESETLOG) {
2244 vers = IP_FW_VERSION_0;
2245 cmd = IP_FW_RESETLOG;
2246 }
2247 else {
2248 cmd = sopt->sopt_name;
2249 }
2250
2251 if (vers == IP_FW_VERSION_NONE) {
2252 /* working off the fact that the offset
2253 * is the same in both structs.
2254 */
2255 struct ip_fw rule;
2256
2257 if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw))
2258 return EINVAL;
2259
2260 if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw),
2261 sizeof(struct ip_fw)))) {
2262 return err;
2263 }
2264
2265 vers = rule.version;
2266 }
2267
2268 if (command) {
2269 *command = cmd;
2270 }
2271
2272 if (api_version) {
2273 *api_version = vers;
2274 }
2275
2276 return err;
2277 }
2278