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