summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2015-03-13 09:03:25 +0000
committerae <ae@FreeBSD.org>2015-03-13 09:03:25 +0000
commit8ee4f19c0595d4c5a1b5edfbe92740fb80a562e6 (patch)
tree144121f14d0d8db127f25dbdb377dd06ecdda3b4 /sys
parentb74bc609255aad13afd0fe21e53fd6ba0f470bb3 (diff)
downloadFreeBSD-src-8ee4f19c0595d4c5a1b5edfbe92740fb80a562e6.zip
FreeBSD-src-8ee4f19c0595d4c5a1b5edfbe92740fb80a562e6.tar.gz
Fix `ipfw fwd tablearg'. Use dedicated field nh4 in struct table_value
to obtain IPv4 next hop address in tablearg case. Add `fwd tablearg' support for IPv6. ipfw(8) uses INADDR_ANY as next hop address in O_FORWARD_IP opcode for specifying tablearg case. For IPv6 we still use this opcode, but when packet identified as IPv6 packet, we obtain next hop address from dedicated field nh6 in struct table_value. Replace hopstore field in struct ip_fw_args with anonymous union and add hopstore6 field. Use this field to copy tablearg value for IPv6. Replace spare1 field in struct table_value with zoneid. Use it to keep scope zone id for link-local IPv6 addresses. Since spare1 was used internally, replace spare0 array with two variables spare0 and spare1. Use getaddrinfo(3)/getnameinfo(3) functions for parsing and formatting IPv6 addresses in table_value. Use zoneid field in struct table_value to store sin6_scope_id value. Since the kernel still uses embedded scope zone id to represent link-local addresses, convert next_hop6 address into this form before return from pfil processing. This also fixes in6_localip() check for link-local addresses. Differential Revision: https://reviews.freebsd.org/D2015 Obtained from: Yandex LLC Sponsored by: Yandex LLC
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/ip_fw.h7
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c45
-rw-r--r--sys/netpfil/ipfw/ip_fw_pfil.c17
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h10
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_value.c3
5 files changed, 69 insertions, 13 deletions
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index ab9ec63..9c53793 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -721,7 +721,7 @@ struct _ipfw_dyn_rule {
#define IPFW_VTYPE_TAG 0x00000020 /* tag/untag */
#define IPFW_VTYPE_DIVERT 0x00000040 /* divert/tee */
#define IPFW_VTYPE_NETGRAPH 0x00000080 /* netgraph/ngtee */
-#define IPFW_VTYPE_LIMIT 0x00000100 /* IPv6 nexthop */
+#define IPFW_VTYPE_LIMIT 0x00000100 /* limit */
#define IPFW_VTYPE_NH4 0x00000200 /* IPv4 nexthop */
#define IPFW_VTYPE_NH6 0x00000400 /* IPv6 nexthop */
@@ -817,10 +817,11 @@ typedef struct _ipfw_table_value {
uint32_t nat; /* O_NAT */
uint32_t nh4;
uint8_t dscp;
- uint8_t spare0[3];
+ uint8_t spare0;
+ uint16_t spare1;
struct in6_addr nh6;
uint32_t limit; /* O_LIMIT */
- uint32_t spare1;
+ uint32_t zoneid; /* scope zone id for nh6 */
uint64_t reserved;
} ipfw_table_value;
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 9c7a3bd..a30f6bf 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -2387,13 +2387,48 @@ do { \
if (q == NULL || q->rule != f ||
dyn_dir == MATCH_FORWARD) {
struct sockaddr_in *sa;
+
sa = &(((ipfw_insn_sa *)cmd)->sa);
if (sa->sin_addr.s_addr == INADDR_ANY) {
- bcopy(sa, &args->hopstore,
- sizeof(*sa));
- args->hopstore.sin_addr.s_addr =
- htonl(tablearg);
- args->next_hop = &args->hopstore;
+#ifdef INET6
+ /*
+ * We use O_FORWARD_IP opcode for
+ * fwd rule with tablearg, but tables
+ * now support IPv6 addresses. And
+ * when we are inspecting IPv6 packet,
+ * we can use nh6 field from
+ * table_value as next_hop6 address.
+ */
+ if (is_ipv6) {
+ struct sockaddr_in6 *sa6;
+
+ sa6 = args->next_hop6 =
+ &args->hopstore6;
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_len = sizeof(*sa6);
+ sa6->sin6_addr = TARG_VAL(
+ chain, tablearg, nh6);
+ /*
+ * Set sin6_scope_id only for
+ * link-local unicast addresses.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(
+ &sa6->sin6_addr))
+ sa6->sin6_scope_id =
+ TARG_VAL(chain,
+ tablearg,
+ zoneid);
+ } else
+#endif
+ {
+ sa = args->next_hop =
+ &args->hopstore;
+ sa->sin_family = AF_INET;
+ sa->sin_len = sizeof(*sa);
+ sa->sin_addr.s_addr = htonl(
+ TARG_VAL(chain, tablearg,
+ nh4));
+ }
} else {
args->next_hop = sa;
}
diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
index b53a8ce..61f182d 100644
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/scope6_var.h>
#endif
#include <netgraph/ng_ipfw.h>
@@ -197,8 +198,20 @@ again:
}
#ifdef INET6
if (args.next_hop6 != NULL) {
- bcopy(args.next_hop6, (fwd_tag+1), len);
- if (in6_localip(&args.next_hop6->sin6_addr))
+ struct sockaddr_in6 *sa6;
+
+ sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
+ bcopy(args.next_hop6, sa6, len);
+ /*
+ * If nh6 address is link-local we should convert
+ * it to kernel internal form before doing any
+ * comparisons.
+ */
+ if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
+ ret = EACCES;
+ break;
+ }
+ if (in6_localip(&sa6->sin6_addr))
(*m0)->m_flags |= M_FASTFWD_OURS;
(*m0)->m_flags |= M_IP6_NEXTHOP;
}
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index 3f46ddd..bb5b3ba 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -102,7 +102,10 @@ struct ip_fw_args {
struct inpcb *inp;
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
- struct sockaddr_in hopstore; /* store here if cannot use a pointer */
+ union { /* store here if cannot use a pointer */
+ struct sockaddr_in hopstore;
+ struct sockaddr_in6 hopstore6;
+ };
};
MALLOC_DECLARE(M_IPFW);
@@ -294,11 +297,12 @@ struct table_value {
uint32_t nat; /* O_NAT */
uint32_t nh4;
uint8_t dscp;
- uint8_t spare0[3];
+ uint8_t spare0;
+ uint16_t spare1;
/* -- 32 bytes -- */
struct in6_addr nh6;
uint32_t limit; /* O_LIMIT */
- uint32_t spare1;
+ uint32_t zoneid; /* scope zone id for nh6 */
uint64_t refcnt; /* Number of references */
};
diff --git a/sys/netpfil/ipfw/ip_fw_table_value.c b/sys/netpfil/ipfw/ip_fw_table_value.c
index 9d68901..c798ac1 100644
--- a/sys/netpfil/ipfw/ip_fw_table_value.c
+++ b/sys/netpfil/ipfw/ip_fw_table_value.c
@@ -117,6 +117,7 @@ mask_table_value(struct table_value *src, struct table_value *dst,
_MCPY(dscp, IPFW_VTYPE_DSCP);
_MCPY(nh4, IPFW_VTYPE_NH4);
_MCPY(nh6, IPFW_VTYPE_NH6);
+ _MCPY(zoneid, IPFW_VTYPE_NH6);
#undef _MCPY
}
@@ -666,6 +667,7 @@ ipfw_import_table_value_v1(ipfw_table_value *iv)
v.nh4 = iv->nh4;
v.nh6 = iv->nh6;
v.limit = iv->limit;
+ v.zoneid = iv->zoneid;
memcpy(iv, &v, sizeof(ipfw_table_value));
}
@@ -691,6 +693,7 @@ ipfw_export_table_value_v1(struct table_value *v, ipfw_table_value *piv)
iv.limit = v->limit;
iv.nh4 = v->nh4;
iv.nh6 = v->nh6;
+ iv.zoneid = v->zoneid;
memcpy(piv, &iv, sizeof(iv));
}
OpenPOWER on IntegriCloud