version 1.12, 2000/06/03 14:36:36 |
version 1.12.2.13, 2004/04/07 22:33:37 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
/* $KAME: ip6_forward.c,v 1.37 2000/05/28 12:17:19 itojun Exp $ */ |
/* $KAME: ip6_forward.c,v 1.56 2000/09/22 04:01:37 itojun Exp $ */ |
|
|
/* |
/* |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
|
#include "opt_ipsec.h" |
|
#include "opt_pfil_hooks.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
|
|
|
|
#include <net/if.h> |
#include <net/if.h> |
#include <net/route.h> |
#include <net/route.h> |
|
#ifdef PFIL_HOOKS |
|
#include <net/pfil.h> |
|
#endif |
|
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <netinet/in_var.h> |
#include <netinet/in_var.h> |
|
|
#include <netinet6/ip6_var.h> |
#include <netinet6/ip6_var.h> |
#include <netinet/icmp6.h> |
#include <netinet/icmp6.h> |
#include <netinet6/nd6.h> |
#include <netinet6/nd6.h> |
|
#include <netinet6/ip6protosw.h> |
|
|
#ifdef IPSEC_IPV6FWD |
#ifdef IPSEC |
#include <netinet6/ipsec.h> |
#include <netinet6/ipsec.h> |
#include <netkey/key.h> |
#include <netkey/key.h> |
#include <netkey/key_debug.h> |
#endif /* IPSEC */ |
#endif /* IPSEC_IPV6FWD */ |
|
|
|
#ifdef IPV6FIREWALL |
#ifdef IPV6FIREWALL |
#include <netinet6/ip6_fw.h> |
#include <netinet6/ip6_fw.h> |
Line 91 ip6_forward(m, srcrt) |
|
Line 97 ip6_forward(m, srcrt) |
|
int error, type = 0, code = 0; |
int error, type = 0, code = 0; |
struct mbuf *mcopy = NULL; |
struct mbuf *mcopy = NULL; |
struct ifnet *origifp; /* maybe unnecessary */ |
struct ifnet *origifp; /* maybe unnecessary */ |
#ifdef IPSEC_IPV6FWD |
#ifdef PFIL_HOOKS |
|
struct packet_filter_hook *pfh; |
|
struct mbuf *m1; |
|
int rv; |
|
#endif /* PFIL_HOOKS */ |
|
#ifdef IPSEC |
struct secpolicy *sp = NULL; |
struct secpolicy *sp = NULL; |
|
int ipsecrt = 0; |
#endif |
#endif |
long time_second = time.tv_sec; |
long time_second = time.tv_sec; |
|
|
#ifdef IPSEC_IPV6FWD |
#ifdef IPSEC |
/* |
/* |
* Check AH/ESP integrity. |
* Check AH/ESP integrity. |
*/ |
*/ |
Line 109 ip6_forward(m, srcrt) |
|
Line 121 ip6_forward(m, srcrt) |
|
m_freem(m); |
m_freem(m); |
return; |
return; |
} |
} |
#endif /*IPSEC_IPV6FWD*/ |
#endif /*IPSEC*/ |
|
|
|
/* |
|
* Do not forward packets to multicast destination (should be handled |
|
* by ip6_mforward(). |
|
* Do not forward packets with unspecified source. It was discussed |
|
* in July 2000, on ipngwg mailing list. |
|
*/ |
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || |
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || |
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { |
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || |
|
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { |
ip6stat.ip6s_cantforward++; |
ip6stat.ip6s_cantforward++; |
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ |
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ |
if (ip6_log_time + ip6_log_interval < time_second) { |
if (ip6_log_time + ip6_log_interval < time_second) { |
Line 148 ip6_forward(m, srcrt) |
|
Line 167 ip6_forward(m, srcrt) |
|
*/ |
*/ |
mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); |
mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); |
|
|
#ifdef IPSEC_IPV6FWD |
#ifdef IPSEC |
/* get a security policy for this packet */ |
/* get a security policy for this packet */ |
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); |
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING, |
|
&error); |
if (sp == NULL) { |
if (sp == NULL) { |
ipsec6stat.out_inval++; |
ipsec6stat.out_inval++; |
ip6stat.ip6s_cantforward++; |
ip6stat.ip6s_cantforward++; |
Line 191 ip6_forward(m, srcrt) |
|
Line 211 ip6_forward(m, srcrt) |
|
/* no need to do IPsec. */ |
/* no need to do IPsec. */ |
key_freesp(sp); |
key_freesp(sp); |
goto skip_ipsec; |
goto skip_ipsec; |
|
|
case IPSEC_POLICY_IPSEC: |
case IPSEC_POLICY_IPSEC: |
if (sp->req == NULL) { |
if (sp->req == NULL) { |
/* XXX should be panic ? */ |
/* XXX should be panic ? */ |
Line 238 ip6_forward(m, srcrt) |
|
Line 258 ip6_forward(m, srcrt) |
|
error = ipsec6_output_tunnel(&state, sp, 0); |
error = ipsec6_output_tunnel(&state, sp, 0); |
|
|
m = state.m; |
m = state.m; |
#if 0 /* XXX allocate a route (ro, dst) again later */ |
|
ro = (struct route_in6 *)state.ro; |
|
dst = (struct sockaddr_in6 *)state.dst; |
|
#endif |
|
key_freesp(sp); |
key_freesp(sp); |
|
|
if (error) { |
if (error) { |
Line 271 ip6_forward(m, srcrt) |
|
Line 287 ip6_forward(m, srcrt) |
|
m_freem(m); |
m_freem(m); |
return; |
return; |
} |
} |
|
|
|
/* adjust pointer */ |
|
ip6 = mtod(m, struct ip6_hdr *); |
|
rt = state.ro ? state.ro->ro_rt : NULL; |
|
dst = (struct sockaddr_in6 *)state.dst; |
|
if (dst != NULL && rt != NULL) |
|
ipsecrt = 1; |
} |
} |
skip_ipsec: |
skip_ipsec: |
#endif /* IPSEC_IPV6FWD */ |
|
|
if (ipsecrt) |
|
goto skip_routing; |
|
#endif /* IPSEC */ |
|
|
dst = &ip6_forward_rt.ro_dst; |
dst = &ip6_forward_rt.ro_dst; |
if (!srcrt) { |
if (!srcrt) { |
Line 289 ip6_forward(m, srcrt) |
|
Line 315 ip6_forward(m, srcrt) |
|
/* this probably fails but give it a try again */ |
/* this probably fails but give it a try again */ |
rtalloc((struct route *)&ip6_forward_rt); |
rtalloc((struct route *)&ip6_forward_rt); |
} |
} |
|
|
if (ip6_forward_rt.ro_rt == 0) { |
if (ip6_forward_rt.ro_rt == 0) { |
ip6stat.ip6s_noroute++; |
ip6stat.ip6s_noroute++; |
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ |
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ |
Line 324 ip6_forward(m, srcrt) |
|
Line 350 ip6_forward(m, srcrt) |
|
} |
} |
} |
} |
rt = ip6_forward_rt.ro_rt; |
rt = ip6_forward_rt.ro_rt; |
|
#ifdef IPSEC |
|
skip_routing:; |
|
#endif /* IPSEC */ |
|
|
/* |
/* |
* Scope check: if a packet can't be delivered to its destination |
* Scope check: if a packet can't be delivered to its destination |
Line 333 ip6_forward(m, srcrt) |
|
Line 362 ip6_forward(m, srcrt) |
|
* [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] |
* [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] |
*/ |
*/ |
if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) != |
if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) != |
in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) { |
in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src) |
|
#ifdef IPSEC |
|
&& !ipsecrt |
|
#endif |
|
) { |
ip6stat.ip6s_cantforward++; |
ip6stat.ip6s_cantforward++; |
ip6stat.ip6s_badscope++; |
ip6stat.ip6s_badscope++; |
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard); |
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard); |
Line 359 ip6_forward(m, srcrt) |
|
Line 392 ip6_forward(m, srcrt) |
|
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); |
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); |
if (mcopy) { |
if (mcopy) { |
u_long mtu; |
u_long mtu; |
#ifdef IPSEC_IPV6FWD |
#ifdef IPSEC |
struct secpolicy *sp; |
struct secpolicy *sp; |
int ipsecerror; |
int ipsecerror; |
size_t ipsechdrsiz; |
size_t ipsechdrsiz; |
#endif |
#endif |
|
|
mtu = rt->rt_ifp->if_mtu; |
mtu = rt->rt_ifp->if_mtu; |
#ifdef IPSEC_IPV6FWD |
#ifdef IPSEC |
/* |
/* |
* When we do IPsec tunnel ingress, we need to play |
* When we do IPsec tunnel ingress, we need to play |
* with if_mtu value (decrement IPsec header size |
* with if_mtu value (decrement IPsec header size |
Line 409 ip6_forward(m, srcrt) |
|
Line 442 ip6_forward(m, srcrt) |
|
* modified by a redirect. |
* modified by a redirect. |
*/ |
*/ |
if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && |
if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && |
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) |
#ifdef IPSEC |
|
!ipsecrt && |
|
#endif |
|
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { |
|
if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) { |
|
/* |
|
* If the incoming interface is equal to the outgoing |
|
* one, and the link attached to the interface is |
|
* point-to-point, then it will be highly probable |
|
* that a routing loop occurs. Thus, we immediately |
|
* drop the packet and send an ICMPv6 error message. |
|
* |
|
* type/code is based on suggestion by Rich Draves. |
|
* not sure if it is the best pick. |
|
*/ |
|
icmp6_error(mcopy, ICMP6_DST_UNREACH, |
|
ICMP6_DST_UNREACH_ADDR, 0); |
|
m_freem(m); |
|
return; |
|
} |
type = ND_REDIRECT; |
type = ND_REDIRECT; |
|
} |
|
|
#ifdef IPV6FIREWALL |
#ifdef IPV6FIREWALL |
/* |
/* |
Line 443 ip6_forward(m, srcrt) |
|
Line 496 ip6_forward(m, srcrt) |
|
* to a loopback interface? I don't think so, and thus |
* to a loopback interface? I don't think so, and thus |
* I bark here. (jinmei@kame.net) |
* I bark here. (jinmei@kame.net) |
* XXX: it is common to route invalid packets to loopback. |
* XXX: it is common to route invalid packets to loopback. |
* (itojun) |
* also, the codepath will be visited on use of ::1 in |
|
* rthdr. (itojun) |
*/ |
*/ |
|
#if 1 |
if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0) { |
if (0) |
|
#else |
|
if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0) |
|
#endif |
|
{ |
printf("ip6_forward: outgoing interface is loopback. " |
printf("ip6_forward: outgoing interface is loopback. " |
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n", |
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n", |
ip6_sprintf(&ip6->ip6_src), |
ip6_sprintf(&ip6->ip6_src), |
Line 454 ip6_forward(m, srcrt) |
|
Line 512 ip6_forward(m, srcrt) |
|
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif), |
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif), |
if_name(rt->rt_ifp)); |
if_name(rt->rt_ifp)); |
} |
} |
|
|
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) |
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) |
origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])]; |
origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])]; |
else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) |
else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) |
Line 476 ip6_forward(m, srcrt) |
|
Line 534 ip6_forward(m, srcrt) |
|
ip6->ip6_dst.s6_addr16[1] = 0; |
ip6->ip6_dst.s6_addr16[1] = 0; |
} |
} |
|
|
|
#ifdef PFIL_HOOKS |
|
/* |
|
* Run through list of hooks for output packets. |
|
*/ |
|
m1 = m; |
|
pfh = pfil_hook_get(PFIL_OUT, |
|
&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); |
|
for (; pfh; pfh = pfh->pfil_link.tqe_next) |
|
if (pfh->pfil_func) { |
|
rv = pfh->pfil_func(ip6, sizeof(*ip6), |
|
rt->rt_ifp, 1, &m1); |
|
m = m1; |
|
if (m == NULL) |
|
goto freecopy; |
|
if (rv) { |
|
error = EHOSTUNREACH; |
|
goto senderr; |
|
} |
|
ip6 = mtod(m, struct ip6_hdr *); |
|
} |
|
#endif /* PFIL_HOOKS */ |
|
|
#ifdef OLDIP6OUTPUT |
#ifdef OLDIP6OUTPUT |
error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, |
error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, |
(struct sockaddr *)dst, |
(struct sockaddr *)dst, |
Line 496 ip6_forward(m, srcrt) |
|
Line 576 ip6_forward(m, srcrt) |
|
goto freecopy; |
goto freecopy; |
} |
} |
} |
} |
|
|
|
#ifdef PFIL_HOOKS |
|
senderr: |
|
#endif |
if (mcopy == NULL) |
if (mcopy == NULL) |
return; |
return; |
|
|