/*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#define VERSION_ONE_STR "IP_FW_VERSION_1"
#define CURRENT_API_VERSION_STR "IP_FW_CURRENT_API_VERSION"
+#if FW2_DEBUG_VERBOSE
+
static struct _s_x f_tcpflags[] = {
{ "syn", TH_SYN },
{ "fin", TH_FIN },
{ NULL, 0 }
};
+
/*
* IP options span the range 0 to 255 so we need to remap them
* (though in fact only the low 5 bits are significant).
{NULL, 0}
};
+#endif /* !FW2_DEBUG_VERBOSE */
+
+#if 0 /* version #1 */
+
static void
ipfw_print_fw_flags(u_int flags)
{
}
}
-static void
-ipfw_print_vers1_struct(struct ip_fw_compat *vers1_rule)
-{
- char ipv4str[MAX_IPv4_STR_LEN];
- print_fw_version(vers1_rule->version);
- printf("Rule #%d\n", vers1_rule->fw_number);
-
- ipfw_print_fw_flags(vers1_rule->fw_flg);
-
- printf("fw_pcnt: %llu\n", vers1_rule->fw_pcnt);
- printf("fw_bcnt: %llu\n", vers1_rule->fw_bcnt);
- printf("fw_src: %s\n",
- inet_ntop(AF_INET, &vers1_rule->fw_src, ipv4str, sizeof(ipv4str)));
- printf("fw_dst: %s\n",
- inet_ntop(AF_INET, &vers1_rule->fw_dst, ipv4str, sizeof(ipv4str)));
- printf("fw_smsk: %s\n",
- inet_ntop(AF_INET, &vers1_rule->fw_smsk, ipv4str, sizeof(ipv4str)));
- printf("fw_dmsk: %s\n",
- inet_ntop(AF_INET, &vers1_rule->fw_dmsk, ipv4str, sizeof(ipv4str)));
-
- if (vers1_rule->fw_flg & IP_FW_F_ICMPBIT_COMPAT) {
- int type_index;
- int first = 1;
-
- printf(" icmptype");
-
- for (type_index = 0;
- type_index < (IP_FW_ICMPTYPES_DIM_COMPAT * sizeof(unsigned) * 8);
- ++type_index) {
- if (vers1_rule->fw_uar_compat.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
- (1U << (type_index % (sizeof(unsigned) * 8)))) {
- printf("%c%d", first == 1 ? ' ' : ',', type_index);
- first = 0;
- }
- }
- } else {
- int i, nsp, ndp;
-
- nsp = IP_FW_GETNSRCP_COMPAT(vers1_rule);
- for (i = 0; i < nsp; i++) {
- printf("source ports: fw_uar_compat.fw_pts: %04x", vers1_rule->fw_uar_compat.fw_pts[i]);
- if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_SRNG_COMPAT))
- printf("-");
- else if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_SMSK_COMPAT))
- printf(":");
- else
- printf(",");
- }
-
- printf("\n");
-
- ndp = IP_FW_GETNDSTP_COMPAT(vers1_rule);
- for (i = 0; i < ndp; i++) {
- printf("source ports: fw_uar_compat.fw_pts: %04x", vers1_rule->fw_uar_compat.fw_pts[nsp+i]);
- if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_DRNG_COMPAT))
- printf("-");
- else if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_DMSK_COMPAT))
- printf(":");
- else
- printf(",");
- }
-
- printf("\n");
- }
-
- printf("fw_ipflg: %d\n", vers1_rule->fw_ipflg);
- printf("fw_ipopt: %d\n", vers1_rule->fw_ipopt);
- printf("fw_ipnopt: %d\n", vers1_rule->fw_ipnopt);
- printf("fw_tcpopt: %d\n", vers1_rule->fw_tcpopt);
- printf("fw_tcpnopt: %d\n", vers1_rule->fw_tcpnopt);
- printf("fw_tcpf: %d\n", vers1_rule->fw_tcpf);
- printf("fw_tcpnf: %d\n", vers1_rule->fw_tcpnf);
- printf("timestamp: %ld\n", vers1_rule->timestamp);
-
- if ((vers1_rule->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
- printf("fw_in_if: ");
- inet_ntop(AF_INET, &vers1_rule->fw_in_if.fu_via_ip, ipv4str,
- sizeof(ipv4str));
- printf("fu_via_ip: %s\n", ipv4str);
- printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_in_if.fu_via_if_compat.name);
- printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_in_if.fu_via_if_compat.unit);
- } else {
- if (vers1_rule->fw_flg & IP_FW_F_IIFACE_COMPAT) {
- printf("fw_in_if: ");
- printf("fu_via_ip: %s\n",
- inet_ntop(AF_INET, &vers1_rule->fw_in_if.fu_via_ip, ipv4str,
- sizeof(ipv4str)));
- printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_in_if.fu_via_if_compat.name);
- printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_in_if.fu_via_if_compat.unit);
- }
- if (vers1_rule->fw_flg & IP_FW_F_OIFACE_COMPAT) {
- printf("fw_out_if: ");
- printf("fu_via_ip: %s\n",
- inet_ntop(AF_INET, &vers1_rule->fw_out_if.fu_via_ip,
- ipv4str, sizeof(ipv4str)));
- printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_out_if.fu_via_if_compat.name);
- printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_out_if.fu_via_if_compat.unit);
- }
- }
-
- printf("fw_prot: %d\n", vers1_rule->fw_prot);
- printf("fw_nports: %d\n", vers1_rule->fw_nports);
- printf("pipe_ptr: %p\n", vers1_rule->pipe_ptr);
- printf("next_rule_ptr: %p\n", vers1_rule->next_rule_ptr);
- printf("fw_uid: %d\n", vers1_rule->fw_uid);
- printf("fw_logamount: %d\n", vers1_rule->fw_logamount);
- printf("fw_loghighest: %llu\n", vers1_rule->fw_loghighest);
-}
-
static void
print_icmptypes(ipfw_insn_u32 *cmd)
{
}
}
+#endif /* !version #1 */
+
+#if FW2_DEBUG_VERBOSE
static void
ipfw_print_vers2_struct(struct ip_fw *vers2_rule)
{
} /* for */
}
+#endif /* !FW2_DEBUG_VERBOSE */
+
+
/*
* helper function, updates the pointer to cmd with the length
* of the current command, and also cleans up the first word of
* sets, sets of addresses, blocks (NOT, OR)
*/
static void
-ipfw_map_from_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
+ipfw_map_from_cmds_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
{
int l;
ipfw_insn *cmd;
}
static void
-ipfw_map_from_actions(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
+ipfw_map_from_cmds_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
{
- int l;
+ int l;
ipfw_insn *cmd;
-
- for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
- l > 0 ;
- l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+ for (l = curr_rule->act_ofs, cmd = curr_rule->cmd ;
+ l > 0 ;
+ l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
+ /* useful alias */
+ ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
+
switch (cmd->opcode) {
- case O_ACCEPT:
- compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
- break;
- case O_COUNT:
- compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
+ case O_PROTO:
+ /* protocol */
+ compat_rule->fw_prot = cmd->arg1;
break;
- case O_PIPE:
- compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
- compat_rule->fw_divert_port_compat = cmd->arg1;
+
+ case O_IP_SRC_ME:
+ compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
+ }
break;
- case O_QUEUE:
- compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
- compat_rule->fw_divert_port_compat = cmd->arg1;
+
+ case O_IP_SRC_MASK:
+ {
+ /* addr/mask */
+ ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
+
+ compat_rule->fw_src = ip->addr;
+ compat_rule->fw_smsk = ip->mask;
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
+ }
break;
- case O_SKIPTO:
- compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
- compat_rule->fw_skipto_rule_compat = cmd->arg1;
+ }
+
+ case O_IP_SRC:
+ /* one IP */
+ /* source -
+ * for now we only deal with one address
+ * per rule and ignore sets of addresses
+ */
+ compat_rule->fw_src.s_addr = cmd32->d[0];
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
+ }
break;
- case O_DIVERT:
- compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
- compat_rule->fw_divert_port_compat = cmd->arg1;
+
+ case O_IP_SRCPORT:
+ {
+ /* source ports */
+ ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
+ uint16_t *p = ports->ports;
+ int i, j;
+
+ /* copy list of ports */
+ for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
+ if (p[0] != p[1]) {
+ /* this is a range */
+ compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
+ compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
+ compat_rule->fw_uar_compat.fw_pts[j] = p[1];
+ } else {
+ compat_rule->fw_uar_compat.fw_pts[j] = p[0];
+ }
+ }
+ IP_FW_SETNSRCP_COMPAT(compat_rule, j);
+
break;
- case O_TEE:
- compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
- compat_rule->fw_divert_port_compat = cmd->arg1;
+ }
+
+ case O_IP_DST_ME:
+ /* destination */
+ compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
+ }
break;
- case O_FORWARD_IP:
+
+ case O_IP_DST_MASK:
{
- ipfw_insn_sa *p = (ipfw_insn_sa *)cmd;
+ /* addr/mask */
+ ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
- compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
- compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
- compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
- compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
- compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
-
+ compat_rule->fw_dst = ip->addr;
+ compat_rule->fw_dmsk = ip->mask;
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
+ }
break;
}
- case O_DENY:
- compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
+ case O_IP_DST:
+ /* one IP */
+ /* dest -
+ * for now we only deal with one address
+ * per rule, and ignore sets of addresses
+ */
+ compat_rule->fw_dst.s_addr = cmd32->d[0];
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
+ }
break;
- case O_REJECT:
- compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
- compat_rule->fw_reject_code_compat = cmd->arg1;
+
+ case O_IP_DSTPORT:
+ {
+ /* dest. ports */
+ ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
+ uint16_t *p = ports->ports;
+ int i,
+ j = IP_FW_GETNSRCP_COMPAT(compat_rule);
+
+ /* copy list of ports */
+ for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
+ if (p[0] != p[1]) {
+ /* this is a range */
+ compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
+ compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
+ compat_rule->fw_uar_compat.fw_pts[j] = p[1];
+ } else {
+ compat_rule->fw_uar_compat.fw_pts[j] = p[0];
+ }
+ }
+ IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
+
break;
- case O_CHECK_STATE:
- compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
+ }
+
+ case O_LOG:
+ {
+ ipfw_insn_log *c = (ipfw_insn_log *)cmd;
+
+ compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
+ compat_rule->fw_logamount = c->max_log;
break;
- default:
+ }
+ case O_UID:
+ compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
+ compat_rule->fw_uid = cmd32->d[0];
break;
- }
- }
-}
-
-static void
-ipfw_version_latest_to_one(struct ip_fw *curr_rule, struct ip_fw_compat *rule_vers1)
-{
- if (!rule_vers1)
- return;
-
- bzero(rule_vers1, sizeof(struct ip_fw_compat));
-
- rule_vers1->version = IP_FW_VERSION_1;
- rule_vers1->context = curr_rule->context;
- rule_vers1->fw_number = curr_rule->rulenum;
- rule_vers1->fw_pcnt = curr_rule->pcnt;
- rule_vers1->fw_bcnt = curr_rule->bcnt;
- rule_vers1->timestamp = curr_rule->timestamp;
-
- /* convert actions */
- ipfw_map_from_actions(curr_rule, rule_vers1);
-
- /* convert commands */
- ipfw_map_from_cmds(curr_rule, rule_vers1);
-
-#if FW2_DEBUG_VERBOSE
- ipfw_print_vers1_struct(rule_vers1);
-#endif
-}
-
-/* first convert to version one then to version zero */
-static void
-ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0)
-{
- struct ip_fw_compat rule_vers1;
-
- ipfw_version_latest_to_one(curr_rule, &rule_vers1);
-
- bzero(rule_vers0, sizeof(struct ip_old_fw));
- bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
- bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
- bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
- bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
-
- rule_vers0->fw_pcnt = rule_vers1.fw_pcnt;
- rule_vers0->fw_bcnt = rule_vers1.fw_bcnt;
- rule_vers0->fw_src = rule_vers1.fw_src;
- rule_vers0->fw_dst = rule_vers1.fw_dst;
- rule_vers0->fw_smsk = rule_vers1.fw_smsk;
- rule_vers0->fw_dmsk = rule_vers1.fw_dmsk;
- rule_vers0->fw_number = rule_vers1.fw_number;
- rule_vers0->fw_flg = rule_vers1.fw_flg;
- rule_vers0->fw_ipopt = rule_vers1.fw_ipopt;
- rule_vers0->fw_ipnopt = rule_vers1.fw_ipnopt;
- rule_vers0->fw_tcpf = rule_vers1.fw_tcpf;
- rule_vers0->fw_tcpnf = rule_vers1.fw_tcpnf;
- rule_vers0->timestamp = rule_vers1.timestamp;
- rule_vers0->fw_prot = rule_vers1.fw_prot;
- rule_vers0->fw_nports = rule_vers1.fw_nports;
- rule_vers0->pipe_ptr = rule_vers1.pipe_ptr;
- rule_vers0->next_rule_ptr = rule_vers1.next_rule_ptr;
-
- if (rule_vers1.fw_ipflg && IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
-}
-
-void
-ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version)
-{
- switch (api_version) {
- case IP_FW_VERSION_0:
- {
- struct ip_old_fw *rule_vers0 = old_rule;
- ipfw_version_latest_to_zero(curr_rule, rule_vers0);
- break;
- }
- case IP_FW_VERSION_1:
- {
- struct ip_fw_compat *rule_vers1 = old_rule;
+ case O_IN:
+ if (cmd->len & F_NOT) {
+ compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
+ } else {
+ compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
+ }
+ break;
- ipfw_version_latest_to_one(curr_rule, rule_vers1);
- break;
- }
- case IP_FW_CURRENT_API_VERSION:
- /* ipfw2 for now, don't need to do anything */
- break;
-
- default:
- /* unknown version */
- break;
- }
-}
-
-
-/* ********************************************
- * *********** Convert to Latest **************
- * ********************************************/
+ case O_KEEP_STATE:
+ compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
+ break;
+
+ case O_LAYER2:
+ compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
+ break;
+
+ case O_XMIT:
+ {
+ ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
+ union ip_fw_if_compat ifu;
+
+ if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
+ /* any */
+ compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
+ ifu.fu_via_ip.s_addr = 0;
+ }
+ else if (ifcmd->p.ip.s_addr != 0) {
+ compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
+ ifu.fu_via_ip = ifcmd->p.ip;
+ } else {
+ compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
+ strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
+ ifu.fu_via_if_compat.unit = ifcmd->p.unit;
+ }
+ compat_rule->fw_out_if = ifu;
+
+ break;
+ }
+
+ case O_RECV:
+ {
+ ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
+ union ip_fw_if_compat ifu;
+
+ if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
+ /* any */
+ compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
+ ifu.fu_via_ip.s_addr = 0;
+ }
+ else if (ifcmd->p.ip.s_addr != 0) {
+ compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
+ ifu.fu_via_ip = ifcmd->p.ip;
+ } else {
+ compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
+ strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
+ ifu.fu_via_if_compat.unit = ifcmd->p.unit;
+ }
+ compat_rule->fw_in_if = ifu;
+
+ break;
+ }
+
+ case O_VIA:
+ {
+ ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
+ union ip_fw_if_compat ifu;
+
+ if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
+ /* any */
+ ifu.fu_via_ip.s_addr = 0;
+ }
+ else if (ifcmd->name[0] != '\0') {
+ compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
+ strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
+ ifu.fu_via_if_compat.unit = ifcmd->p.unit;
+ } else {
+ ifu.fu_via_ip = ifcmd->p.ip;
+ }
+ compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
+ compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
+
+ break;
+ }
+
+ case O_FRAG:
+ compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
+ break;
+
+ case O_IPOPT:
+ /* IP options */
+ compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
+ compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
+ break;
+
+ case O_TCPFLAGS:
+ /* check for "setup" */
+ if ((cmd->arg1 & 0xff) == TH_SYN &&
+ ((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
+ compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
+ compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
+ }
+ else {
+ compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
+ compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
+ }
+ break;
+
+ case O_TCPOPTS:
+ /* TCP options */
+ compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
+ compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
+ break;
+
+ case O_ESTAB:
+ compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
+ break;
+
+ case O_ICMPTYPE:
+ {
+ /* ICMP */
+ /* XXX: check this */
+ int i, type;
+
+ compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
+ for (i = 0; i < sizeof(uint32_t) ; i++) {
+ type = cmd32->d[0] & i;
+
+ compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |=
+ 1 << (type % (sizeof(unsigned) * 8));
+ }
+ break;
+ }
+ default:
+ break;
+ } /* switch */
+ } /* for */
+}
+
+static void
+ipfw_map_from_actions_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
+{
+ int l;
+ ipfw_insn *cmd;
+
+ for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
+ l > 0 ;
+ l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+ switch (cmd->opcode) {
+ case O_ACCEPT:
+ compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
+ break;
+ case O_COUNT:
+ compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
+ break;
+ case O_PIPE:
+ compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_QUEUE:
+ compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_SKIPTO:
+ compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
+ compat_rule->fw_skipto_rule_compat = cmd->arg1;
+ break;
+ case O_DIVERT:
+ compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_TEE:
+ compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_FORWARD_IP:
+ {
+ ipfw_insn_sa *p = (ipfw_insn_sa *)cmd;
+
+ compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
+ compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
+ compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
+ compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
+ compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
+
+ break;
+ }
+ case O_DENY:
+ compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
+ break;
+ case O_REJECT:
+ compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
+ compat_rule->fw_reject_code_compat = cmd->arg1;
+ break;
+ case O_CHECK_STATE:
+ compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+ipfw_map_from_actions_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
+{
+ int l;
+ ipfw_insn *cmd;
+ for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
+ l > 0 ;
+ l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+ switch (cmd->opcode) {
+ case O_ACCEPT:
+ compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
+ break;
+ case O_COUNT:
+ compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
+ break;
+ case O_PIPE:
+ compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_QUEUE:
+ compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_SKIPTO:
+ compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
+ compat_rule->fw_skipto_rule_compat = cmd->arg1;
+ break;
+ case O_DIVERT:
+ compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_TEE:
+ compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
+ compat_rule->fw_divert_port_compat = cmd->arg1;
+ break;
+ case O_FORWARD_IP:
+ {
+ ipfw_insn_sa *p = (ipfw_insn_sa *)cmd;
+
+ compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
+ compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
+ compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
+ compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
+ compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
+
+ break;
+ }
+ case O_DENY:
+ compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
+ break;
+ case O_REJECT:
+ compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
+ compat_rule->fw_reject_code_compat = cmd->arg1;
+ break;
+ case O_CHECK_STATE:
+ compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+ipfw_version_latest_to_one_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *rule_vers1)
+{
+ if (!rule_vers1)
+ return;
+
+ bzero(rule_vers1, sizeof(struct ip_fw_compat_32));
+
+ rule_vers1->version = IP_FW_VERSION_1;
+ rule_vers1->context = CAST_DOWN_EXPLICIT(user32_addr_t,curr_rule->context);
+ rule_vers1->fw_number = curr_rule->rulenum;
+ rule_vers1->fw_pcnt = curr_rule->pcnt;
+ rule_vers1->fw_bcnt = curr_rule->bcnt;
+ rule_vers1->timestamp = curr_rule->timestamp;
+
+ /* convert actions */
+ ipfw_map_from_actions_32(curr_rule, rule_vers1);
+
+ /* convert commands */
+ ipfw_map_from_cmds_32(curr_rule, rule_vers1);
+
+#if FW2_DEBUG_VERBOSE
+ ipfw_print_vers1_struct_32(rule_vers1);
+#endif
+}
+
+static void
+ipfw_version_latest_to_one_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *rule_vers1)
+{
+ if (!rule_vers1)
+ return;
+
+ bzero(rule_vers1, sizeof(struct ip_fw_compat_64));
+
+ rule_vers1->version = IP_FW_VERSION_1;
+ rule_vers1->context = CAST_DOWN_EXPLICIT(__uint64_t, curr_rule->context);
+ rule_vers1->fw_number = curr_rule->rulenum;
+ rule_vers1->fw_pcnt = curr_rule->pcnt;
+ rule_vers1->fw_bcnt = curr_rule->bcnt;
+ rule_vers1->timestamp = curr_rule->timestamp;
+
+ /* convert actions */
+ ipfw_map_from_actions_64(curr_rule, rule_vers1);
+
+ /* convert commands */
+ ipfw_map_from_cmds_64(curr_rule, rule_vers1);
+
+#if FW2_DEBUG_VERBOSE
+ ipfw_print_vers1_struct_64(rule_vers1);
+#endif
+}
+
+/* first convert to version one then to version zero */
+static void
+ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0, int is64user)
+{
+
+ if ( is64user ){
+ struct ip_fw_compat_64 rule_vers1;
+ ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, &rule_vers1);
+ bzero(rule_vers0, sizeof(struct ip_old_fw));
+ bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
+ bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
+ bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
+ bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
+ rule_vers0->fw_pcnt = rule_vers1.fw_pcnt;
+ rule_vers0->fw_bcnt = rule_vers1.fw_bcnt;
+ rule_vers0->fw_src = rule_vers1.fw_src;
+ rule_vers0->fw_dst = rule_vers1.fw_dst;
+ rule_vers0->fw_smsk = rule_vers1.fw_smsk;
+ rule_vers0->fw_dmsk = rule_vers1.fw_dmsk;
+ rule_vers0->fw_number = rule_vers1.fw_number;
+ rule_vers0->fw_flg = rule_vers1.fw_flg;
+ rule_vers0->fw_ipopt = rule_vers1.fw_ipopt;
+ rule_vers0->fw_ipnopt = rule_vers1.fw_ipnopt;
+ rule_vers0->fw_tcpf = rule_vers1.fw_tcpf;
+ rule_vers0->fw_tcpnf = rule_vers1.fw_tcpnf;
+ rule_vers0->timestamp = rule_vers1.timestamp;
+ rule_vers0->fw_prot = rule_vers1.fw_prot;
+ rule_vers0->fw_nports = rule_vers1.fw_nports;
+ rule_vers0->pipe_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
+ rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
+
+ if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
+ }
+ else {
+ struct ip_fw_compat_32 rule_vers1;
+ ipfw_version_latest_to_one_32( (struct ip_fw_32*)curr_rule, &rule_vers1);
+ bzero(rule_vers0, sizeof(struct ip_old_fw));
+ bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
+ bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
+ bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
+ bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
+ rule_vers0->fw_pcnt = rule_vers1.fw_pcnt;
+ rule_vers0->fw_bcnt = rule_vers1.fw_bcnt;
+ rule_vers0->fw_src = rule_vers1.fw_src;
+ rule_vers0->fw_dst = rule_vers1.fw_dst;
+ rule_vers0->fw_smsk = rule_vers1.fw_smsk;
+ rule_vers0->fw_dmsk = rule_vers1.fw_dmsk;
+ rule_vers0->fw_number = rule_vers1.fw_number;
+ rule_vers0->fw_flg = rule_vers1.fw_flg;
+ rule_vers0->fw_ipopt = rule_vers1.fw_ipopt;
+ rule_vers0->fw_ipnopt = rule_vers1.fw_ipnopt;
+ rule_vers0->fw_tcpf = rule_vers1.fw_tcpf;
+ rule_vers0->fw_tcpnf = rule_vers1.fw_tcpnf;
+ rule_vers0->timestamp = rule_vers1.timestamp;
+ rule_vers0->fw_prot = rule_vers1.fw_prot;
+ rule_vers0->fw_nports = rule_vers1.fw_nports;
+ rule_vers0->pipe_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
+ rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
+
+ if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
+ }
+
+}
+
+void
+ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version, int is64user)
+{
+ switch (api_version) {
+ case IP_FW_VERSION_0:
+ {
+ struct ip_old_fw *rule_vers0 = old_rule;
+
+ ipfw_version_latest_to_zero(curr_rule, rule_vers0, is64user);
+ break;
+ }
+ case IP_FW_VERSION_1:
+ {
+ if ( is64user )
+ ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, (struct ip_fw_compat_64 *)old_rule);
+ else
+ ipfw_version_latest_to_one_32((struct ip_fw_32*)curr_rule, (struct ip_fw_compat_32 *)old_rule);
+
+ break;
+ }
+ case IP_FW_CURRENT_API_VERSION:
+ /* ipfw2 for now, don't need to do anything */
+ break;
+
+ default:
+ /* unknown version */
+ break;
+ }
+}
+
+
+/* ********************************************
+ * *********** Convert to Latest **************
+ * ********************************************/
/* from ip_fw.c */
static int
-ipfw_check_vers1_struct(struct ip_fw_compat *frwl)
+ipfw_check_vers1_struct_32(struct ip_fw_compat_32 *frwl)
+{
+ /* Check for invalid flag bits */
+ if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
+ /*
+ printf(("%s undefined flag bits set (flags=%x)\n",
+ err_prefix, frwl->fw_flg));
+ */
+ return (EINVAL);
+ }
+ if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
+ /* check-state */
+ return 0 ;
+ }
+ /* Must apply to incoming or outgoing (or both) */
+ if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
+ /*
+ printf(("%s neither in nor out\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+ /* Empty interface name is no good */
+ if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
+ && !*frwl->fw_in_if.fu_via_if_compat.name)
+ || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
+ && !*frwl->fw_out_if.fu_via_if_compat.name)) {
+ /*
+ printf(("%s empty interface name\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+ /* Sanity check interface matching */
+ if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
+ ; /* allow "via" backwards compatibility */
+ } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
+ && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
+ /*
+ printf(("%s outgoing interface check on incoming\n",
+ err_prefix));
+ */
+ return (EINVAL);
+ }
+ /* Sanity check port ranges */
+ if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
+ /*
+ printf(("%s src range set but n_src_p=%d\n",
+ err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
+ */
+ return (EINVAL);
+ }
+ if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
+ /*
+ printf(("%s dst range set but n_dst_p=%d\n",
+ err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
+ */
+ return (EINVAL);
+ }
+ if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
+ /*
+ printf(("%s too many ports (%d+%d)\n",
+ err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
+ */
+ return (EINVAL);
+ }
+ /*
+ * Protocols other than TCP/UDP don't use port range
+ */
+ if ((frwl->fw_prot != IPPROTO_TCP) &&
+ (frwl->fw_prot != IPPROTO_UDP) &&
+ (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
+ /*
+ printf(("%s port(s) specified for non TCP/UDP rule\n",
+ err_prefix));
+ */
+ return (EINVAL);
+ }
+
+ /*
+ * Rather than modify the entry to make such entries work,
+ * we reject this rule and require user level utilities
+ * to enforce whatever policy they deem appropriate.
+ */
+ if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
+ (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
+ /*
+ printf(("%s rule never matches\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+
+ if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
+ (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
+ if (frwl->fw_nports) {
+ /*
+ printf(("%s cannot mix 'frag' and ports\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+ if (frwl->fw_prot == IPPROTO_TCP &&
+ frwl->fw_tcpf != frwl->fw_tcpnf) {
+ /*
+ printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+ }
+
+ /* Check command specific stuff */
+ switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
+ {
+ case IP_FW_F_REJECT_COMPAT:
+ if (frwl->fw_reject_code_compat >= 0x100
+ && !(frwl->fw_prot == IPPROTO_TCP
+ && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
+ /*
+ printf(("%s unknown reject code\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+ break;
+ case IP_FW_F_DIVERT_COMPAT: /* Diverting to port zero is invalid */
+ case IP_FW_F_TEE_COMPAT:
+ case IP_FW_F_PIPE_COMPAT: /* piping through 0 is invalid */
+ case IP_FW_F_QUEUE_COMPAT: /* piping through 0 is invalid */
+ if (frwl->fw_divert_port_compat == 0) {
+ /*
+ printf(("%s can't divert to port 0\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+ break;
+ case IP_FW_F_DENY_COMPAT:
+ case IP_FW_F_ACCEPT_COMPAT:
+ case IP_FW_F_COUNT_COMPAT:
+ case IP_FW_F_SKIPTO_COMPAT:
+ case IP_FW_F_FWD_COMPAT:
+ case IP_FW_F_UID_COMPAT:
+ break;
+ default:
+ /*
+ printf(("%s invalid command\n", err_prefix));
+ */
+ return (EINVAL);
+ }
+
+ return 0;
+}
+
+static int
+ipfw_check_vers1_struct_64(struct ip_fw_compat_64 *frwl)
{
/* Check for invalid flag bits */
if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
printf(("%s undefined flag bits set (flags=%x)\n",
err_prefix, frwl->fw_flg));
*/
+
+ return (EINVAL);
+ }
+ if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
+ /* check-state */
+ return 0 ;
+ }
+ /* Must apply to incoming or outgoing (or both) */
+ if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
+ /*
+ printf(("%s neither in nor out\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ /* Empty interface name is no good */
+ if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
+ && !*frwl->fw_in_if.fu_via_if_compat.name)
+ || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
+ && !*frwl->fw_out_if.fu_via_if_compat.name)) {
+ /*
+ printf(("%s empty interface name\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ /* Sanity check interface matching */
+ if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
+ ; /* allow "via" backwards compatibility */
+ } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
+ && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
+ /*
+ printf(("%s outgoing interface check on incoming\n",
+ err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ /* Sanity check port ranges */
+ if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
+ /*
+ printf(("%s src range set but n_src_p=%d\n",
+ err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
+ */
+
+ return (EINVAL);
+ }
+ if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
+ /*
+ printf(("%s dst range set but n_dst_p=%d\n",
+ err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
+ */
+
+ return (EINVAL);
+ }
+ if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
+ /*
+ printf(("%s too many ports (%d+%d)\n",
+ err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
+ */
+
+ return (EINVAL);
+ }
+ /*
+ * Protocols other than TCP/UDP don't use port range
+ */
+ if ((frwl->fw_prot != IPPROTO_TCP) &&
+ (frwl->fw_prot != IPPROTO_UDP) &&
+ (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
+ /*
+ printf(("%s port(s) specified for non TCP/UDP rule\n",
+ err_prefix));
+ */
+
+ return (EINVAL);
+ }
+
+ /*
+ * Rather than modify the entry to make such entries work,
+ * we reject this rule and require user level utilities
+ * to enforce whatever policy they deem appropriate.
+ */
+ if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
+ (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
+ /*
+ printf(("%s rule never matches\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+
+ if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
+ (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
+ if (frwl->fw_nports) {
+ /*
+ printf(("%s cannot mix 'frag' and ports\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ if (frwl->fw_prot == IPPROTO_TCP &&
+ frwl->fw_tcpf != frwl->fw_tcpnf) {
+ /*
+ printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ }
+
+ /* Check command specific stuff */
+ switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
+ {
+ case IP_FW_F_REJECT_COMPAT:
+ if (frwl->fw_reject_code_compat >= 0x100
+ && !(frwl->fw_prot == IPPROTO_TCP
+ && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
+ /*
+ printf(("%s unknown reject code\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ break;
+ case IP_FW_F_DIVERT_COMPAT: /* Diverting to port zero is invalid */
+ case IP_FW_F_TEE_COMPAT:
+ case IP_FW_F_PIPE_COMPAT: /* piping through 0 is invalid */
+ case IP_FW_F_QUEUE_COMPAT: /* piping through 0 is invalid */
+ if (frwl->fw_divert_port_compat == 0) {
+ /*
+ printf(("%s can't divert to port 0\n", err_prefix));
+ */
+
+ return (EINVAL);
+ }
+ break;
+ case IP_FW_F_DENY_COMPAT:
+ case IP_FW_F_ACCEPT_COMPAT:
+ case IP_FW_F_COUNT_COMPAT:
+ case IP_FW_F_SKIPTO_COMPAT:
+ case IP_FW_F_FWD_COMPAT:
+ case IP_FW_F_UID_COMPAT:
+ break;
+ default:
+ /*
+ printf(("%s invalid command\n", err_prefix));
+ */
+
return (EINVAL);
}
- if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
- /* check-state */
- return 0 ;
+
+ return 0;
+}
+
+static void
+ipfw_convert_to_cmds_32(struct ip_fw *curr_rule, struct ip_fw_compat_32 *compat_rule)
+{
+ int k;
+ uint32_t actbuf[255], cmdbuf[255];
+ ipfw_insn *action, *cmd, *src, *dst;
+ ipfw_insn *have_state = NULL; /* track check-state or keep-state */
+
+ if (!compat_rule || !curr_rule) {
+ return;
+ }
+
+ /* preemptively check the old ip_fw rule to
+ * make sure it's valid before starting to copy stuff
+ */
+ if (ipfw_check_vers1_struct_32(compat_rule)) {
+ /* bad rule */
+ return;
+ }
+
+ bzero(actbuf, sizeof(actbuf)); /* actions go here */
+ bzero(cmdbuf, sizeof(cmdbuf));
+
+ /* fill in action */
+ action = (ipfw_insn *)actbuf;
+ {
+ u_int flag = compat_rule->fw_flg;
+
+ action->len = 1; /* default */
+
+ if (flag & IP_FW_F_CHECK_S_COMPAT) {
+ have_state = action;
+ action->opcode = O_CHECK_STATE;
+ }
+ else {
+ switch (flag & IP_FW_F_COMMAND_COMPAT) {
+ case IP_FW_F_ACCEPT_COMPAT:
+ action->opcode = O_ACCEPT;
+ break;
+ case IP_FW_F_COUNT_COMPAT:
+ action->opcode = O_COUNT;
+ break;
+ case IP_FW_F_PIPE_COMPAT:
+ action->opcode = O_PIPE;
+ action->len = F_INSN_SIZE(ipfw_insn_pipe);
+ action->arg1 = compat_rule->fw_divert_port_compat;
+ break;
+ case IP_FW_F_QUEUE_COMPAT:
+ action->opcode = O_QUEUE;
+ action->len = F_INSN_SIZE(ipfw_insn_pipe);
+ action->arg1 = compat_rule->fw_divert_port_compat;
+ break;
+ case IP_FW_F_SKIPTO_COMPAT:
+ action->opcode = O_SKIPTO;
+ action->arg1 = compat_rule->fw_skipto_rule_compat;
+ break;
+ case IP_FW_F_DIVERT_COMPAT:
+ action->opcode = O_DIVERT;
+ action->arg1 = compat_rule->fw_divert_port_compat;
+ break;
+ case IP_FW_F_TEE_COMPAT:
+ action->opcode = O_TEE;
+ action->arg1 = compat_rule->fw_divert_port_compat;
+ break;
+ case IP_FW_F_FWD_COMPAT:
+ {
+ ipfw_insn_sa *p = (ipfw_insn_sa *)action;
+
+ action->opcode = O_FORWARD_IP;
+ action->len = F_INSN_SIZE(ipfw_insn_sa);
+
+ p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
+ p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
+ p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
+ p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
+
+ break;
+ }
+ case IP_FW_F_DENY_COMPAT:
+ action->opcode = O_DENY;
+ action->arg1 = 0;
+ break;
+ case IP_FW_F_REJECT_COMPAT:
+ action->opcode = O_REJECT;
+ action->arg1 = compat_rule->fw_reject_code_compat;
+ break;
+ default:
+ action->opcode = O_NOP;
+ break;
+ }
+ }
+
+ /* action is mandatory */
+ if (action->opcode == O_NOP) {
+ return;
+ }
+
+ action = next_cmd(action);
+ } /* end actions */
+
+ cmd = (ipfw_insn *)cmdbuf;
+
+ /* this is O_CHECK_STATE, we're done */
+ if (have_state) {
+ goto done;
+ }
+
+ {
+ ipfw_insn *prev = NULL;
+ u_int flag = compat_rule->fw_flg;
+
+ /* logging */
+ if (flag & IP_FW_F_PRN_COMPAT) {
+ ipfw_insn_log *c = (ipfw_insn_log *)cmd;
+
+ cmd->opcode = O_LOG;
+ cmd->len |= F_INSN_SIZE(ipfw_insn_log);
+ c->max_log = compat_rule->fw_logamount;
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ /* protocol */
+ if (compat_rule->fw_prot != 0) {
+ fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ /* source */
+ if (flag & IP_FW_F_SME_COMPAT) {
+ cmd->opcode = O_IP_SRC_ME;
+ cmd->len |= F_INSN_SIZE(ipfw_insn);
+ if (flag & IP_FW_F_INVSRC_COMPAT) {
+ cmd->len ^= F_NOT; /* toggle F_NOT */
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ } else {
+ if (compat_rule->fw_smsk.s_addr != 0) {
+ /* addr/mask */
+ ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
+
+ ip->addr = compat_rule->fw_src;
+ ip->mask = compat_rule->fw_smsk;
+ cmd->opcode = O_IP_SRC_MASK;
+ cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
+ } else {
+ /* one IP */
+ ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
+
+ if (compat_rule->fw_src.s_addr == 0) {
+ /* any */
+ cmd32->o.len &= ~F_LEN_MASK; /* zero len */
+ } else {
+ cmd32->d[0] = compat_rule->fw_src.s_addr;
+ cmd32->o.opcode = O_IP_SRC;
+ cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+ }
+ }
+
+ if (flag & IP_FW_F_INVSRC_COMPAT) {
+ cmd->len ^= F_NOT; /* toggle F_NOT */
+ }
+
+ if (F_LEN(cmd) != 0) { /* !any */
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ }
+
+ /* source ports */
+ {
+ ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
+ uint16_t *p = ports->ports;
+ int i, j = 0,
+ nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
+ have_range = 0;
+
+ cmd->opcode = O_IP_SRCPORT;
+ for (i = 0; i < nports; i++) {
+ if (((flag & IP_FW_F_SRNG_COMPAT) ||
+ (flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
+ p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
+ p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+ have_range = 1;
+ } else {
+ p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+ }
+ p += 2;
+ j++;
+ }
+
+ if (j > 0) {
+ ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ /* destination */
+ if (flag & IP_FW_F_DME_COMPAT) {
+ cmd->opcode = O_IP_DST_ME;
+ cmd->len |= F_INSN_SIZE(ipfw_insn);
+ if (flag & IP_FW_F_INVDST_COMPAT) {
+ cmd->len ^= F_NOT; /* toggle F_NOT */
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ } else {
+ if (compat_rule->fw_dmsk.s_addr != 0) {
+ /* addr/mask */
+ ipfw_insn_ip *ip = (ipfw_insn_ip *)cmd;
+
+ ip->addr = compat_rule->fw_dst;
+ ip->mask = compat_rule->fw_dmsk;
+ cmd->opcode = O_IP_DST_MASK;
+ cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
+ } else {
+ /* one IP */
+ ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
+
+ if (compat_rule->fw_dst.s_addr == 0) {
+ /* any */
+ cmd32->o.len &= ~F_LEN_MASK; /* zero len */
+ } else {
+ cmd32->d[0] = compat_rule->fw_dst.s_addr;
+ cmd32->o.opcode = O_IP_DST;
+ cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+ }
+ }
+
+ if (flag & IP_FW_F_INVDST_COMPAT) {
+ cmd->len ^= F_NOT; /* toggle F_NOT */
+ }
+
+ if (F_LEN(cmd) != 0) { /* !any */
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ }
+
+ /* dest. ports */
+ {
+ ipfw_insn_u16 *ports = (ipfw_insn_u16 *)cmd;
+ uint16_t *p = ports->ports;
+ int i = IP_FW_GETNSRCP_COMPAT(compat_rule),
+ j = 0,
+ nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
+ have_range = 0;
+
+ cmd->opcode = O_IP_DSTPORT;
+ for (; i < nports; i++, p += 2) {
+ if (((flag & IP_FW_F_DRNG_COMPAT) ||
+ (flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
+ /* range */
+ p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
+ p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+ have_range = 1;
+ } else {
+ p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+ }
+ j++;
+ }
+
+ if (j > 0) {
+ ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
}
- /* Must apply to incoming or outgoing (or both) */
- if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
- /*
- printf(("%s neither in nor out\n", err_prefix));
- */
- return (EINVAL);
+
+ if (flag & IP_FW_F_UID_COMPAT) {
+ ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
+
+ cmd32->o.opcode = O_UID;
+ cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+ cmd32->d[0] = compat_rule->fw_uid;
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
}
- /* Empty interface name is no good */
- if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
- && !*frwl->fw_in_if.fu_via_if_compat.name)
- || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
- && !*frwl->fw_out_if.fu_via_if_compat.name)) {
- /*
- printf(("%s empty interface name\n", err_prefix));
- */
- return (EINVAL);
+
+ if (flag & IP_FW_F_KEEP_S_COMPAT) {
+ have_state = cmd;
+ fill_cmd(cmd, O_KEEP_STATE, 0);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
}
- /* Sanity check interface matching */
- if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
- ; /* allow "via" backwards compatibility */
- } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
- && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
- /*
- printf(("%s outgoing interface check on incoming\n",
- err_prefix));
- */
- return (EINVAL);
+ if (flag & IP_FW_BRIDGED_COMPAT) {
+ fill_cmd(cmd, O_LAYER2, 0);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
+ /* via */
+ ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
+ union ip_fw_if_compat ifu = compat_rule->fw_in_if;
+
+ cmd->opcode = O_VIA;
+ ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+
+ if (ifu.fu_via_ip.s_addr == 0) {
+ /* "any" */
+ ifcmd->name[0] = '\0';
+ ifcmd->o.len = 0;
+ }
+ else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
+ /* by name */
+ strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
+ ifcmd->p.unit = ifu.fu_via_if_compat.unit;
+ } else {
+ /* by addr */
+ ifcmd->p.ip = ifu.fu_via_ip;
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ } else {
+ if (flag & IP_FW_F_IN_COMPAT) {
+ fill_cmd(cmd, O_IN, 0);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ if (flag & IP_FW_F_OUT_COMPAT) {
+ /* if the previous command was O_IN, and this
+ * is being set as well, it's equivalent to not
+ * having either command, so let's back up prev
+ * to the cmd before it and move cmd to prev.
+ */
+ if (prev->opcode == O_IN) {
+ cmd = prev;
+ bzero(cmd, sizeof(*cmd));
+ } else {
+ cmd->len ^= F_NOT; /* toggle F_NOT */
+ fill_cmd(cmd, O_IN, 0);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ }
+ if (flag & IP_FW_F_OIFACE_COMPAT) {
+ /* xmit */
+ ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
+ union ip_fw_if_compat ifu = compat_rule->fw_out_if;
+
+ cmd->opcode = O_XMIT;
+ ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+
+ if (ifu.fu_via_ip.s_addr == 0) {
+ /* "any" */
+ ifcmd->name[0] = '\0';
+ ifcmd->o.len = 0;
+ }
+ else if (flag & IP_FW_F_OIFNAME_COMPAT) {
+ /* by name */
+ strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
+ ifcmd->p.unit = ifu.fu_via_if_compat.unit;
+ } else {
+ /* by addr */
+ ifcmd->p.ip = ifu.fu_via_ip;
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ else if (flag & IP_FW_F_IIFACE_COMPAT) {
+ /* recv */
+ ipfw_insn_if *ifcmd = (ipfw_insn_if *)cmd;
+ union ip_fw_if_compat ifu = compat_rule->fw_in_if;
+
+ cmd->opcode = O_RECV;
+ ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+
+ if (ifu.fu_via_ip.s_addr == 0) {
+ /* "any" */
+ ifcmd->name[0] = '\0';
+ ifcmd->o.len = 0;
+ }
+ else if (flag & IP_FW_F_IIFNAME_COMPAT) {
+ /* by name */
+ strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
+ ifcmd->p.unit = ifu.fu_via_if_compat.unit;
+ } else {
+ /* by addr */
+ ifcmd->p.ip = ifu.fu_via_ip;
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ }
+
+ if (flag & IP_FW_F_FRAG_COMPAT) {
+ fill_cmd(cmd, O_FRAG, 0);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ /* IP options */
+ if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
+ fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
+ (compat_rule->fw_ipnopt & 0xff) << 8);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ if (compat_rule->fw_prot == IPPROTO_TCP) {
+ if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
+ fill_cmd(cmd, O_ESTAB, 0);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+
+ /* TCP options and flags */
+ if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
+ if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
+ compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
+ fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ( (TH_ACK) & 0xff) <<8);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ else {
+ fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
+ (compat_rule->fw_tcpnf & 0xff) << 8);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
+ }
+ if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
+ fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
+ (compat_rule->fw_tcpnopt & 0xff) << 8);
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
+ }
}
- /* Sanity check port ranges */
- if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
- /*
- printf(("%s src range set but n_src_p=%d\n",
- err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
- */
- return (EINVAL);
+
+ /* ICMP */
+ /* XXX: check this */
+ if (flag & IP_FW_F_ICMPBIT_COMPAT) {
+ int i;
+ ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
+
+ cmd32->o.opcode = O_ICMPTYPE;
+ cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+
+ for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
+ cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
+ }
+
+ prev = cmd;
+ cmd = next_cmd(cmd);
}
- if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
- /*
- printf(("%s dst range set but n_dst_p=%d\n",
- err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
- */
- return (EINVAL);
+ } /* end commands */
+
+done:
+ /* finally, copy everything into the current
+ * rule buffer in the right order.
+ */
+ dst = curr_rule->cmd;
+
+ /* first, do match probability */
+ if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
+ dst->opcode = O_PROB;
+ dst->len = 2;
+ *((int32_t *)(dst+1)) = compat_rule->pipe_ptr;
+ dst += dst->len;
}
- if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
- /*
- printf(("%s too many ports (%d+%d)\n",
- err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
- */
- return (EINVAL);
+
+ /* generate O_PROBE_STATE if necessary */
+ if (have_state && have_state->opcode != O_CHECK_STATE) {
+ fill_cmd(dst, O_PROBE_STATE, 0);
+ dst = next_cmd(dst);
}
+
/*
- * Protocols other than TCP/UDP don't use port range
+ * copy all commands but O_LOG, O_KEEP_STATE
*/
- if ((frwl->fw_prot != IPPROTO_TCP) &&
- (frwl->fw_prot != IPPROTO_UDP) &&
- (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
- /*
- printf(("%s port(s) specified for non TCP/UDP rule\n",
- err_prefix));
- */
- return (EINVAL);
+ for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
+ k = F_LEN(src);
+
+ switch (src->opcode) {
+ case O_LOG:
+ case O_KEEP_STATE:
+ break;
+ default:
+ bcopy(src, dst, k * sizeof(uint32_t));
+ dst += k;
+ }
}
/*
- * Rather than modify the entry to make such entries work,
- * we reject this rule and require user level utilities
- * to enforce whatever policy they deem appropriate.
+ * put back the have_state command as last opcode
*/
- if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
- (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
- /*
- printf(("%s rule never matches\n", err_prefix));
- */
- return (EINVAL);
+ if (have_state && have_state->opcode != O_CHECK_STATE) {
+ k = F_LEN(have_state);
+ bcopy(have_state, dst, k * sizeof(uint32_t));
+ dst += k;
}
+
+ /*
+ * start action section
+ */
+ curr_rule->act_ofs = dst - curr_rule->cmd;
- if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
- (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
- if (frwl->fw_nports) {
- /*
- printf(("%s cannot mix 'frag' and ports\n", err_prefix));
- */
- return (EINVAL);
- }
- if (frwl->fw_prot == IPPROTO_TCP &&
- frwl->fw_tcpf != frwl->fw_tcpnf) {
- /*
- printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
- */
- return (EINVAL);
- }
+ /*
+ * put back O_LOG if necessary
+ */
+ src = (ipfw_insn *)cmdbuf;
+ if (src->opcode == O_LOG) {
+ k = F_LEN(src);
+ bcopy(src, dst, k * sizeof(uint32_t));
+ dst += k;
}
-
- /* Check command specific stuff */
- switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
- {
- case IP_FW_F_REJECT_COMPAT:
- if (frwl->fw_reject_code_compat >= 0x100
- && !(frwl->fw_prot == IPPROTO_TCP
- && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
- /*
- printf(("%s unknown reject code\n", err_prefix));
- */
- return (EINVAL);
- }
- break;
- case IP_FW_F_DIVERT_COMPAT: /* Diverting to port zero is invalid */
- case IP_FW_F_TEE_COMPAT:
- case IP_FW_F_PIPE_COMPAT: /* piping through 0 is invalid */
- case IP_FW_F_QUEUE_COMPAT: /* piping through 0 is invalid */
- if (frwl->fw_divert_port_compat == 0) {
- /*
- printf(("%s can't divert to port 0\n", err_prefix));
- */
- return (EINVAL);
- }
- break;
- case IP_FW_F_DENY_COMPAT:
- case IP_FW_F_ACCEPT_COMPAT:
- case IP_FW_F_COUNT_COMPAT:
- case IP_FW_F_SKIPTO_COMPAT:
- case IP_FW_F_FWD_COMPAT:
- case IP_FW_F_UID_COMPAT:
- break;
- default:
- /*
- printf(("%s invalid command\n", err_prefix));
- */
- return (EINVAL);
+
+ /*
+ * copy all other actions
+ */
+ for (src = (ipfw_insn *)actbuf; src != action; src += k) {
+ k = F_LEN(src);
+ bcopy(src, dst, k * sizeof(uint32_t));
+ dst += k;
}
- return 0;
+ curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
+
+ return;
}
static void
-ipfw_convert_to_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
+ipfw_convert_to_cmds_64(struct ip_fw *curr_rule, struct ip_fw_compat_64 *compat_rule)
{
int k;
uint32_t actbuf[255], cmdbuf[255];
ipfw_insn *action, *cmd, *src, *dst;
ipfw_insn *have_state = NULL; /* track check-state or keep-state */
- if (!compat_rule || !curr_rule || !(curr_rule->cmd)) {
+ if (!compat_rule || !curr_rule) {
return;
}
/* preemptively check the old ip_fw rule to
* make sure it's valid before starting to copy stuff
*/
- if (ipfw_check_vers1_struct(compat_rule)) {
+ if (ipfw_check_vers1_struct_64(compat_rule)) {
/* bad rule */
return;
}
bzero(actbuf, sizeof(actbuf)); /* actions go here */
bzero(cmdbuf, sizeof(cmdbuf));
-
/* fill in action */
action = (ipfw_insn *)actbuf;
{
if (flag & IP_FW_F_ICMPBIT_COMPAT) {
int i;
ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* alias for cmd */
-
cmd32->o.opcode = O_ICMPTYPE;
cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
cmd = next_cmd(cmd);
}
} /* end commands */
-
done:
/* finally, copy everything into the current
* rule buffer in the right order.
*/
for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
k = F_LEN(src);
-
switch (src->opcode) {
case O_LOG:
case O_KEEP_STATE:
}
curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
-
return;
}
static int
-ipfw_version_one_to_version_two(struct sockopt *sopt, struct ip_fw *curr_rule,
- struct ip_fw_compat *rule_vers1)
+ipfw_version_one_to_version_two_32(struct sockopt *sopt, struct ip_fw *curr_rule,
+ struct ip_fw_compat_32 *rule_vers1)
{
int err = EINVAL;
- struct ip_fw_compat *rule_ptr;
- struct ip_fw_compat rule;
+ struct ip_fw_compat_32 *rule_ptr;
+ struct ip_fw_compat_32 rule;
if (rule_vers1) {
rule_ptr = rule_vers1;
err = 0;
} else {
/* do some basic size checking here, more extensive checking later */
- if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat))
+ if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_32))
return err;
- if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat),
- sizeof(struct ip_fw_compat)))) {
+ if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_32),
+ sizeof(struct ip_fw_compat_32)))) {
return err;
}
}
/* deal with commands */
- ipfw_convert_to_cmds(curr_rule, rule_ptr);
+ ipfw_convert_to_cmds_32(curr_rule, rule_ptr);
+
+ curr_rule->version = IP_FW_CURRENT_API_VERSION;
+ curr_rule->context = CAST_DOWN_EXPLICIT(void*, rule_ptr->context);
+ curr_rule->rulenum = rule_ptr->fw_number;
+ curr_rule->pcnt = rule_ptr->fw_pcnt;
+ curr_rule->bcnt = rule_ptr->fw_bcnt;
+ curr_rule->timestamp = rule_ptr->timestamp;
+
+
+#if FW2_DEBUG_VERBOSE
+ ipfw_print_vers2_struct(curr_rule);
+#endif
+
+ return err;
+}
+
+static int
+ipfw_version_one_to_version_two_64(struct sockopt *sopt, struct ip_fw *curr_rule,
+ struct ip_fw_compat_64 *rule_vers1)
+{
+ int err = EINVAL;
+ struct ip_fw_compat_64 *rule_ptr;
+ struct ip_fw_compat_64 rule;
+
+ if (rule_vers1) {
+ rule_ptr = rule_vers1;
+ err = 0;
+ } else {
+ /* do some basic size checking here, more extensive checking later */
+ if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_64))
+ return err;
+
+ if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_64),
+ sizeof(struct ip_fw_compat_64)))) {
+ return err;
+ }
+ rule_ptr = &rule;
+ }
+
+ /* deal with commands */
+ ipfw_convert_to_cmds_64(curr_rule, rule_ptr);
curr_rule->version = IP_FW_CURRENT_API_VERSION;
- curr_rule->context = rule_ptr->context;
+ curr_rule->context = CAST_DOWN_EXPLICIT( void *, rule_ptr->context);
curr_rule->rulenum = rule_ptr->fw_number;
curr_rule->pcnt = rule_ptr->fw_pcnt;
curr_rule->bcnt = rule_ptr->fw_bcnt;
#if FW2_DEBUG_VERBOSE
ipfw_print_vers2_struct(curr_rule);
-#endif /* FW2_DEBUG_VERBOSE */
+#endif
return err;
}
* latest version of the firewall is ipfw2.
*/
static int
-ipfw_version_one_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat *rule_vers1)
+ipfw_version_one_to_latest_32(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_32 *rule_vers1)
+{
+ int err;
+
+ /* if rule_vers1 is not null then this is coming from
+ * ipfw_version_zero_to_latest(), so pass that along;
+ * otherwise let ipfw_version_one_to_version_two()
+ * get the rule from sopt.
+ */
+ err = ipfw_version_one_to_version_two_32(sopt, curr_rule, rule_vers1);
+
+ return err;
+}
+
+static int
+ipfw_version_one_to_latest_64(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_64 *rule_vers1)
{
int err;
* otherwise let ipfw_version_one_to_version_two()
* get the rule from sopt.
*/
- err = ipfw_version_one_to_version_two(sopt, curr_rule, rule_vers1);
+ err = ipfw_version_one_to_version_two_64(sopt, curr_rule, rule_vers1);
return err;
}
+
+#if 0
+
+/*
+ * XXX - ipfw_version_zero_to_one
+ *
+ * This function is only used in version #1 of ipfw, which is now deprecated.
+ *
+ */
+
static void
ipfw_version_zero_to_one(struct ip_old_fw *rule_vers0, struct ip_fw_compat *rule_vers1)
{
rule_vers1->fw_ipflg = (rule_vers0->fw_tcpf & IP_OLD_FW_TCPF_ESTAB) ? IP_FW_IF_TCPEST_COMPAT : 0;
}
-/* first convert to version one, then to version two */
-static int
-ipfw_version_zero_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule)
-{
- int err;
- struct ip_old_fw rule_vers0;
- struct ip_fw_compat rule_vers1;
-
- if (sopt->sopt_name == IP_OLD_FW_GET ||
- sopt->sopt_name == IP_OLD_FW_FLUSH ||
- sopt->sopt_val == USER_ADDR_NULL) {
- /* In the old-style API, it was legal to not pass in a rule
- * structure for certain firewall operations (e.g. flush,
- * reset log). If that's the situation, we pretend we received
- * a blank structure. */
- bzero(curr_rule, sizeof(struct ip_fw));
- curr_rule->version = 10;
- }
- else {
- if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_old_fw)) {
- return EINVAL;
- }
-
- err = sooptcopyin(sopt, &rule_vers0, sizeof(struct ip_old_fw),
- sizeof(struct ip_old_fw));
- if (err) {
- return err;
- }
-
- ipfw_version_zero_to_one(&rule_vers0, &rule_vers1);
- }
-
- return (ipfw_version_one_to_latest(sopt, curr_rule, &rule_vers1));
-}
+#endif /* !ipfw_version_zero_to_one */
/* rule is a u_int32_t buffer[255] into which the converted
* (if necessary) rules go.
*/
int
-ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version)
+ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version, int is64user)
{
int err = 0;
*/
switch (api_version) {
case IP_FW_VERSION_0:
- /* this is the oldest version we support */
- err = ipfw_version_zero_to_latest(sopt, curr_rule);
+ /* we're not supporting VERSION 0 */
+ err = EOPNOTSUPP;
break;
case IP_FW_VERSION_1:
/* this is the version supported in Panther */
- err = ipfw_version_one_to_latest(sopt, curr_rule, NULL);
+ if ( is64user )
+ err = ipfw_version_one_to_latest_64(sopt, curr_rule, NULL);
+ else
+ err = ipfw_version_one_to_latest_32(sopt, curr_rule, NULL);
break;
case IP_FW_CURRENT_API_VERSION:
/* working off the fact that the offset
* is the same in both structs.
*/
- struct ip_fw rule;
-
- if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw))
- return EINVAL;
+ struct ip_fw_64 rule;
+ size_t copyinsize;
+
+ if (proc_is64bit(sopt->sopt_p))
+ copyinsize = sizeof(struct ip_fw_64);
+ else
+ copyinsize = sizeof(struct ip_fw_32);
- if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw),
- sizeof(struct ip_fw)))) {
+ if (!sopt->sopt_val || sopt->sopt_valsize < copyinsize)
+ return EINVAL;
+ if ((err = sooptcopyin(sopt, &rule, copyinsize, copyinsize))) {
return err;
}
if (command) {
*command = cmd;
}
-
if (api_version) {
*api_version = vers;
}