Page MenuHomeFreeBSD

D41479.diff
No OneTemporary

D41479.diff

diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c
--- a/sys/netinet/ip_fastfwd.c
+++ b/sys/netinet/ip_fastfwd.c
@@ -237,12 +237,13 @@
struct route ro;
struct sockaddr_in *dst;
const struct sockaddr *gw;
- struct in_addr dest, odest, rtdest, osrc;
+ struct in_addr dest, odest, osrc;
uint16_t ip_len, ip_off;
int error = 0;
struct m_tag *fwd_tag = NULL;
struct mbuf *mcopy = NULL;
struct in_addr redest;
+ bool rt_changed = false;
/*
* Are we active and forwarding packets?
*/
@@ -371,7 +372,9 @@
#endif
/*
- * Next hop forced by pfil(9) hook?
+ * After pfil_mbuf_in we use the changed destination no matter if it
+ * comes from IP headers (see right after pfil_mbuf_in) or from the
+ * PACKET_TAG_IPFORWARD tag.
*/
if ((m->m_flags & M_IP_NEXTHOP) &&
((fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL)) {
@@ -382,6 +385,7 @@
(fwd_tag + 1))->sin_addr.s_addr;
m_tag_delete(m, fwd_tag);
m->m_flags &= ~M_IP_NEXTHOP;
+ rt_changed = true;
}
/*
@@ -390,17 +394,13 @@
if (ip_findroute(&nh, dest, m) != 0)
return (NULL); /* icmp unreach already sent */
- /*
- * Avoid second route lookup by caching destination.
- */
- rtdest.s_addr = dest.s_addr;
-
/*
* Step 5: outgoing firewall packet processing
*/
if (!PFIL_HOOKED_OUT(V_inet_pfil_head))
goto passout;
+ odest.s_addr = ip->ip_dst.s_addr;
if (pfil_mbuf_out(V_inet_pfil_head, &m, nh->nh_ifp,
NULL) != PFIL_PASS)
goto drop;
@@ -409,18 +409,21 @@
M_ASSERTPKTHDR(m);
ip = mtod(m, struct ip *);
- dest.s_addr = ip->ip_dst.s_addr;
/*
- * Destination address changed?
+ * After pfil_mbuf_out we might keep the destination set by pfil_mbuf_in
+ * if it was set via the PACKET_TAG_IPFORWARD tag.
*/
if (m->m_flags & M_IP_NEXTHOP)
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
else
fwd_tag = NULL;
- if (odest.s_addr != dest.s_addr || fwd_tag != NULL) {
+
+ if (!rt_changed && odest.s_addr != ip->ip_dst.s_addr) {
+ dest.s_addr = ip->ip_dst.s_addr;
/*
* Is it now for a local address on this host?
+ * XXX Should we direct to local also by routing, not just NAT?
*/
if (m->m_flags & M_FASTFWD_OURS || in_localip(dest)) {
forwardlocal:
@@ -430,20 +433,23 @@
m->m_flags |= M_FASTFWD_OURS;
return (m);
}
- /*
- * Redo route lookup with new destination address
- */
- if (fwd_tag) {
- dest.s_addr = ((struct sockaddr_in *)
- (fwd_tag + 1))->sin_addr.s_addr;
- m_tag_delete(m, fwd_tag);
- m->m_flags &= ~M_IP_NEXTHOP;
- }
- if (dest.s_addr != rtdest.s_addr &&
- ip_findroute(&nh, dest, m) != 0)
- return (NULL); /* icmp unreach already sent */
+ rt_changed = true;
}
+ if (fwd_tag) {
+ dest.s_addr = ((struct sockaddr_in *)
+ (fwd_tag + 1))->sin_addr.s_addr;
+ m_tag_delete(m, fwd_tag);
+ m->m_flags &= ~M_IP_NEXTHOP;
+ rt_changed = true;
+ }
+
+ /*
+ * Redo route lookup with new destination address
+ */
+ if (rt_changed && ip_findroute(&nh, dest, m) != 0)
+ return (NULL); /* icmp unreach already sent */
+
passout:
/*
* Step 6: send off the packet
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -921,6 +921,7 @@
struct sockaddr_in *sin;
struct in_addr dest;
struct route ro;
+ struct m_tag *fwd_tag;
uint32_t flowid;
int error, type = 0, code = 0, mtu = 0;
@@ -942,11 +943,20 @@
bzero(&ro, sizeof(ro));
sin = (struct sockaddr_in *)&ro.ro_dst;
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(*sin);
- sin->sin_addr = ip->ip_dst;
+
+ if (m->m_flags & M_IP_NEXTHOP && ((fwd_tag = m_tag_find(m,
+ PACKET_TAG_IPFORWARD, NULL)) != NULL)) {
+ bcopy((fwd_tag + 1), sin, sizeof(struct sockaddr_in));
+ m->m_flags &= ~M_IP_NEXTHOP;
+ m_tag_delete(m, fwd_tag);
+ } else {
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_addr = ip->ip_dst;
+ }
+
flowid = m->m_pkthdr.flowid;
- ro.ro_nh = fib4_lookup(M_GETFIB(m), ip->ip_dst, 0, NHR_REF, flowid);
+ ro.ro_nh = fib4_lookup(M_GETFIB(m), sin->sin_addr, 0, NHR_REF, flowid);
if (ro.ro_nh != NULL) {
ia = ifatoia(ro.ro_nh->nh_ifa);
} else
diff --git a/sys/netinet6/ip6_fastfwd.c b/sys/netinet6/ip6_fastfwd.c
--- a/sys/netinet6/ip6_fastfwd.c
+++ b/sys/netinet6/ip6_fastfwd.c
@@ -90,13 +90,14 @@
struct mbuf*
ip6_tryforward(struct mbuf *m)
{
- struct sockaddr_in6 dst;
+ struct sockaddr_in6 dst, odst;
struct nhop_object *nh;
struct m_tag *fwd_tag;
struct ip6_hdr *ip6;
struct ifnet *rcvif;
uint32_t plen;
int error;
+ bool rt_changed = false;
/*
* Fallback conditions to ip6_input for slow path processing.
@@ -158,6 +159,11 @@
dst.sin6_len = sizeof(dst);
dst.sin6_addr = ip6->ip6_dst;
+ bzero(&odst, sizeof(odst));
+ odst.sin6_family = AF_INET6;
+ odst.sin6_len = sizeof(dst);
+ odst.sin6_addr = ip6->ip6_dst;
+
/*
* Incoming packet firewall processing.
*/
@@ -178,6 +184,10 @@
if (m->m_flags & M_FASTFWD_OURS)
return (m);
+ /*
+ * After pfil_mbuf_in we use the changed destination no matter if it
+ * comes from IP headers or from the PACKET_TAG_IPFORWARD tag.
+ */
ip6 = mtod(m, struct ip6_hdr *);
if ((m->m_flags & M_IP6_NEXTHOP) &&
(fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
@@ -187,6 +197,7 @@
bcopy((fwd_tag + 1), &dst, sizeof(dst));
m->m_flags &= ~M_IP6_NEXTHOP;
m_tag_delete(m, fwd_tag);
+ rt_changed = true;
} else {
/* Update dst since pfil could change it */
dst.sin6_addr = ip6->ip6_dst;
@@ -213,6 +224,7 @@
/*
* Outgoing packet firewall processing.
*/
+ odst.sin6_addr = ip6->ip6_dst;
if (pfil_mbuf_out(V_inet6_pfil_head, &m, nh->nh_ifp,
NULL) != PFIL_PASS)
goto dropout;
@@ -243,30 +255,34 @@
*/
return (m);
}
- /*
- * Again. A packet filter could change the destination address.
- */
+
ip6 = mtod(m, struct ip6_hdr *);
+
+ /*
+ * After pfil_mbuf_out we might keep the destination set by pfil_mbuf_in
+ * if it was set via the PACKET_TAG_IPFORWARD tag.
+ */
if (m->m_flags & M_IP6_NEXTHOP)
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
else
fwd_tag = NULL;
- if (fwd_tag != NULL ||
- !IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &ip6->ip6_dst)) {
- if (fwd_tag != NULL) {
- bcopy((fwd_tag + 1), &dst, sizeof(dst));
- m->m_flags &= ~M_IP6_NEXTHOP;
- m_tag_delete(m, fwd_tag);
- } else
- dst.sin6_addr = ip6->ip6_dst;
- /*
- * Redo route lookup with new destination address
- */
- if (ip6_findroute(&nh, &dst, m) != 0) {
- m = NULL;
- goto dropout;
- }
+ if (!rt_changed && !IN6_ARE_ADDR_EQUAL(
+ &odst.sin6_addr, &ip6->ip6_dst)) {
+ dst.sin6_addr = ip6->ip6_dst;
+ rt_changed = true;
+ }
+
+ if (fwd_tag != NULL) {
+ bcopy((fwd_tag + 1), &dst, sizeof(dst));
+ m->m_flags &= ~M_IP6_NEXTHOP;
+ m_tag_delete(m, fwd_tag);
+ rt_changed = true;
+ }
+
+ if (rt_changed && ip6_findroute(&nh, &dst, m) != 0) {
+ m = NULL;
+ goto dropout;
}
passout:
#ifdef IPSTEALTH
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -177,9 +177,17 @@
* 3) packet filters attaching PACKET_TAG_IPFORWARD would embed
* scope for the nexthop.
*/
- bzero(&dst, sizeof(struct sockaddr_in6));
- dst.sin6_family = AF_INET6;
- dst.sin6_addr = ip6->ip6_dst;
+ if (m->m_flags & M_IP6_NEXTHOP && ((fwd_tag = m_tag_find(m,
+ PACKET_TAG_IPFORWARD, NULL)) != NULL)) {
+ bcopy((fwd_tag + 1), &dst, sizeof(dst));
+ m->m_flags &= ~M_IP6_NEXTHOP;
+ m_tag_delete(m, fwd_tag);
+ } else {
+ bzero(&dst, sizeof(struct sockaddr_in6));
+ dst.sin6_family = AF_INET6;
+ dst.sin6_addr = ip6->ip6_dst;
+ }
+
dst.sin6_scope_id = in6_get_unicast_scopeid(&ip6->ip6_dst, m->m_pkthdr.rcvif);
again:
nh = fib6_lookup(M_GETFIB(m), &dst.sin6_addr, dst.sin6_scope_id,

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 12, 4:32 AM (9 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17112746
Default Alt Text
D41479.diff (7 KB)

Event Timeline