Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142245923
D8877.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
36 KB
Referenced Files
None
Subscribers
None
D8877.diff
View Options
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
@@ -235,12 +235,12 @@
struct mbuf *m0 = NULL;
struct nhop_object *nh = NULL;
struct route ro;
- struct sockaddr_in *dst;
+ struct sockaddr_in *dst, ndst;
const struct sockaddr *gw;
struct in_addr dest, odest, rtdest, osrc;
uint16_t ip_len, ip_off;
int error = 0;
- struct m_tag *fwd_tag = NULL;
+ struct ifnet *nifp = NULL;
struct mbuf *mcopy = NULL;
struct in_addr redest;
/*
@@ -373,23 +373,19 @@
/*
* Next hop forced by pfil(9) hook?
*/
- if ((m->m_flags & M_IP_NEXTHOP) &&
- ((fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL)) {
- /*
- * Now we will find route to forced destination.
- */
- 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 (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &ndst, &nifp)) {
+ dest.s_addr = ndst.sin_addr.s_addr;
}
/*
* Find route to destination.
*/
- if (ip_findroute(&nh, dest, m) != 0)
+ if (!nifp && ip_findroute(&nh, dest, m) != 0)
return (NULL); /* icmp unreach already sent */
+ if (!nifp)
+ nifp = nh->nh_ifp;
+
/*
* Avoid second route lookup by caching destination.
*/
@@ -401,7 +397,7 @@
if (!PFIL_HOOKED_OUT(V_inet_pfil_head))
goto passout;
- if (pfil_mbuf_out(V_inet_pfil_head, &m, nh->nh_ifp,
+ if (pfil_mbuf_out(V_inet_pfil_head, &m, nifp,
NULL) != PFIL_PASS)
goto drop;
@@ -414,11 +410,8 @@
/*
* Destination address changed?
*/
- 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 (odest.s_addr != dest.s_addr || IP_HAS_NEXTHOP(m)) {
+ struct ifnet *nnifp = NULL;
/*
* Is it now for a local address on this host?
*/
@@ -433,15 +426,13 @@
/*
* 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 (!ip_get_fwdtag(m, &ndst, &nnifp)) {
+ dest.s_addr = ndst.sin_addr.s_addr;
}
- if (dest.s_addr != rtdest.s_addr &&
+ if (!nnifp && dest.s_addr != rtdest.s_addr &&
ip_findroute(&nh, dest, m) != 0)
return (NULL); /* icmp unreach already sent */
+ nifp = nnifp ? nnifp : nh->nh_ifp;
}
passout:
@@ -456,7 +447,7 @@
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = dest;
- if (nh->nh_flags & NHF_GATEWAY) {
+ if (nh && nh->nh_ifp == nifp && nh->nh_flags & NHF_GATEWAY) {
gw = &nh->gw_sa;
ro.ro_flags |= RT_HAS_GW;
} else
@@ -465,13 +456,13 @@
/* Handle redirect case. */
redest.s_addr = 0;
if (V_ipsendredirects && osrc.s_addr == ip->ip_src.s_addr &&
- nh->nh_ifp == m->m_pkthdr.rcvif)
+ nifp == m->m_pkthdr.rcvif)
mcopy = ip_redir_alloc(m, nh, ip_len, &osrc, &redest);
/*
* Check if packet fits MTU or if hardware will fragment for us
*/
- if (ip_len <= nh->nh_mtu) {
+ if (ip_len <= nifp->if_mtu) {
/*
* Avoid confusing lower layers.
*/
@@ -479,8 +470,8 @@
/*
* Send off the packet via outgoing interface
*/
- IP_PROBE(send, NULL, NULL, ip, nh->nh_ifp, ip, NULL);
- error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m, gw, &ro);
+ IP_PROBE(send, NULL, NULL, ip, nifp, ip, NULL);
+ error = (*nifp->if_output)(nifp, m, gw, &ro);
} else {
/*
* Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery
@@ -488,15 +479,15 @@
if (ip_off & IP_DF) {
IPSTAT_INC(ips_cantfrag);
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
- 0, nh->nh_mtu);
+ 0, nifp->if_mtu);
goto consumed;
} else {
/*
* We have to fragment the packet
*/
m->m_pkthdr.csum_flags |= CSUM_IP;
- if (ip_fragment(ip, &m, nh->nh_mtu,
- nh->nh_ifp->if_hwassist) != 0)
+ if (ip_fragment(ip, &m, nifp->if_mtu,
+ nifp->if_hwassist) != 0)
goto drop;
KASSERT(m != NULL, ("null mbuf and no error"));
/*
@@ -512,9 +503,9 @@
m_clrprotoflags(m);
IP_PROBE(send, NULL, NULL,
- mtod(m, struct ip *), nh->nh_ifp,
+ mtod(m, struct ip *), nifp,
mtod(m, struct ip *), NULL);
- error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m,
+ error = (*nifp->if_output)(nifp, m,
gw, &ro);
if (error)
break;
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -105,10 +105,9 @@
extern int in_mcast_loop;
static inline int
-ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, int flags,
+ip_output_pfil(struct mbuf **mp, struct ifnet **ifp, int flags,
struct inpcb *inp, struct sockaddr_in *dst, int *fibnum, int *error)
{
- struct m_tag *fwd_tag = NULL;
struct mbuf *m;
struct in_addr odst;
struct ip *ip;
@@ -118,7 +117,7 @@
/* Run through list of hooks for output packets. */
odst.s_addr = ip->ip_dst.s_addr;
- switch (pfil_mbuf_out(V_inet_pfil_head, mp, ifp, inp)) {
+ switch (pfil_mbuf_out(V_inet_pfil_head, mp, *ifp, inp)) {
case PFIL_DROPPED:
*error = EACCES;
/* FALLTHROUGH */
@@ -187,12 +186,9 @@
return 1; /* Finished */
}
/* Or forward to some other address? */
- if ((m->m_flags & M_IP_NEXTHOP) &&
- ((fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL)) {
- bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in));
+ if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, dst, ifp)) {
m->m_flags |= M_SKIP_FIREWALL;
- m->m_flags &= ~M_IP_NEXTHOP;
- m_tag_delete(m, fwd_tag);
+ ip_flush_fwdtag(m);
return -1; /* Reloop for CHANGE of dst */
}
@@ -694,7 +690,8 @@
/* Jump over all PFIL processing if hooks are not active. */
if (PFIL_HOOKED_OUT(V_inet_pfil_head)) {
- switch (ip_output_pfil(&m, ifp, flags, inp, dst, &fibnum,
+ struct ifnet *oifp = ifp;
+ switch (ip_output_pfil(&m, &ifp, flags, inp, dst, &fibnum,
&error)) {
case 1: /* Finished */
goto done;
@@ -712,6 +709,18 @@
}
gw = (const struct sockaddr *)dst;
ip = mtod(m, struct ip *);
+ if (oifp != ifp) {
+ /*
+ * pf(4) decided on interface so
+ * emulate the previous way of
+ * if_output() with new ifp/dst
+ * combo and no route set.
+ */
+ IFP_TO_IA(ifp, ia);
+ mtu = ifp->if_mtu;
+ ro = NULL;
+ break;
+ }
goto again;
}
}
@@ -1549,3 +1558,92 @@
if_simloop(ifp, copym, AF_INET, 0);
}
}
+
+struct ip_fwdtag {
+ struct sockaddr_in dst;
+ u_short if_index;
+};
+
+int
+ip_set_fwdtag(struct mbuf *m, struct sockaddr_in *dst, struct ifnet *ifp)
+{
+ struct ip_fwdtag *fwd_info;
+ struct m_tag *fwd_tag;
+
+ KASSERT(dst != NULL, ("%s: !dst", __func__));
+ KASSERT(dst->sin_family == AF_INET, ("%s: !AF_INET", __func__));
+
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag != NULL) {
+ KASSERT(((struct ip_fwdtag *)(fwd_tag+1))->dst.sin_family ==
+ AF_INET, ("%s: !AF_INET", __func__));
+
+ m_tag_unlink(m, fwd_tag);
+ } else {
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*fwd_info),
+ M_NOWAIT);
+ if (fwd_tag == NULL) {
+ return (ENOBUFS);
+ }
+ }
+
+ fwd_info = (struct ip_fwdtag *)(fwd_tag+1);
+
+ bcopy(dst, &fwd_info->dst, sizeof(fwd_info->dst));
+ fwd_info->if_index = ifp ? ifp->if_index : 0;
+ m->m_flags |= M_IP_NEXTHOP;
+
+ if (in_localip(fwd_info->dst.sin_addr))
+ m->m_flags |= M_FASTFWD_OURS;
+ else
+ m->m_flags &= ~M_FASTFWD_OURS;
+
+ m_tag_prepend(m, fwd_tag);
+
+ return (0);
+}
+
+int
+ip_get_fwdtag(struct mbuf *m, struct sockaddr_in *dst, struct ifnet **ifp)
+{
+ struct ip_fwdtag *fwd_info;
+ struct m_tag *fwd_tag;
+
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag == NULL) {
+ return (ENOENT);
+ }
+
+ fwd_info = (struct ip_fwdtag *)(fwd_tag+1);
+
+ KASSERT(((struct sockaddr *)&fwd_info->dst)->sa_family == AF_INET,
+ ("%s: !AF_INET", __func__));
+
+ if (dst != NULL) {
+ bcopy(&fwd_info->dst, dst, sizeof(*dst));
+ }
+
+ if (ifp != NULL && fwd_info->if_index != 0) {
+ struct ifnet *nifp = ifnet_byindex(fwd_info->if_index);
+ if (nifp != NULL) {
+ *ifp = nifp;
+ }
+ }
+
+ return (0);
+}
+
+void
+ip_flush_fwdtag(struct mbuf *m)
+{
+ struct m_tag *fwd_tag;
+
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag != NULL) {
+ KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family ==
+ AF_INET, ("%s: !AF_INET", __func__));
+
+ m->m_flags &= ~(M_IP_NEXTHOP | M_FASTFWD_OURS);
+ m_tag_delete(m, fwd_tag);
+ }
+}
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -260,6 +260,11 @@
ipproto_input_t rip_input;
ipproto_ctlinput_t rip_ctlinput;
+#define IP_HAS_NEXTHOP(m) ((m)->m_flags & M_IP_NEXTHOP)
+int ip_set_fwdtag(struct mbuf *, struct sockaddr_in *, struct ifnet *);
+int ip_get_fwdtag(struct mbuf *, struct sockaddr_in *, struct ifnet **);
+void ip_flush_fwdtag(struct mbuf *);
+
VNET_DECLARE(struct pfil_head *, inet_pfil_head);
#define V_inet_pfil_head VNET(inet_pfil_head)
#define PFIL_INET_NAME "inet"
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -613,6 +613,7 @@
int off0;
int optlen = 0;
#ifdef INET
+ struct sockaddr_in next_hop;
int len;
uint8_t ipttl;
#endif
@@ -622,8 +623,8 @@
int rstreason = 0; /* For badport_bandlim accounting purposes */
int lookupflag;
uint8_t iptos;
- struct m_tag *fwd_tag = NULL;
#ifdef INET6
+ struct sockaddr_in6 next_hop6;
struct ip6_hdr *ip6 = NULL;
int isipv6;
#else
@@ -808,22 +809,6 @@
*/
drop_hdrlen = off0 + off;
- /*
- * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain.
- */
- if (
-#ifdef INET6
- (isipv6 && (m->m_flags & M_IP6_NEXTHOP))
-#ifdef INET
- || (!isipv6 && (m->m_flags & M_IP_NEXTHOP))
-#endif
-#endif
-#if defined(INET) && !defined(INET6)
- (m->m_flags & M_IP_NEXTHOP)
-#endif
- )
- fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
-
/*
* For initial SYN packets we don't need write lock on matching
* PCB, be it a listening one or a synchronized one. The packet
@@ -835,10 +820,8 @@
findpcb:
tp = NULL;
#ifdef INET6
- if (isipv6 && fwd_tag != NULL) {
- struct sockaddr_in6 *next_hop6;
-
- next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1);
+ if (isipv6 && IP6_HAS_NEXTHOP(m) &&
+ !ip6_get_fwdtag(m, &next_hop6, NULL)) {
/*
* Transparently forwarded. Pretend to be the destination.
* Already got one like this?
@@ -853,10 +836,12 @@
* any hardware-generated hash is ignored.
*/
inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src,
- th->th_sport, &next_hop6->sin6_addr,
- next_hop6->sin6_port ? ntohs(next_hop6->sin6_port) :
+ th->th_sport, &next_hop6.sin6_addr,
+ next_hop6.sin6_port ? ntohs(next_hop6.sin6_port) :
th->th_dport, lookupflag, m->m_pkthdr.rcvif);
}
+ /* Remove the tag from the packet. We don't need it anymore. */
+ ip_flush_fwdtag(m);
} else if (isipv6) {
inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src,
th->th_sport, &ip6->ip6_dst, th->th_dport, lookupflag,
@@ -867,10 +852,7 @@
else
#endif
#ifdef INET
- if (fwd_tag != NULL) {
- struct sockaddr_in *next_hop;
-
- next_hop = (struct sockaddr_in *)(fwd_tag+1);
+ if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) {
/*
* Transparently forwarded. Pretend to be the destination.
* already got one like this?
@@ -885,10 +867,12 @@
* any hardware-generated hash is ignored.
*/
inp = in_pcblookup(&V_tcbinfo, ip->ip_src,
- th->th_sport, next_hop->sin_addr,
- next_hop->sin_port ? ntohs(next_hop->sin_port) :
+ th->th_sport, next_hop.sin_addr,
+ next_hop.sin_port ? ntohs(next_hop.sin_port) :
th->th_dport, lookupflag, m->m_pkthdr.rcvif);
}
+ /* Remove the tag from the packet. We don't need it anymore. */
+ ip6_flush_fwdtag(m);
} else
inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src,
th->th_sport, ip->ip_dst, th->th_dport, lookupflag,
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -450,9 +450,8 @@
struct inpcb *inp;
uint16_t len, ip_len;
struct inpcbinfo *pcbinfo;
- struct sockaddr_in udp_in[2];
+ struct sockaddr_in udp_in[2], next_hop;
struct mbuf *m;
- struct m_tag *fwd_tag;
int cscov_partial, iphlen;
m = *mp;
@@ -578,12 +577,7 @@
*
* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain.
*/
- if ((m->m_flags & M_IP_NEXTHOP) &&
- (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
- struct sockaddr_in *next_hop;
-
- next_hop = (struct sockaddr_in *)(fwd_tag + 1);
-
+ if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) {
/*
* Transparently forwarded. Pretend to be the destination.
* Already got one like this?
@@ -597,14 +591,13 @@
* any hardware-generated hash is ignored.
*/
inp = in_pcblookup(pcbinfo, ip->ip_src,
- uh->uh_sport, next_hop->sin_addr,
- next_hop->sin_port ? htons(next_hop->sin_port) :
+ uh->uh_sport, next_hop.sin_addr,
+ next_hop.sin_port ? htons(next_hop.sin_port) :
uh->uh_dport, INPLOOKUP_WILDCARD |
INPLOOKUP_RLOCKPCB, ifp);
}
/* Remove the tag from the packet. We don't need it anymore. */
- m_tag_delete(m, fwd_tag);
- m->m_flags &= ~M_IP_NEXTHOP;
+ ip_flush_fwdtag(m);
} else
inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport,
ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD |
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
@@ -91,12 +91,11 @@
ip6_tryforward(struct mbuf *m)
{
struct sockaddr_in6 dst;
- struct nhop_object *nh;
- struct m_tag *fwd_tag;
+ struct nhop_object *nh = NULL;
struct ip6_hdr *ip6;
- struct ifnet *rcvif;
+ struct ifnet *rcvif, *nifp = NULL;
uint32_t plen;
- int error;
+ int error, mtu = 0;
/*
* Fallback conditions to ip6_input for slow path processing.
@@ -171,23 +170,12 @@
* that new destination or next hop is our local address.
* So, we can just go back to ip6_input.
* XXX: should we decrement ip6_hlim in such case?
- *
- * Also it can forward packet to another destination, e.g.
- * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf.
*/
if (m->m_flags & M_FASTFWD_OURS)
return (m);
ip6 = mtod(m, struct ip6_hdr *);
- if ((m->m_flags & M_IP6_NEXTHOP) &&
- (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
- /*
- * Now we will find route to forwarded by pfil destination.
- */
- bcopy((fwd_tag + 1), &dst, sizeof(dst));
- m->m_flags &= ~M_IP6_NEXTHOP;
- m_tag_delete(m, fwd_tag);
- } else {
+ if (!IP6_HAS_NEXTHOP(m) || ip6_get_fwdtag(m, &dst, &nifp)) {
/* Update dst since pfil could change it */
dst.sin6_addr = ip6->ip6_dst;
}
@@ -195,15 +183,18 @@
/*
* Find route to destination.
*/
- if (ip6_findroute(&nh, &dst, m) != 0) {
+ if (!nifp && ip6_findroute(&nh, &dst, m) != 0) {
m = NULL;
in6_ifstat_inc(rcvif, ifs6_in_noroute);
goto dropin;
}
+ if (!nifp)
+ nifp = nh->nh_ifp;
+ mtu = IN6_LINKMTU(nifp);
if (!PFIL_HOOKED_OUT(V_inet6_pfil_head)) {
- if (m->m_pkthdr.len > nh->nh_mtu) {
- in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig);
- icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu);
+ if (m->m_pkthdr.len > mtu) {
+ in6_ifstat_inc(nifp, ifs6_in_toobig);
+ icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, mtu);
m = NULL;
goto dropout;
}
@@ -213,17 +204,19 @@
/*
* Outgoing packet firewall processing.
*/
- if (pfil_mbuf_out(V_inet6_pfil_head, &m, nh->nh_ifp,
+ if (pfil_mbuf_out(V_inet6_pfil_head, &m, nifp,
NULL) != PFIL_PASS)
goto dropout;
/*
* We used slow path processing for packets with scoped addresses.
* So, scope checks aren't needed here.
+ *
+ * XXX this one is rather strange. Shouldn't we switch nh first?
*/
- if (m->m_pkthdr.len > nh->nh_mtu) {
- in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig);
- icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu);
+ if (m->m_pkthdr.len > mtu) {
+ in6_ifstat_inc(nifp, ifs6_in_toobig);
+ icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, mtu);
m = NULL;
goto dropout;
}
@@ -232,9 +225,6 @@
* If packet filter sets the M_FASTFWD_OURS flag, this means
* that new destination or next hop is our local address.
* So, we can just go back to ip6_input.
- *
- * Also it can forward packet to another destination, e.g.
- * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf.
*/
if (m->m_flags & M_FASTFWD_OURS) {
/*
@@ -247,26 +237,21 @@
* Again. A packet filter could change the destination address.
*/
ip6 = mtod(m, struct ip6_hdr *);
- 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 ||
+ if (IP6_HAS_NEXTHOP(m) ||
!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
+ struct ifnet *nnifp = NULL;
+ if (ip6_get_fwdtag(m, &dst, &nnifp)) {
+ /* Update dst since pfil could change it */
dst.sin6_addr = ip6->ip6_dst;
+ }
/*
* Redo route lookup with new destination address
*/
- if (ip6_findroute(&nh, &dst, m) != 0) {
+ if (!nnifp && ip6_findroute(&nh, &dst, m) != 0) {
m = NULL;
goto dropout;
}
+ nifp = nnifp ? nnifp : nh->nh_ifp;
}
passout:
#ifdef IPSTEALTH
@@ -277,17 +262,16 @@
}
m_clrprotoflags(m); /* Avoid confusing lower layers. */
- IP_PROBE(send, NULL, NULL, ip6, nh->nh_ifp, NULL, ip6);
+ IP_PROBE(send, NULL, NULL, ip6, nifp, NULL, ip6);
- if (nh->nh_flags & NHF_GATEWAY)
+ if (nh && nh->nh_ifp == nifp && nh->nh_flags & NHF_GATEWAY)
dst.sin6_addr = nh->gw6_sa.sin6_addr;
- error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m,
- (struct sockaddr *)&dst, NULL);
+ error = (*nifp->if_output)(nifp, m, (struct sockaddr *)&dst, NULL);
if (error != 0) {
- in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard);
+ in6_ifstat_inc(nifp, ifs6_out_discard);
IP6STAT_INC(ip6s_cantforward);
} else {
- in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward);
+ in6_ifstat_inc(nifp, ifs6_out_forward);
IP6STAT_INC(ip6s_forward);
}
return (NULL);
@@ -295,7 +279,7 @@
in6_ifstat_inc(rcvif, ifs6_in_discard);
goto drop;
dropout:
- in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard);
+ in6_ifstat_inc(nifp, ifs6_out_discard);
drop:
if (m != NULL)
m_freem(m);
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
@@ -91,14 +91,14 @@
ip6_forward(struct mbuf *m, int srcrt)
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct sockaddr_in6 dst;
+ struct sockaddr_in6 dst, gw6;
struct nhop_object *nh = NULL;
int error, type = 0, code = 0;
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
+ struct ifnet *ifp = NULL, *nifp = NULL;
u_int32_t inzone, outzone;
struct in6_addr odst;
- struct m_tag *fwd_tag;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
/*
@@ -194,6 +194,9 @@
goto bad;
}
+ ifp = nh->nh_ifp;
+
+routed:
if (nh->nh_flags & (NHF_BLACKHOLE | NHF_REJECT)) {
IP6STAT_INC(ip6s_cantforward);
if (mcopy != NULL) {
@@ -214,12 +217,12 @@
* address).
* [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1]
*/
- outzone = in6_get_unicast_scopeid(&ip6->ip6_src, nh->nh_ifp);
+ outzone = in6_get_unicast_scopeid(&ip6->ip6_src, ifp);
inzone = in6_get_unicast_scopeid(&ip6->ip6_src, m->m_pkthdr.rcvif);
if (inzone != outzone) {
IP6STAT_INC(ip6s_cantforward);
IP6STAT_INC(ip6s_badscope);
- in6_ifstat_inc(nh->nh_ifp, ifs6_in_discard);
+ in6_ifstat_inc(ifp, ifs6_in_discard);
if (V_ip6_log_cannot_forward && ip6_log_ratelimit()) {
log(LOG_DEBUG,
@@ -228,7 +231,7 @@
ip6_sprintf(ip6bufs, &ip6->ip6_src),
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
ip6->ip6_nxt,
- if_name(m->m_pkthdr.rcvif), if_name(nh->nh_ifp));
+ if_name(m->m_pkthdr.rcvif), if_name(ifp));
}
if (mcopy)
icmp6_error(mcopy, ICMP6_DST_UNREACH,
@@ -244,7 +247,7 @@
* packet to a different zone by (e.g.) a default route.
*/
inzone = in6_get_unicast_scopeid(&ip6->ip6_dst, m->m_pkthdr.rcvif);
- outzone = in6_get_unicast_scopeid(&ip6->ip6_dst, nh->nh_ifp);
+ outzone = in6_get_unicast_scopeid(&ip6->ip6_dst, ifp);
if (inzone != outzone) {
IP6STAT_INC(ip6s_cantforward);
@@ -252,7 +255,7 @@
goto bad;
}
- if (nh->nh_flags & NHF_GATEWAY) {
+ if (nh && nh->nh_flags & NHF_GATEWAY) {
/* Store gateway address in deembedded form */
dst.sin6_addr = nh->gw6_sa.sin6_addr;
dst.sin6_scope_id = ntohs(in6_getscope(&dst.sin6_addr));
@@ -268,7 +271,7 @@
* Also, don't send redirect if forwarding using a route
* modified by a redirect.
*/
- if (V_ip6_sendredirects && nh->nh_ifp == m->m_pkthdr.rcvif && !srcrt &&
+ if (V_ip6_sendredirects && nh && nh->nh_ifp == m->m_pkthdr.rcvif && !srcrt &&
(nh->nh_flags & NHF_REDIRECT) == 0)
type = ND_REDIRECT;
@@ -280,7 +283,7 @@
* link identifiers, we can do this stuff after making a copy for
* returning an error.
*/
- if ((nh->nh_ifp->if_flags & IFF_LOOPBACK) != 0) {
+ if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
/*
* See corresponding comments in ip6_output.
* XXX: but is it possible that ip6_forward() sends a packet
@@ -301,14 +304,14 @@
ip6_sprintf(ip6bufs, &ip6->ip6_src),
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
- if_name(nh->nh_ifp));
+ if_name(ifp));
}
/* we can just use rcvif in forwarding. */
origifp = m->m_pkthdr.rcvif;
}
else
- origifp = nh->nh_ifp;
+ origifp = ifp;
/*
* clear embedded scope identifiers if necessary.
* in6_clearscope will touch the addresses only when necessary.
@@ -322,7 +325,7 @@
odst = ip6->ip6_dst;
/* Run through list of hooks for forwarded packets. */
- if (pfil_mbuf_fwd(V_inet6_pfil_head, &m, nh->nh_ifp,
+ if (pfil_mbuf_fwd(V_inet6_pfil_head, &m, ifp,
NULL) != PFIL_PASS)
goto freecopy;
ip6 = mtod(m, struct ip6_hdr *);
@@ -334,7 +337,8 @@
if (in6_localip(&ip6->ip6_dst))
m->m_flags |= M_FASTFWD_OURS;
else {
- NH_FREE(nh);
+ if (nh)
+ NH_FREE(nh);
/* Update address and scopeid. Assume scope is embedded */
dst.sin6_scope_id = ntohs(in6_getscope(&ip6->ip6_dst));
@@ -361,30 +365,31 @@
goto out;
}
/* Or forward to some other address? */
- if ((m->m_flags & M_IP6_NEXTHOP) &&
- (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
- struct sockaddr_in6 *gw6 = (struct sockaddr_in6 *)(fwd_tag + 1);
-
+ if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &gw6, &nifp)) {
/* Update address and scopeid. Assume scope is embedded */
- dst.sin6_scope_id = ntohs(in6_getscope(&gw6->sin6_addr));
- dst.sin6_addr = gw6->sin6_addr;
+ dst.sin6_scope_id = ntohs(in6_getscope(&gw6.sin6_addr));
+ dst.sin6_addr = gw6.sin6_addr;
in6_clearscope(&dst.sin6_addr);
m->m_flags |= M_SKIP_FIREWALL;
- m->m_flags &= ~M_IP6_NEXTHOP;
- m_tag_delete(m, fwd_tag);
- NH_FREE(nh);
- goto again;
+ ip6_flush_fwdtag(m);
+ if (nh)
+ NH_FREE(nh);
+ if (!nifp)
+ goto again;
+ ifp = nifp;
+ goto routed;
}
pass:
+
/* See if the size was changed by the packet filter. */
/* TODO: change to nh->nh_mtu */
- if (m->m_pkthdr.len > IN6_LINKMTU(nh->nh_ifp)) {
- in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig);
+ if (m->m_pkthdr.len > IN6_LINKMTU(ifp)) {
+ in6_ifstat_inc(ifp, ifs6_in_toobig);
if (mcopy)
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,
- IN6_LINKMTU(nh->nh_ifp));
+ IN6_LINKMTU(ifp));
goto bad;
}
@@ -393,13 +398,13 @@
in6_set_unicast_scopeid(&dst.sin6_addr, dst.sin6_scope_id);
dst.sin6_scope_id = 0;
}
- error = nd6_output_ifp(nh->nh_ifp, origifp, m, &dst, NULL);
+ error = nd6_output_ifp(ifp, origifp, m, &dst, NULL);
if (error) {
- in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard);
+ in6_ifstat_inc(ifp, ifs6_out_discard);
IP6STAT_INC(ip6s_cantforward);
} else {
IP6STAT_INC(ip6s_forward);
- in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward);
+ in6_ifstat_inc(ifp, ifs6_out_forward);
if (type)
IP6STAT_INC(ip6s_redirectsent);
else {
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -406,6 +406,7 @@
{
struct ip6_hdr *ip6;
struct ifnet *ifp, *origifp;
+ struct ifnet *nifp = NULL;
struct mbuf *m = m0;
struct mbuf *mprev;
struct route_in6 *ro_pmtu;
@@ -427,7 +428,7 @@
int sw_csum, tso;
int needfiblookup;
uint32_t fibnum;
- struct m_tag *fwd_tag = NULL;
+ int has_fwd_tag = 0;
uint32_t id;
uint32_t optvalid;
@@ -679,6 +680,7 @@
*/
nh = NULL;
ifp = NULL;
+ origifp = NULL;
mtu = 0;
if (ro != NULL) {
if (ro->ro_nh != NULL && inp != NULL) {
@@ -686,13 +688,13 @@
NH_VALIDATE((struct route *)ro, &inp->inp_rt_cookie,
fibnum);
}
- if (ro->ro_nh != NULL && fwd_tag == NULL &&
+ if (ro->ro_nh != NULL && !has_fwd_tag &&
(!NH_IS_VALID(ro->ro_nh) ||
ro->ro_dst.sin6_family != AF_INET6 ||
!IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)))
RO_INVALIDATE_CACHE(ro);
- if (ro->ro_nh != NULL && fwd_tag == NULL &&
+ if (ro->ro_nh != NULL && !has_fwd_tag &&
ro->ro_dst.sin6_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) {
/* Nexthop is valid and contains valid ifp */
@@ -701,7 +703,7 @@
if (ro->ro_lle)
LLE_FREE(ro->ro_lle); /* zeros ro_lle */
ro->ro_lle = NULL;
- if (fwd_tag == NULL) {
+ if (!has_fwd_tag) {
bzero(&dst_sa, sizeof(dst_sa));
dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_len = sizeof(dst_sa);
@@ -720,6 +722,10 @@
* Can be the case when dst is multicast, link-local or
* interface is explicitly specificed by the caller.
*/
+ if (ifp == NULL) {
+ error = EHOSTUNREACH;
+ goto bad;
+ }
}
if (nh == NULL) {
/*
@@ -732,6 +738,7 @@
} else {
ifp = nh->nh_ifp;
origifp = nh->nh_aifp;
+ mtu = ifp->if_mtu;
ia = (struct in6_ifaddr *)(nh->nh_ifa);
counter_u64_add(nh->nh_pksent, 1);
}
@@ -740,7 +747,7 @@
struct in6_addr kdst;
uint32_t scopeid;
- if (fwd_tag == NULL) {
+ if (!has_fwd_tag) {
bzero(&dst_sa, sizeof(dst_sa));
dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_len = sizeof(dst_sa);
@@ -786,7 +793,7 @@
ia = ifatoia6(nh->nh_ifa);
if (nh->nh_flags & NHF_GATEWAY)
dst->sin6_addr = nh->gw6_sa.sin6_addr;
- else if (fwd_tag != NULL)
+ else if (has_fwd_tag)
dst->sin6_addr = dst_sa.sin6_addr;
nonh6lookup:
;
@@ -1086,17 +1093,28 @@
goto done;
}
/* Or forward to some other address? */
- if ((m->m_flags & M_IP6_NEXTHOP) &&
- (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
+ if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &dst_sa, &nifp)) {
if (ro != NULL)
dst = (struct sockaddr_in6 *)&ro->ro_dst;
else
dst = &sin6;
- bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6));
m->m_flags |= M_SKIP_FIREWALL;
- m->m_flags &= ~M_IP6_NEXTHOP;
- m_tag_delete(m, fwd_tag);
- goto again;
+ ip6_flush_fwdtag(m);
+ has_fwd_tag = 1;
+ if (!nifp)
+ goto again;
+ /*
+ * pf(4) decided on interface so
+ * emulate the previous way of
+ * if_output() with new ifp/dst
+ * combo and no route set.
+ */
+ ifp = nifp;
+ ia = in6_ifawithifp(ifp, &ip6->ip6_src);
+ mtu = ifp->if_mtu;
+ dst = &sin6;
+ *dst = dst_sa; /* XXX */
+ ro = NULL;
}
passout:
@@ -3361,3 +3379,109 @@
return len;
#undef elen
}
+
+struct ip6_fwdtag {
+ struct sockaddr_in6 dst;
+ u_short if_index;
+};
+
+int
+ip6_set_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, struct ifnet *ifp)
+{
+ struct ip6_fwdtag *fwd_info;
+ struct m_tag *fwd_tag;
+ int error;
+
+ KASSERT(dst != NULL, ("%s: !dst", __func__));
+ KASSERT(dst->sin6_family == AF_INET6, ("%s: !AF_INET6", __func__));
+
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag != NULL) {
+ KASSERT(((struct ip6_fwdtag *)(fwd_tag+1))->dst.sin6_family ==
+ AF_INET6, ("%s: !AF_INET6", __func__));
+
+ m_tag_unlink(m, fwd_tag);
+ } else {
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*dst),
+ M_NOWAIT);
+ if (fwd_tag == NULL) {
+ return (ENOBUFS);
+ }
+ }
+
+ fwd_info = (struct ip6_fwdtag *)(fwd_tag+1);
+
+ fwd_info->if_index = ifp ? ifp->if_index : 0;
+
+ bcopy(dst, &fwd_info->dst, sizeof(fwd_info->dst));
+ if (fwd_info->if_index) {
+ /* force scope for pf(4) giving us an interface */
+ fwd_info->dst.sin6_scope_id = fwd_info->if_index;
+ }
+
+ /*
+ * If nh6 address is link-local we should convert
+ * it to kernel internal form before doing any
+ * comparisons.
+ */
+ error = sa6_embedscope(&fwd_info->dst, V_ip6_use_defzone);
+ if (error != 0) {
+ m_tag_free(fwd_tag);
+ return (error);
+ }
+
+ if (in6_localip(&fwd_info->dst.sin6_addr))
+ m->m_flags |= M_FASTFWD_OURS;
+ else
+ m->m_flags &= ~M_FASTFWD_OURS;
+
+ m->m_flags |= M_IP6_NEXTHOP;
+ m_tag_prepend(m, fwd_tag);
+
+ return (0);
+}
+
+int
+ip6_get_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, struct ifnet **ifp)
+{
+ struct ip6_fwdtag *fwd_info;
+ struct m_tag *fwd_tag;
+
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag == NULL) {
+ return (ENOENT);
+ }
+
+ fwd_info = (struct ip6_fwdtag *)(fwd_tag+1);
+
+ KASSERT(((struct sockaddr *)&fwd_info->dst)->sa_family == AF_INET6,
+ ("%s: !AF_INET6", __func__));
+
+ if (dst != NULL) {
+ bcopy((fwd_tag+1), dst, sizeof(*dst));
+ }
+
+ if (ifp != NULL && fwd_info->if_index != 0) {
+ struct ifnet *nifp = ifnet_byindex(fwd_info->if_index);
+ if (nifp != NULL) {
+ *ifp = nifp;
+ }
+ }
+
+ return (0);
+}
+
+void
+ip6_flush_fwdtag(struct mbuf *m)
+{
+ struct m_tag *fwd_tag;
+
+ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag != NULL) {
+ KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family ==
+ AF_INET6, ("%s: !AF_INET6", __func__));
+
+ m->m_flags &= ~(M_IP6_NEXTHOP | M_FASTFWD_OURS);
+ m_tag_delete(m, fwd_tag);
+ }
+}
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -409,6 +409,11 @@
int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int,
uint32_t);
+#define IP6_HAS_NEXTHOP(m) ((m)->m_flags & M_IP6_NEXTHOP)
+int ip6_set_fwdtag(struct mbuf *, struct sockaddr_in6 *, struct ifnet *);
+int ip6_get_fwdtag(struct mbuf *, struct sockaddr_in6 *, struct ifnet **);
+void ip6_flush_fwdtag(struct mbuf *);
+
int route6_input(struct mbuf **, int *, int);
void frag6_init(void);
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -357,8 +357,7 @@
int off = *offp;
int cscov_partial;
int plen, ulen;
- struct sockaddr_in6 fromsa[2];
- struct m_tag *fwd_tag;
+ struct sockaddr_in6 fromsa[2], next_hop6;
uint16_t uh_sum;
uint8_t nxt;
@@ -458,12 +457,7 @@
/*
* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain.
*/
- if ((m->m_flags & M_IP6_NEXTHOP) &&
- (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
- struct sockaddr_in6 *next_hop6;
-
- next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1);
-
+ if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &next_hop6, NULL)) {
/*
* Transparently forwarded. Pretend to be the destination.
* Already got one like this?
@@ -478,14 +472,13 @@
* any hardware-generated hash is ignored.
*/
inp = in6_pcblookup(pcbinfo, &ip6->ip6_src,
- uh->uh_sport, &next_hop6->sin6_addr,
- next_hop6->sin6_port ? htons(next_hop6->sin6_port) :
+ uh->uh_sport, &next_hop6.sin6_addr,
+ next_hop6.sin6_port ? htons(next_hop6.sin6_port) :
uh->uh_dport, INPLOOKUP_WILDCARD |
INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif);
}
/* Remove the tag from the packet. We don't need it anymore. */
- m_tag_delete(m, fwd_tag);
- m->m_flags &= ~M_IP6_NEXTHOP;
+ ip6_flush_fwdtag(m);
} else
inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src,
uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
@@ -127,6 +127,27 @@
int ipfw;
args.flags = (flags & PFIL_IN) ? IPFW_ARGS_IN : IPFW_ARGS_OUT;
+
+ /* restore the correct forwarding interface */
+ if (args.flags & IPFW_ARGS_OUT) switch (mtod(*m0, struct ip *)->ip_v) {
+#ifdef INET6
+ case IPV6_VERSION >> 4:
+ if (IP6_HAS_NEXTHOP(*m0)) {
+ ip6_get_fwdtag(*m0, NULL, &ifp);
+ }
+ break;
+#endif
+#ifdef INET
+ case IPVERSION:
+ if (IP_HAS_NEXTHOP(*m0)) {
+ ip_get_fwdtag(*m0, NULL, &ifp);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
again:
/*
* extract and remove the tag if present. If we are left
@@ -163,8 +184,6 @@
ret = PFIL_DROPPED;
#else
{
- void *psa;
- size_t len;
#ifdef INET
if (args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR)) {
MPASS((args.flags & (IPFW_ARGS_NH4 |
@@ -172,12 +191,11 @@
IPFW_ARGS_NH4PTR));
MPASS((args.flags & (IPFW_ARGS_NH6 |
IPFW_ARGS_NH6PTR)) == 0);
- len = sizeof(struct sockaddr_in);
- psa = (args.flags & IPFW_ARGS_NH4) ?
- &args.hopstore : args.next_hop;
- if (in_localip(satosin(psa)->sin_addr))
- (*m0)->m_flags |= M_FASTFWD_OURS;
- (*m0)->m_flags |= M_IP_NEXTHOP;
+ if (ip_set_fwdtag(*m0, (args.flags & IPFW_ARGS_NH4) ?
+ &args.hopstore : args.next_hop, NULL)) {
+ ret = PFIL_DROPPED;
+ break;
+ }
}
#endif /* INET */
#ifdef INET6
@@ -187,38 +205,9 @@
IPFW_ARGS_NH6PTR));
MPASS((args.flags & (IPFW_ARGS_NH4 |
IPFW_ARGS_NH4PTR)) == 0);
- len = sizeof(struct sockaddr_in6);
- psa = args.next_hop6;
- (*m0)->m_flags |= M_IP6_NEXTHOP;
- }
-#endif /* INET6 */
- /*
- * Incoming packets should not be tagged so we do not
- * m_tag_find. Outgoing packets may be tagged, so we
- * reuse the tag if present.
- */
- tag = (flags & PFIL_IN) ? NULL :
- m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
- if (tag != NULL) {
- m_tag_unlink(*m0, tag);
- } else {
- tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
- M_NOWAIT);
- if (tag == NULL) {
- ret = PFIL_DROPPED;
- break;
- }
- }
- if ((args.flags & IPFW_ARGS_NH6) == 0)
- bcopy(psa, tag + 1, len);
- m_tag_prepend(*m0, tag);
- ret = PFIL_PASS;
-#ifdef INET6
- /* IPv6 next hop needs additional handling */
- if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
struct sockaddr_in6 *sa6;
- sa6 = satosin6(tag + 1);
+ sa6 = satosin6(args.next_hop);
if (args.flags & IPFW_ARGS_NH6) {
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(*sa6);
@@ -227,17 +216,10 @@
sa6->sin6_scope_id =
args.hopstore6.sin6_scope_id;
}
- /*
- * 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) {
+ if (ip6_set_fwdtag(*m0, sa6, NULL)) {
ret = PFIL_DROPPED;
break;
}
- if (in6_localip(&sa6->sin6_addr))
- (*m0)->m_flags |= M_FASTFWD_OURS;
}
#endif /* INET6 */
}
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -495,6 +495,20 @@
SYSCTL_ULONG(_net_pf, OID_AUTO, request_maxcount, CTLFLAG_RWTUN,
&pf_ioctl_maxcount, 0, "Maximum number of tables, addresses, ... in a single ioctl() call");
+VNET_DEFINE_STATIC(int, pf_share_forward) = 0;
+VNET_DEFINE_STATIC(int, pf_share_forward6) = 0;
+
+#define V_pf_share_forward VNET(pf_share_forward)
+#define V_pf_share_forward6 VNET(pf_share_forward6)
+
+SYSCTL_INT(_net_pf, OID_AUTO, share_forward,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(pf_share_forward), 0,
+ "If set pf(4) will defer IPv4 forwarding to the network stack.");
+
+SYSCTL_INT(_net_pf, OID_AUTO, share_forward6,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(pf_share_forward6), 0,
+ "If set pf(4) will defer IPv6 forwarding to the network stack.");
+
VNET_DEFINE(void *, pf_swi_cookie);
VNET_DEFINE(struct intr_event *, pf_swi_ie);
@@ -7355,6 +7369,18 @@
if (ifp == NULL)
goto bad;
+ if (V_pf_share_forward) {
+ if (!IP_HAS_NEXTHOP(m0)) {
+ if (ip_set_fwdtag(m0, &dst, ifp))
+ goto bad;
+
+ if (r_rt == PF_DUPTO)
+ ip_forward(m0, 1);
+ }
+
+ return;
+ }
+
if (pd->dir == PF_IN) {
if (pf_test(PF_OUT, PFIL_FWD, ifp, &m0, inp, &pd->act) != PF_PASS)
goto bad;
@@ -7605,6 +7631,18 @@
if (ifp == NULL)
goto bad;
+ if (V_pf_share_forward6) {
+ if (!IP6_HAS_NEXTHOP(m0)) {
+ if (ip6_set_fwdtag(m0, &dst, ifp))
+ goto bad;
+
+ if (r_rt == PF_DUPTO)
+ ip6_forward(m0, 1);
+ }
+
+ return;
+ }
+
if (pd->dir == PF_IN) {
if (pf_test6(PF_OUT, PFIL_FWD, ifp, &m0, inp, &pd->act) != PF_PASS)
goto bad;
@@ -8011,6 +8049,10 @@
if (!V_pf_status.running)
return (PF_PASS);
+ if (dir == PF_OUT && IP_HAS_NEXTHOP(m) && V_pf_share_forward) {
+ ip_get_fwdtag(m, NULL, &ifp);
+ }
+
PF_RULES_RLOCK();
kif = (struct pfi_kkif *)ifp->if_pf_kif;
@@ -8587,6 +8629,10 @@
if (!V_pf_status.running)
return (PF_PASS);
+ if (dir == PF_OUT && IP6_HAS_NEXTHOP(m) && V_pf_share_forward6) {
+ ip6_get_fwdtag(m, NULL, &ifp);
+ }
+
PF_RULES_RLOCK();
kif = (struct pfi_kkif *)ifp->if_pf_kif;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 18, 6:29 PM (9 h, 45 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27714933
Default Alt Text
D8877.diff (36 KB)
Attached To
Mode
D8877: pf|ipfw|netinet6?: shared IP forwarding
Attached
Detach File
Event Timeline
Log In to Comment