mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
pf/ipfw/netinet[6]: IP forwarding rework, fixes IPv4 in pf(4)
Based on feedback by countless users, this removes the if_output calls in the pf code that escape pfil processing in IPv4 by going the long way. In our 11.1 iteration ip_tryforward() is easy to port and while we are at it we shall also tackle IPv6. :) Many thanks to Andrey V. Elsukov (ae@) for giving this direction and review. Also see: https://reviews.freebsd.org/D8877 pf: add ipv6 shared forwarding
This commit is contained in:
parent
05dbf872ab
commit
b349ba1521
15 changed files with 569 additions and 162 deletions
|
|
@ -969,6 +969,9 @@ RACCT_DEFAULT_TO_DISABLED opt_global.h
|
|||
# Resource Limits
|
||||
RCTL opt_global.h
|
||||
|
||||
# OPNsense additions
|
||||
PF_SHARE_FORWARD opt_pf.h
|
||||
|
||||
# Random number generator(s)
|
||||
# Which CSPRNG hash we get.
|
||||
# If Yarrow is not chosen, Fortuna is selected.
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ ip_tryforward(struct mbuf *m)
|
|||
struct in_addr odest, dest;
|
||||
uint16_t ip_len, ip_off;
|
||||
int error = 0;
|
||||
struct m_tag *fwd_tag = NULL;
|
||||
|
||||
/*
|
||||
* Are we active and forwarding packets?
|
||||
|
|
@ -317,9 +316,7 @@ passin:
|
|||
/*
|
||||
* Destination address changed?
|
||||
*/
|
||||
if (m->m_flags & M_IP_NEXTHOP)
|
||||
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
|
||||
if (odest.s_addr != dest.s_addr || fwd_tag != NULL) {
|
||||
if (odest.s_addr != dest.s_addr || IP_HAS_NEXTHOP(m)) {
|
||||
/*
|
||||
* Is it now for a local address on this host?
|
||||
*/
|
||||
|
|
@ -334,11 +331,13 @@ forwardlocal:
|
|||
/*
|
||||
* 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_HAS_NEXTHOP(m)) {
|
||||
struct sockaddr_in tmp;
|
||||
if (ip_get_fwdtag(m, &tmp, NULL)) {
|
||||
return (NULL);
|
||||
}
|
||||
dest.s_addr = tmp.sin_addr.s_addr;
|
||||
ip_flush_fwdtag(m);
|
||||
}
|
||||
if (ip_findroute(&nh, dest, m) != 0)
|
||||
return (NULL); /* icmp unreach already sent */
|
||||
|
|
|
|||
|
|
@ -622,16 +622,14 @@ tooshort:
|
|||
goto ours;
|
||||
}
|
||||
reinjected:
|
||||
if (m->m_flags & M_IP_NEXTHOP) {
|
||||
if (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) {
|
||||
/*
|
||||
* Directly ship the packet on. This allows
|
||||
* forwarding packets originally destined to us
|
||||
* to some other directly connected host.
|
||||
*/
|
||||
ip_forward(m, 1);
|
||||
return;
|
||||
}
|
||||
if (IP_HAS_NEXTHOP(m)) {
|
||||
/*
|
||||
* Directly ship the packet on. This allows
|
||||
* forwarding packets originally destined to us
|
||||
* to some other directly connected host.
|
||||
*/
|
||||
ip_forward(m, 1);
|
||||
return;
|
||||
}
|
||||
passin:
|
||||
|
||||
|
|
|
|||
|
|
@ -102,20 +102,20 @@ extern int in_mcast_loop;
|
|||
extern struct protosw inetsw[];
|
||||
|
||||
static inline int
|
||||
ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp,
|
||||
ip_output_pfil(struct mbuf **mp, struct ifnet **ifp, 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;
|
||||
u_short ifidx;
|
||||
|
||||
m = *mp;
|
||||
ip = mtod(m, struct ip *);
|
||||
|
||||
/* Run through list of hooks for output packets. */
|
||||
odst.s_addr = ip->ip_dst.s_addr;
|
||||
*error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, PFIL_OUT, inp);
|
||||
*error = pfil_run_hooks(&V_inet_pfil_hook, mp, *ifp, PFIL_OUT, inp);
|
||||
m = *mp;
|
||||
if ((*error) != 0 || m == NULL)
|
||||
return 1; /* Finished */
|
||||
|
|
@ -179,13 +179,15 @@ ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp,
|
|||
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, &ifidx)) {
|
||||
if (ifidx != 0) {
|
||||
struct ifnet *nifp = ifnet_byindex(ifidx);
|
||||
if (nifp != NULL) {
|
||||
*ifp = nifp;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
}
|
||||
|
||||
|
|
@ -403,6 +405,7 @@ again:
|
|||
isbroadcast = in_broadcast(gw->sin_addr, ifp);
|
||||
}
|
||||
|
||||
haveroute:
|
||||
/*
|
||||
* Calculate MTU. If we have a route that is up, use that,
|
||||
* otherwise use the interface's MTU.
|
||||
|
|
@ -571,7 +574,8 @@ sendit:
|
|||
|
||||
/* Jump over all PFIL processing if hooks are not active. */
|
||||
if (PFIL_HOOKED(&V_inet_pfil_hook)) {
|
||||
switch (ip_output_pfil(&m, ifp, inp, dst, &fibnum, &error)) {
|
||||
struct ifnet *same = ifp;
|
||||
switch (ip_output_pfil(&m, &ifp, inp, dst, &fibnum, &error)) {
|
||||
case 1: /* Finished */
|
||||
goto done;
|
||||
|
||||
|
|
@ -588,6 +592,9 @@ sendit:
|
|||
rte = NULL;
|
||||
gw = dst;
|
||||
ip = mtod(m, struct ip *);
|
||||
if (same != ifp) {
|
||||
goto haveroute;
|
||||
}
|
||||
goto again;
|
||||
|
||||
}
|
||||
|
|
@ -1390,3 +1397,89 @@ ip_mloopback(struct ifnet *ifp, const struct mbuf *m, int hlen)
|
|||
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, u_short ifidx)
|
||||
{
|
||||
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 = ifidx;
|
||||
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, u_short *ifidx)
|
||||
{
|
||||
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 (ifidx != NULL) {
|
||||
*ifidx = fwd_info->if_index;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,6 +236,11 @@ extern int (*ip_rsvp_vif)(struct socket *, struct sockopt *);
|
|||
extern void (*ip_rsvp_force_done)(struct socket *);
|
||||
extern int (*rsvp_input_p)(struct mbuf **, int *, int);
|
||||
|
||||
#define IP_HAS_NEXTHOP(m) ((m)->m_flags & M_IP_NEXTHOP)
|
||||
int ip_set_fwdtag(struct mbuf *, struct sockaddr_in *, u_short);
|
||||
int ip_get_fwdtag(struct mbuf *, struct sockaddr_in *, u_short *);
|
||||
void ip_flush_fwdtag(struct mbuf *);
|
||||
|
||||
VNET_DECLARE(struct pfil_head, inet_pfil_hook); /* packet filter hooks */
|
||||
#define V_inet_pfil_hook VNET(inet_pfil_hook)
|
||||
|
||||
|
|
|
|||
|
|
@ -575,6 +575,7 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
|
|||
int off0;
|
||||
int optlen = 0;
|
||||
#ifdef INET
|
||||
struct sockaddr_in next_hop;
|
||||
int len;
|
||||
#endif
|
||||
int tlen = 0, off;
|
||||
|
|
@ -582,8 +583,8 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
|
|||
int thflags;
|
||||
int rstreason = 0; /* For badport_bandlim accounting purposes */
|
||||
uint8_t iptos;
|
||||
struct m_tag *fwd_tag = NULL;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 next_hop6;
|
||||
struct ip6_hdr *ip6 = NULL;
|
||||
int isipv6;
|
||||
#else
|
||||
|
|
@ -777,22 +778,6 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
|
|||
} else
|
||||
ti_locked = TI_UNLOCKED;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
findpcb:
|
||||
#ifdef INVARIANTS
|
||||
if (ti_locked == TI_RLOCKED) {
|
||||
|
|
@ -802,10 +787,11 @@ findpcb:
|
|||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (isipv6 && fwd_tag != NULL) {
|
||||
struct sockaddr_in6 *next_hop6;
|
||||
|
||||
next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1);
|
||||
/*
|
||||
* Grab info from IP forward tag prepended to the chain.
|
||||
*/
|
||||
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?
|
||||
|
|
@ -820,11 +806,13 @@ findpcb:
|
|||
* 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, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif);
|
||||
}
|
||||
/* Remove the tag from the packet. We don't need it anymore. */
|
||||
ip6_flush_fwdtag(m);
|
||||
} else if (isipv6) {
|
||||
inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src,
|
||||
th->th_sport, &ip6->ip6_dst, th->th_dport,
|
||||
|
|
@ -836,10 +824,10 @@ findpcb:
|
|||
else
|
||||
#endif
|
||||
#ifdef INET
|
||||
if (fwd_tag != NULL) {
|
||||
struct sockaddr_in *next_hop;
|
||||
|
||||
next_hop = (struct sockaddr_in *)(fwd_tag+1);
|
||||
/*
|
||||
* Grab info from IP forward tag prepended to the chain.
|
||||
*/
|
||||
if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) {
|
||||
/*
|
||||
* Transparently forwarded. Pretend to be the destination.
|
||||
* already got one like this?
|
||||
|
|
@ -854,11 +842,13 @@ findpcb:
|
|||
* 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, INPLOOKUP_WILDCARD |
|
||||
INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif);
|
||||
}
|
||||
/* Remove the tag from the packet. We don't need it anymore. */
|
||||
ip_flush_fwdtag(m);
|
||||
} else
|
||||
inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src,
|
||||
th->th_sport, ip->ip_dst, th->th_dport,
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
|
|||
struct ip save_ip;
|
||||
struct sockaddr_in udp_in;
|
||||
struct mbuf *m;
|
||||
struct m_tag *fwd_tag;
|
||||
struct sockaddr_in next_hop;
|
||||
int cscov_partial, iphlen;
|
||||
|
||||
m = *mp;
|
||||
|
|
@ -624,14 +624,9 @@ udp_input(struct mbuf **mp, int *offp, int proto)
|
|||
*/
|
||||
|
||||
/*
|
||||
* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain.
|
||||
* Grab info from IP forward 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?
|
||||
|
|
@ -645,14 +640,13 @@ udp_input(struct mbuf **mp, int *offp, int proto)
|
|||
* 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 |
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ ip6_tryforward(struct mbuf *m)
|
|||
{
|
||||
struct sockaddr_in6 dst;
|
||||
struct nhop6_basic nh;
|
||||
struct m_tag *fwd_tag;
|
||||
struct ip6_hdr *ip6;
|
||||
struct ifnet *rcvif;
|
||||
uint32_t plen;
|
||||
|
|
@ -173,14 +172,16 @@ ip6_tryforward(struct mbuf *m)
|
|||
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) {
|
||||
if (IP6_HAS_NEXTHOP(m)) {
|
||||
/*
|
||||
* 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);
|
||||
struct sockaddr_in6 tmp;
|
||||
if (ip6_get_fwdtag(m, &tmp, NULL)) {
|
||||
return (NULL);
|
||||
}
|
||||
dst.sin6_addr = tmp.sin6_addr;
|
||||
ip6_flush_fwdtag(m);
|
||||
} else {
|
||||
/* Update dst since pfil could change it */
|
||||
dst.sin6_addr = ip6->ip6_dst;
|
||||
|
|
@ -232,17 +233,15 @@ passin:
|
|||
* 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);
|
||||
if (IP6_HAS_NEXTHOP(m)) {
|
||||
struct sockaddr_in6 tmp;
|
||||
if (ip6_get_fwdtag(m, &tmp, NULL)) {
|
||||
return (NULL);
|
||||
}
|
||||
dst.sin6_addr = tmp.sin6_addr;
|
||||
ip6_flush_fwdtag(m);
|
||||
} else
|
||||
dst.sin6_addr = ip6->ip6_dst;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ ip6_forward(struct mbuf *m, int srcrt)
|
|||
#ifdef SCTP
|
||||
int sw_csum;
|
||||
#endif
|
||||
struct m_tag *fwd_tag;
|
||||
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
|
||||
|
||||
/*
|
||||
|
|
@ -359,13 +358,17 @@ again2:
|
|||
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) {
|
||||
if (IP6_HAS_NEXTHOP(m)) {
|
||||
dst = (struct sockaddr_in6 *)&rin6.ro_dst;
|
||||
bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6));
|
||||
if (ip6_get_fwdtag(m, dst, NULL) != 0) {
|
||||
if (mcopy) {
|
||||
m_freem(m);
|
||||
goto freecopy;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
m->m_flags |= M_SKIP_FIREWALL;
|
||||
m->m_flags &= ~M_IP6_NEXTHOP;
|
||||
m_tag_delete(m, fwd_tag);
|
||||
ip6_flush_fwdtag(m);
|
||||
RTFREE(rt);
|
||||
goto again2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -785,8 +785,7 @@ ip6_input(struct mbuf *m)
|
|||
goto hbhcheck;
|
||||
}
|
||||
reinjected:
|
||||
if ((m->m_flags & M_IP6_NEXTHOP) &&
|
||||
m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) {
|
||||
if (IP6_HAS_NEXTHOP(m)) {
|
||||
/*
|
||||
* Directly ship the packet on. This allows forwarding
|
||||
* packets originally destined to us to some other directly
|
||||
|
|
|
|||
|
|
@ -319,8 +319,8 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
|
|||
int hdrsplit = 0;
|
||||
int sw_csum, tso;
|
||||
int needfiblookup;
|
||||
int has_fwd_tag = 0;
|
||||
uint32_t fibnum;
|
||||
struct m_tag *fwd_tag = NULL;
|
||||
uint32_t id;
|
||||
|
||||
if (inp != NULL) {
|
||||
|
|
@ -541,7 +541,7 @@ again:
|
|||
ro->ro_dst.sin6_family = AF_INET6;
|
||||
RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum);
|
||||
}
|
||||
if (ro->ro_rt && fwd_tag == NULL && (ro->ro_rt->rt_flags & RTF_UP) &&
|
||||
if (ro->ro_rt && !has_fwd_tag && (ro->ro_rt->rt_flags & RTF_UP) &&
|
||||
ro->ro_dst.sin6_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) {
|
||||
rt = ro->ro_rt;
|
||||
|
|
@ -550,7 +550,7 @@ again:
|
|||
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);
|
||||
|
|
@ -854,13 +854,11 @@ again:
|
|||
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, NULL)) {
|
||||
dst = (struct sockaddr_in6 *)&ro->ro_dst;
|
||||
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);
|
||||
ip6_flush_fwdtag(m);
|
||||
has_fwd_tag = 1;
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
|
@ -3062,3 +3060,102 @@ ip6_optlen(struct inpcb *in6p)
|
|||
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, u_short ifidx)
|
||||
{
|
||||
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);
|
||||
|
||||
bcopy(dst, &fwd_info->dst, sizeof(fwd_info->dst));
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
fwd_info->if_index = ifidx;
|
||||
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, u_short *ifidx)
|
||||
{
|
||||
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 (ifidx != NULL) {
|
||||
*ifidx = fwd_info->if_index;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -397,6 +397,11 @@ int ip6_deletefraghdr(struct mbuf *, int, int);
|
|||
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 *, u_short);
|
||||
int ip6_get_fwdtag(struct mbuf *, struct sockaddr_in6 *, u_short *);
|
||||
void ip6_flush_fwdtag(struct mbuf *);
|
||||
|
||||
int route6_input(struct mbuf **, int *, int);
|
||||
|
||||
void frag6_init(void);
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
|||
int cscov_partial;
|
||||
int plen, ulen;
|
||||
struct sockaddr_in6 fromsa;
|
||||
struct m_tag *fwd_tag;
|
||||
struct sockaddr_in6 next_hop6;
|
||||
uint16_t uh_sum;
|
||||
uint8_t nxt;
|
||||
|
||||
|
|
@ -411,14 +411,9 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
|||
*/
|
||||
|
||||
/*
|
||||
* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain.
|
||||
* Grab info from IP forward 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?
|
||||
|
|
@ -433,14 +428,13 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
|||
* 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,
|
||||
|
|
|
|||
|
|
@ -165,66 +165,25 @@ again:
|
|||
ret = EACCES;
|
||||
#else
|
||||
{
|
||||
struct m_tag *fwd_tag;
|
||||
size_t len;
|
||||
|
||||
KASSERT(args.next_hop == NULL || args.next_hop6 == NULL,
|
||||
("%s: both next_hop=%p and next_hop6=%p not NULL", __func__,
|
||||
args.next_hop, args.next_hop6));
|
||||
#ifdef INET6
|
||||
if (args.next_hop6 != NULL)
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
#ifdef INET
|
||||
if (args.next_hop != NULL)
|
||||
len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
fwd_tag = (dir == DIR_IN) ? NULL :
|
||||
m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
|
||||
if (fwd_tag != NULL) {
|
||||
m_tag_unlink(*m0, fwd_tag);
|
||||
} else {
|
||||
fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
|
||||
M_NOWAIT);
|
||||
if (fwd_tag == NULL) {
|
||||
ret = EACCES;
|
||||
break; /* i.e. drop */
|
||||
}
|
||||
}
|
||||
#ifdef INET6
|
||||
if (args.next_hop6 != NULL) {
|
||||
struct sockaddr_in6 *sa6;
|
||||
|
||||
sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
|
||||
bcopy(args.next_hop6, sa6, len);
|
||||
/*
|
||||
* If nh6 address is link-local we should convert
|
||||
* it to kernel internal form before doing any
|
||||
* comparisons.
|
||||
*/
|
||||
if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
|
||||
if (ip6_set_fwdtag(*m0, args.next_hop6, 0)) {
|
||||
ret = EACCES;
|
||||
break;
|
||||
}
|
||||
if (in6_localip(&sa6->sin6_addr))
|
||||
(*m0)->m_flags |= M_FASTFWD_OURS;
|
||||
(*m0)->m_flags |= M_IP6_NEXTHOP;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET
|
||||
if (args.next_hop != NULL) {
|
||||
bcopy(args.next_hop, (fwd_tag+1), len);
|
||||
if (in_localip(args.next_hop->sin_addr))
|
||||
(*m0)->m_flags |= M_FASTFWD_OURS;
|
||||
(*m0)->m_flags |= M_IP_NEXTHOP;
|
||||
if (ip_set_fwdtag(*m0, args.next_hop, 0)) {
|
||||
ret = EACCES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_tag_prepend(*m0, fwd_tag);
|
||||
}
|
||||
#endif /* INET || INET6 */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -290,6 +290,9 @@ static void pf_mtag_free(struct m_tag *);
|
|||
static void pf_route(struct mbuf **, struct pf_rule *, int,
|
||||
struct ifnet *, struct pf_state *,
|
||||
struct pf_pdesc *);
|
||||
static void pf_route_shared(struct mbuf **, struct pf_rule *, int,
|
||||
struct ifnet *, struct pf_state *,
|
||||
struct pf_pdesc *);
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
static void pf_change_a6(struct pf_addr *, u_int16_t *,
|
||||
|
|
@ -297,6 +300,9 @@ static void pf_change_a6(struct pf_addr *, u_int16_t *,
|
|||
static void pf_route6(struct mbuf **, struct pf_rule *, int,
|
||||
struct ifnet *, struct pf_state *,
|
||||
struct pf_pdesc *);
|
||||
static void pf_route6_shared(struct mbuf **, struct pf_rule *,
|
||||
int, struct ifnet *, struct pf_state *,
|
||||
struct pf_pdesc *);
|
||||
#endif /* INET6 */
|
||||
|
||||
int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
|
||||
|
|
@ -368,6 +374,25 @@ SYSCTL_ULONG(_net_pf, OID_AUTO, states_hashsize, CTLFLAG_RDTUN,
|
|||
SYSCTL_ULONG(_net_pf, OID_AUTO, source_nodes_hashsize, CTLFLAG_RDTUN,
|
||||
&pf_srchashsize, 0, "Size of pf(4) source nodes hashtable");
|
||||
|
||||
#ifdef PF_SHARE_FORWARD
|
||||
static VNET_DEFINE(int, pf_share_forward) = 1;
|
||||
static VNET_DEFINE(int, pf_share_forward6) = 1;
|
||||
#else
|
||||
static VNET_DEFINE(int, pf_share_forward) = 0;
|
||||
static VNET_DEFINE(int, pf_share_forward6) = 0;
|
||||
#endif
|
||||
|
||||
#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 share IPv4 forwarding decisions with ipfw(4).");
|
||||
|
||||
SYSCTL_INT(_net_pf, OID_AUTO, share_forward6,
|
||||
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(pf_share_forward6), 0,
|
||||
"If set pf(4) will share IPv6 forwarding decisions with ipfw(4).");
|
||||
|
||||
VNET_DEFINE(void *, pf_swi_cookie);
|
||||
|
||||
VNET_DEFINE(uint32_t, pf_hashseed);
|
||||
|
|
@ -5568,6 +5593,113 @@ done:
|
|||
*m = NULL;
|
||||
return;
|
||||
|
||||
bad_locked:
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
bad:
|
||||
m_freem(m0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void
|
||||
pf_route_shared(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *ifp,
|
||||
struct pf_state *s, struct pf_pdesc *pd)
|
||||
{
|
||||
struct mbuf *m0;
|
||||
struct sockaddr_in dst;
|
||||
struct ip *ip;
|
||||
struct pf_addr naddr;
|
||||
struct pf_src_node *sn = NULL;
|
||||
int error = 0;
|
||||
|
||||
KASSERT(m && *m && r && ifp, ("%s: invalid parameters", __func__));
|
||||
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",
|
||||
__func__));
|
||||
|
||||
if ((pd->pf_mtag == NULL &&
|
||||
((pd->pf_mtag = pf_get_mtag(*m)) == NULL)) ||
|
||||
pd->pf_mtag->routed++ > 3) {
|
||||
m0 = *m;
|
||||
*m = NULL;
|
||||
goto bad_locked;
|
||||
}
|
||||
|
||||
if (r->rt == PF_DUPTO) {
|
||||
if ((m0 = m_dup(*m, M_NOWAIT)) == NULL) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((r->rt == PF_REPLYTO) == (r->direction == dir)) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
return;
|
||||
}
|
||||
m0 = *m;
|
||||
}
|
||||
|
||||
/* retain old behaviour by avoiding a rewrite */
|
||||
if (IP_HAS_NEXTHOP(m0)) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ip = mtod(m0, struct ip *);
|
||||
|
||||
bzero(&dst, sizeof(dst));
|
||||
dst.sin_family = AF_INET;
|
||||
dst.sin_len = sizeof(dst);
|
||||
dst.sin_addr = ip->ip_dst;
|
||||
|
||||
if (r->rt == PF_FASTROUTE) {
|
||||
struct nhop4_basic nh4;
|
||||
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
|
||||
if (fib4_lookup_nh_basic(M_GETFIB(m0), ip->ip_dst, 0,
|
||||
m0->m_pkthdr.flowid, &nh4) != 0) {
|
||||
KMOD_IPSTAT_INC(ips_noroute);
|
||||
error = EHOSTUNREACH;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ifp = nh4.nh_ifp;
|
||||
dst.sin_addr = nh4.nh_addr;
|
||||
} else {
|
||||
if (TAILQ_EMPTY(&r->rpool.list)) {
|
||||
DPFPRINTF(PF_DEBUG_URGENT,
|
||||
("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__));
|
||||
goto bad_locked;
|
||||
}
|
||||
if (s == NULL) {
|
||||
pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
|
||||
&naddr, NULL, &sn);
|
||||
if (!PF_AZERO(&naddr, AF_INET))
|
||||
dst.sin_addr.s_addr = naddr.v4.s_addr;
|
||||
ifp = r->rpool.cur->kif ?
|
||||
r->rpool.cur->kif->pfik_ifp : NULL;
|
||||
} else {
|
||||
if (!PF_AZERO(&s->rt_addr, AF_INET))
|
||||
dst.sin_addr.s_addr =
|
||||
s->rt_addr.v4.s_addr;
|
||||
ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
|
||||
PF_STATE_UNLOCK(s);
|
||||
}
|
||||
}
|
||||
if (ifp == NULL)
|
||||
goto bad;
|
||||
|
||||
if (ip_set_fwdtag(m0, &dst, ifp->if_index))
|
||||
goto bad;
|
||||
|
||||
done:
|
||||
if (r->rt == PF_DUPTO && IP_HAS_NEXTHOP(m0))
|
||||
ip_forward(m0, 1);
|
||||
return;
|
||||
|
||||
bad_locked:
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
|
|
@ -5703,6 +5835,109 @@ done:
|
|||
*m = NULL;
|
||||
return;
|
||||
|
||||
bad_locked:
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
bad:
|
||||
m_freem(m0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
static void
|
||||
pf_route6_shared(struct mbuf **m, struct pf_rule *r, int dir,
|
||||
struct ifnet *ifp, struct pf_state *s, struct pf_pdesc *pd)
|
||||
{
|
||||
struct mbuf *m0;
|
||||
struct sockaddr_in6 dst;
|
||||
struct ip6_hdr *ip6;
|
||||
struct pf_addr naddr;
|
||||
struct pf_src_node *sn = NULL;
|
||||
|
||||
KASSERT(m && *m && r && ifp, ("%s: invalid parameters", __func__));
|
||||
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",
|
||||
__func__));
|
||||
|
||||
if ((pd->pf_mtag == NULL &&
|
||||
((pd->pf_mtag = pf_get_mtag(*m)) == NULL)) ||
|
||||
pd->pf_mtag->routed++ > 3) {
|
||||
m0 = *m;
|
||||
*m = NULL;
|
||||
goto bad_locked;
|
||||
}
|
||||
|
||||
if (r->rt == PF_DUPTO) {
|
||||
if ((m0 = m_dup(*m, M_NOWAIT)) == NULL) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((r->rt == PF_REPLYTO) == (r->direction == dir)) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
return;
|
||||
}
|
||||
m0 = *m;
|
||||
}
|
||||
|
||||
/* retain old behaviour by avoiding a rewrite */
|
||||
if (IP6_HAS_NEXTHOP(m0)) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ip6 = mtod(m0, struct ip6_hdr *);
|
||||
|
||||
bzero(&dst, sizeof(dst));
|
||||
dst.sin6_family = AF_INET6;
|
||||
dst.sin6_len = sizeof(dst);
|
||||
dst.sin6_addr = ip6->ip6_dst;
|
||||
|
||||
/* Cheat. XXX why only in the v6 case??? */
|
||||
if (r->rt == PF_FASTROUTE) {
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
m0->m_flags |= M_SKIP_FIREWALL;
|
||||
ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
|
||||
*m = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (TAILQ_EMPTY(&r->rpool.list)) {
|
||||
DPFPRINTF(PF_DEBUG_URGENT,
|
||||
("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__));
|
||||
goto bad_locked;
|
||||
}
|
||||
if (s == NULL) {
|
||||
pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
|
||||
&naddr, NULL, &sn);
|
||||
if (!PF_AZERO(&naddr, AF_INET6))
|
||||
PF_ACPY((struct pf_addr *)&dst.sin6_addr,
|
||||
&naddr, AF_INET6);
|
||||
ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
|
||||
} else {
|
||||
if (!PF_AZERO(&s->rt_addr, AF_INET6))
|
||||
PF_ACPY((struct pf_addr *)&dst.sin6_addr,
|
||||
&s->rt_addr, AF_INET6);
|
||||
ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
|
||||
}
|
||||
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
|
||||
if (ifp == NULL)
|
||||
goto bad;
|
||||
|
||||
if (ip6_set_fwdtag(m0, &dst, ifp->if_index))
|
||||
goto bad;
|
||||
|
||||
done:
|
||||
if (r->rt == PF_DUPTO && IP6_HAS_NEXTHOP(m0))
|
||||
ip6_forward(m0, 1);
|
||||
|
||||
return;
|
||||
|
||||
bad_locked:
|
||||
if (s)
|
||||
PF_STATE_UNLOCK(s);
|
||||
|
|
@ -5861,12 +6096,25 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
|
|||
struct pf_ruleset *ruleset = NULL;
|
||||
struct pf_pdesc pd;
|
||||
int off, dirndx, pqid = 0;
|
||||
int share_forward = V_pf_share_forward;
|
||||
u_short ifidx;
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
|
||||
if (!V_pf_status.running)
|
||||
return (PF_PASS);
|
||||
|
||||
/* restore the correct forwarding interface */
|
||||
if (share_forward && dir == PF_OUT && IP_HAS_NEXTHOP(m) &&
|
||||
!ip_get_fwdtag(m, NULL, &ifidx)) {
|
||||
if (ifidx != 0) {
|
||||
struct ifnet *nifp = ifnet_byindex(ifidx);
|
||||
if (nifp != NULL) {
|
||||
ifp = nifp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
|
||||
kif = (struct pfi_kif *)ifp->if_pf_kif;
|
||||
|
|
@ -6222,7 +6470,11 @@ done:
|
|||
default:
|
||||
/* pf_route() returns unlocked. */
|
||||
if (r->rt) {
|
||||
pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
|
||||
if (!share_forward)
|
||||
pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
|
||||
else
|
||||
pf_route_shared(m0, r, dir, kif->pfik_ifp, s,
|
||||
&pd);
|
||||
return (action);
|
||||
}
|
||||
break;
|
||||
|
|
@ -6249,6 +6501,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
|
|||
struct pf_pdesc pd;
|
||||
int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0;
|
||||
int fwdir = dir;
|
||||
int share_forward = V_pf_share_forward6;
|
||||
u_short ifidx;
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
|
||||
|
|
@ -6273,6 +6527,17 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
|
|||
if (!V_pf_status.running)
|
||||
return (PF_PASS);
|
||||
|
||||
/* restore the correct forwarding interface */
|
||||
if (share_forward && dir == PF_OUT && IP6_HAS_NEXTHOP(m) &&
|
||||
!ip6_get_fwdtag(m, NULL, &ifidx)) {
|
||||
if (ifidx != 0) {
|
||||
struct ifnet *nifp = ifnet_byindex(ifidx);
|
||||
if (nifp != NULL) {
|
||||
ifp = nifp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
pd.pf_mtag = pf_find_mtag(m);
|
||||
|
||||
|
|
@ -6637,7 +6902,11 @@ done:
|
|||
default:
|
||||
/* pf_route6() returns unlocked. */
|
||||
if (r->rt) {
|
||||
pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
|
||||
if (!share_forward)
|
||||
pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
|
||||
else
|
||||
pf_route6_shared(m0, r, dir, kif->pfik_ifp, s,
|
||||
&pd);
|
||||
return (action);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in a new issue