summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2017-03-19 07:34:19 +0000
committerLuiz Souza <luiz@netgate.com>2017-07-15 11:13:39 -0500
commit47b0e8446bdc7d22edeced3e8371f8fead9d9b46 (patch)
tree6c36f05eb2ce074d17bd477acf9987ec77f4c78f
parent8f9d443add7b88b37079e841ed5ae9ffde397622 (diff)
downloadFreeBSD-src-47b0e8446bdc7d22edeced3e8371f8fead9d9b46.zip
FreeBSD-src-47b0e8446bdc7d22edeced3e8371f8fead9d9b46.tar.gz
MFC r314716:
Add IPv6 support to O_IP_DST_LOOKUP opcode. o check the size of O_IP_SRC_LOOKUP opcode, it can not exceed the size of ipfw_insn_u32; o rename ipfw_lookup_table_extended() function into ipfw_lookup_table() and remove old ipfw_lookup_table(); o use args->f_id.flow_id6 that is in host byte order to get DSCP value; o add SCTP ports support to 'lookup src/dst-port' opcode; o add IPv6 support to 'lookup src/dst-ip' opcode. PR: 217292 Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D9873 (cherry picked from commit d05930372b11a5433026bb7e67fde41321a29dac)
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c176
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h4
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c2
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c19
4 files changed, 114 insertions, 87 deletions
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index e28863e..fdebef9 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -382,8 +382,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)
@@ -1466,86 +1466,130 @@ 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 */)
- key = ucred_cache->cr_uid;
- else if (v == 5 /* O_JAIL */)
- key = ucred_cache->cr_prison->pr_id;
+ &ucred_cache);
+ if (vidx == 4 /* uid */)
+ key = ucred_cache->cr_uid;
+ else if (vidx == 5 /* jail */)
+ key = ucred_cache->cr_prison->pr_id;
#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] ==
- TARG_VAL(chain, v, tag);
- 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] ==
- TARG_VAL(chain, v, tag);
- 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] ==
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index 758479f..810b21f 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -739,9 +739,7 @@ struct table_info;
typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen,
uint32_t *val);
-int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
- uint32_t *val);
-int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
void *paddr, uint32_t *val);
int ipfw_init_tables(struct ip_fw_chain *ch, int first);
int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables);
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index 7f199e7..64dba6f 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1821,6 +1821,8 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
break;
case O_IP_SRC_LOOKUP:
+ if (cmdlen > F_INSN_SIZE(ipfw_insn_u32))
+ goto bad_size;
case O_IP_DST_LOOKUP:
if (cmd->arg1 >= V_fw_tables_max) {
printf("ipfw: invalid table number %d\n",
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 902c9b6..c932e7e 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -1606,30 +1606,13 @@ ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
}
/*
- * Lookup an IP @addr in table @tbl.
- * Stores found value in @val.
- *
- * Returns 1 if @addr was found.
- */
-int
-ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
- uint32_t *val)
-{
- struct table_info *ti;
-
- ti = KIDX_TO_TI(ch, tbl);
-
- return (ti->lookup(ti, &addr, sizeof(in_addr_t), val));
-}
-
-/*
* Lookup an arbtrary key @paddr of legth @plen in table @tbl.
* Stores found value in @val.
*
* Returns 1 if key was found.
*/
int
-ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
void *paddr, uint32_t *val)
{
struct table_info *ti;
OpenPOWER on IntegriCloud