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