Page MenuHomeFreeBSD

D8877.diff
No OneTemporary

D8877.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
@@ -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

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)

Event Timeline