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;