summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netpfil/ipfw/ip_fw2.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netpfil/ipfw/ip_fw2.c')
-rw-r--r--freebsd/sys/netpfil/ipfw/ip_fw2.c199
1 files changed, 130 insertions, 69 deletions
diff --git a/freebsd/sys/netpfil/ipfw/ip_fw2.c b/freebsd/sys/netpfil/ipfw/ip_fw2.c
index 945ad170..1425d95f 100644
--- a/freebsd/sys/netpfil/ipfw/ip_fw2.c
+++ b/freebsd/sys/netpfil/ipfw/ip_fw2.c
@@ -384,8 +384,8 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain,
/* Check by name or by IP address */
if (cmd->name[0] != '\0') { /* match by name */
if (cmd->name[0] == '\1') /* use tablearg to match */
- return ipfw_lookup_table_extended(chain, cmd->p.kidx, 0,
- &ifp->if_index, tablearg);
+ return ipfw_lookup_table(chain, cmd->p.kidx, 0,
+ &ifp->if_index, tablearg);
/* Check name */
if (cmd->p.glob) {
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -1002,7 +1002,6 @@ ipfw_chk(struct ip_fw_args *args)
int is_ipv4 = 0;
int done = 0; /* flag to exit the outer loop */
- IPFW_RLOCK_TRACKER;
if (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready))
return (IP_FW_PASS); /* accept */
@@ -1465,96 +1464,142 @@ do { \
src_ip.s_addr);
break;
- case O_IP_SRC_LOOKUP:
case O_IP_DST_LOOKUP:
- if (is_ipv4) {
- uint32_t key =
- (cmd->opcode == O_IP_DST_LOOKUP) ?
- dst_ip.s_addr : src_ip.s_addr;
- uint32_t v = 0;
-
- if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
- /* generic lookup. The key must be
- * in 32bit big-endian format.
- */
- v = ((ipfw_insn_u32 *)cmd)->d[1];
- if (v == 0)
- key = dst_ip.s_addr;
- else if (v == 1)
- key = src_ip.s_addr;
- else if (v == 6) /* dscp */
- key = (ip->ip_tos >> 2) & 0x3f;
- else if (offset != 0)
- break;
- else if (proto != IPPROTO_TCP &&
- proto != IPPROTO_UDP)
- break;
- else if (v == 2)
- key = dst_port;
- else if (v == 3)
- key = src_port;
+ {
+ void *pkey;
+ uint32_t vidx, key;
+ uint16_t keylen;
+
+ if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+ /* Determine lookup key type */
+ vidx = ((ipfw_insn_u32 *)cmd)->d[1];
+ if (vidx != 4 /* uid */ &&
+ vidx != 5 /* jail */ &&
+ is_ipv6 == 0 && is_ipv4 == 0)
+ break;
+ /* Determine key length */
+ if (vidx == 0 /* dst-ip */ ||
+ vidx == 1 /* src-ip */)
+ keylen = is_ipv6 ?
+ sizeof(struct in6_addr):
+ sizeof(in_addr_t);
+ else {
+ keylen = sizeof(key);
+ pkey = &key;
+ }
+ if (vidx == 0 /* dst-ip */)
+ pkey = is_ipv4 ? (void *)&dst_ip:
+ (void *)&args->f_id.dst_ip6;
+ else if (vidx == 1 /* src-ip */)
+ pkey = is_ipv4 ? (void *)&src_ip:
+ (void *)&args->f_id.src_ip6;
+ else if (vidx == 6 /* dscp */) {
+ if (is_ipv4)
+ key = ip->ip_tos >> 2;
+ else {
+ key = args->f_id.flow_id6;
+ key = (key & 0x0f) << 2 |
+ (key & 0xf000) >> 14;
+ }
+ key &= 0x3f;
+ } else if (vidx == 2 /* dst-port */ ||
+ vidx == 3 /* src-port */) {
+ /* Skip fragments */
+ if (offset != 0)
+ break;
+ /* Skip proto without ports */
+ if (proto != IPPROTO_TCP &&
+ proto != IPPROTO_UDP &&
+ proto != IPPROTO_SCTP)
+ break;
+ if (vidx == 2 /* dst-port */)
+ key = dst_port;
+ else
+ key = src_port;
+ }
#ifndef USERSPACE
- else if (v == 4 || v == 5) {
- check_uidgid(
- (ipfw_insn_u32 *)cmd,
- args, &ucred_lookup,
+ else if (vidx == 4 /* uid */ ||
+ vidx == 5 /* jail */) {
+ check_uidgid(
+ (ipfw_insn_u32 *)cmd,
+ args, &ucred_lookup,
#ifdef __FreeBSD__
- &ucred_cache);
- if (v == 4 /* O_UID */)
+ &ucred_cache);
+ if (vidx == 4 /* uid */)
#ifndef __rtems__
- key = ucred_cache->cr_uid;
+ key = ucred_cache->cr_uid;
#else /* __rtems__ */
- key = BSD_DEFAULT_UID;
+ key = BSD_DEFAULT_UID;
#endif /* __rtems__ */
- else if (v == 5 /* O_JAIL */)
+ else if (vidx == 5 /* jail */)
#ifndef __rtems__
- key = ucred_cache->cr_prison->pr_id;
+ key = ucred_cache->cr_prison->pr_id;
#else /* __rtems__ */
- key = BSD_DEFAULT_PRISON->pr_id;
+ key = BSD_DEFAULT_PRISON->pr_id;
#endif /* __rtems__ */
#else /* !__FreeBSD__ */
- (void *)&ucred_cache);
- if (v ==4 /* O_UID */)
- key = ucred_cache.uid;
- else if (v == 5 /* O_JAIL */)
- key = ucred_cache.xid;
+ (void *)&ucred_cache);
+ if (vidx == 4 /* uid */)
+ key = ucred_cache.uid;
+ else if (vidx == 5 /* jail */)
+ key = ucred_cache.xid;
#endif /* !__FreeBSD__ */
}
#endif /* !USERSPACE */
else
- break;
- }
- match = ipfw_lookup_table(chain,
- cmd->arg1, key, &v);
- if (!match)
+ break;
+ match = ipfw_lookup_table(chain,
+ cmd->arg1, keylen, pkey, &vidx);
+ if (!match)
+ break;
+ tablearg = vidx;
break;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
- match =
- ((ipfw_insn_u32 *)cmd)->d[0] == v;
- else
- tablearg = v;
+ }
+ /* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */
+ /* FALLTHROUGH */
+ }
+ case O_IP_SRC_LOOKUP:
+ {
+ void *pkey;
+ uint32_t vidx;
+ uint16_t keylen;
+
+ if (is_ipv4) {
+ keylen = sizeof(in_addr_t);
+ if (cmd->opcode == O_IP_DST_LOOKUP)
+ pkey = &dst_ip;
+ else
+ pkey = &src_ip;
} else if (is_ipv6) {
- uint32_t v = 0;
- void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
- &args->f_id.dst_ip6: &args->f_id.src_ip6;
- match = ipfw_lookup_table_extended(chain,
- cmd->arg1,
- sizeof(struct in6_addr),
- pkey, &v);
- if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
- match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
- if (match)
- tablearg = v;
+ keylen = sizeof(struct in6_addr);
+ if (cmd->opcode == O_IP_DST_LOOKUP)
+ pkey = &args->f_id.dst_ip6;
+ else
+ pkey = &args->f_id.src_ip6;
+ } else
+ break;
+ match = ipfw_lookup_table(chain, cmd->arg1,
+ keylen, pkey, &vidx);
+ if (!match)
+ break;
+ if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
+ match = ((ipfw_insn_u32 *)cmd)->d[0] ==
+ TARG_VAL(chain, vidx, tag);
+ if (!match)
+ break;
}
+ tablearg = vidx;
break;
+ }
case O_IP_FLOW_LOOKUP:
{
uint32_t v = 0;
- match = ipfw_lookup_table_extended(chain,
+ match = ipfw_lookup_table(chain,
cmd->arg1, 0, &args->f_id, &v);
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
- match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
+ match = ((ipfw_insn_u32 *)cmd)->d[0] ==
+ TARG_VAL(chain, v, tag);
if (match)
tablearg = v;
}
@@ -2583,6 +2628,22 @@ do { \
l = 0; /* in any case exit inner loop */
retval = ipfw_run_eaction(chain, args,
cmd, &done);
+ /*
+ * If both @retval and @done are zero,
+ * consider this as rule matching and
+ * update counters.
+ */
+ if (retval == 0 && done == 0) {
+ IPFW_INC_RULE_COUNTER(f, pktlen);
+ /*
+ * Reset the result of the last
+ * dynamic state lookup.
+ * External action can change
+ * @args content, and it may be
+ * used for new state lookup later.
+ */
+ dyn_dir = MATCH_UNKNOWN;
+ }
break;
default: