2015-08-25 01:21:26 +03:00
|
|
|
/* $NetBSD: ip6_forward.c,v 1.78 2015/08/24 22:21:27 pooka Exp $ */
|
2002-09-11 12:15:37 +04:00
|
|
|
/* $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-05-19 05:40:18 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2000-05-19 05:40:18 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
2001-11-13 03:56:55 +03:00
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2015-08-25 01:21:26 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.78 2015/08/24 22:21:27 pooka Exp $");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2015-08-25 01:21:26 +03:00
|
|
|
#ifdef _KERNEL_OPT
|
2010-02-05 00:48:11 +03:00
|
|
|
#include "opt_gateway.h"
|
2000-07-16 11:57:55 +04:00
|
|
|
#include "opt_ipsec.h"
|
2015-08-25 01:21:26 +03:00
|
|
|
#endif
|
2000-07-16 11:57:55 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/domain.h>
|
|
|
|
#include <sys/protosw.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
2013-06-30 01:06:57 +04:00
|
|
|
#include <net/pfil.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
2000-01-31 17:18:52 +03:00
|
|
|
#include <netinet/ip_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/ip6_var.h>
|
2008-04-15 07:57:04 +04:00
|
|
|
#include <netinet6/ip6_private.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/icmp6.h>
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <netinet6/nd6.h>
|
|
|
|
|
2013-06-05 23:01:26 +04:00
|
|
|
#ifdef IPSEC
|
2007-02-10 12:43:05 +03:00
|
|
|
#include <netipsec/ipsec.h>
|
|
|
|
#include <netipsec/ipsec6.h>
|
|
|
|
#include <netipsec/key.h>
|
|
|
|
#include <netipsec/xform.h>
|
2013-06-05 23:01:26 +04:00
|
|
|
#endif /* IPSEC */
|
2007-02-10 12:43:05 +03:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <net/net_osdep.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
struct route ip6_forward_rt;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2013-06-30 01:06:57 +04:00
|
|
|
extern pfil_head_t *inet6_pfil_hook; /* XXX */
|
2001-06-12 19:12:33 +04:00
|
|
|
|
2014-12-10 04:10:14 +03:00
|
|
|
static void __printflike(4, 5)
|
2014-12-08 03:19:37 +03:00
|
|
|
ip6_cantforward(const struct ip6_hdr *ip6, const struct ifnet *srcifp,
|
|
|
|
const struct ifnet *dstifp, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
|
|
|
|
char reason[256];
|
|
|
|
va_list ap;
|
|
|
|
uint64_t *ip6s;
|
|
|
|
|
|
|
|
/* update statistics */
|
|
|
|
ip6s = IP6_STAT_GETREF();
|
|
|
|
ip6s[IP6_STAT_CANTFORWARD]++;
|
|
|
|
if (dstifp)
|
|
|
|
ip6s[IP6_STAT_BADSCOPE]++;
|
|
|
|
IP6_STAT_PUTREF();
|
|
|
|
|
|
|
|
if (dstifp)
|
|
|
|
in6_ifstat_inc(dstifp, ifs6_in_discard);
|
|
|
|
|
2015-08-07 11:11:33 +03:00
|
|
|
if (ip6_log_time + ip6_log_interval >= time_uptime)
|
2014-12-08 03:19:37 +03:00
|
|
|
return;
|
2015-08-07 11:11:33 +03:00
|
|
|
ip6_log_time = time_uptime;
|
2014-12-08 03:19:37 +03:00
|
|
|
|
|
|
|
va_start(ap, fmt);
|
2014-12-10 04:10:14 +03:00
|
|
|
vsnprintf(reason, sizeof(reason), fmt, ap);
|
2014-12-08 03:19:37 +03:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
log(LOG_DEBUG, "Cannot forward from %s@%s to %s@%s nxt %d (%s)\n",
|
|
|
|
IN6_PRINT(sbuf, &ip6->ip6_src), srcifp ? if_name(srcifp) : "?",
|
|
|
|
IN6_PRINT(dbuf, &ip6->ip6_dst), dstifp ? if_name(dstifp) : "?",
|
|
|
|
ip6->ip6_nxt, reason);
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Forward a packet. If some error occurs return the sender
|
|
|
|
* an icmp packet. Note we can't always generate a meaningful
|
|
|
|
* icmp message because icmp doesn't have a large enough repertoire
|
|
|
|
* of codes and types.
|
|
|
|
*
|
|
|
|
* If not forwarding, just drop the packet. This could be confusing
|
|
|
|
* if ipforwarding was zero but some routing protocol was advancing
|
|
|
|
* us as a gateway to somewhere. However, we must let the routing
|
|
|
|
* protocol deal with that.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2007-05-23 21:14:59 +04:00
|
|
|
ip6_forward(struct mbuf *m, int srcrt)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
1999-12-13 18:17:17 +03:00
|
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
const struct sockaddr_in6 *dst;
|
2001-02-10 07:14:26 +03:00
|
|
|
struct rtentry *rt;
|
2004-06-24 19:01:51 +04:00
|
|
|
int error = 0, type = 0, code = 0;
|
1999-12-13 18:17:17 +03:00
|
|
|
struct mbuf *mcopy = NULL;
|
2000-05-19 05:40:18 +04:00
|
|
|
struct ifnet *origifp; /* maybe unnecessary */
|
2014-12-08 03:19:37 +03:00
|
|
|
uint32_t inzone, outzone;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
struct in6_addr src_in6, dst_in6;
|
2013-06-05 23:01:26 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
int needipsec = 0;
|
2014-05-30 05:39:03 +04:00
|
|
|
struct secpolicy *sp = NULL;
|
2007-02-10 12:43:05 +03:00
|
|
|
#endif
|
|
|
|
|
2009-11-12 01:19:22 +03:00
|
|
|
/*
|
|
|
|
* Clear any in-bound checksum flags for this packet.
|
|
|
|
*/
|
|
|
|
m->m_pkthdr.csum_flags = 0;
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2000-07-27 19:53:51 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2000-02-26 11:39:18 +03:00
|
|
|
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
|
2000-07-27 19:53:51 +04:00
|
|
|
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
|
|
|
|
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
|
2014-12-08 03:19:37 +03:00
|
|
|
ip6_cantforward(ip6, m->m_pkthdr.rcvif, NULL,
|
|
|
|
((m->m_flags & (M_BCAST|M_MCAST)) != 0) ? "bcast/mcast" :
|
|
|
|
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ? "mcast/dst" :
|
|
|
|
"unspec/src");
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
|
1999-12-13 18:17:17 +03:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
1999-06-28 10:36:47 +04:00
|
|
|
icmp6_error(m, ICMP6_TIME_EXCEEDED,
|
|
|
|
ICMP6_TIME_EXCEED_TRANSIT, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ip6->ip6_hlim -= IPV6_HLIMDEC;
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
|
|
|
|
* size of IPv6 + ICMPv6 headers) bytes of the packet in case
|
|
|
|
* we need to generate an ICMP6 message to the src.
|
|
|
|
* Thanks to M_EXT, in most cases copy will not occur.
|
|
|
|
*
|
|
|
|
* It is important to save it before IPsec processing as IPsec
|
|
|
|
* processing may modify the mbuf.
|
|
|
|
*/
|
|
|
|
mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
|
|
|
|
|
2013-06-05 23:01:26 +04:00
|
|
|
#ifdef IPSEC
|
2014-05-30 05:39:03 +04:00
|
|
|
if (ipsec_used) {
|
|
|
|
/* Check the security policy (SP) for the packet */
|
2007-02-10 12:43:05 +03:00
|
|
|
|
2014-05-30 05:39:03 +04:00
|
|
|
sp = ipsec6_check_policy(m, NULL, 0, &needipsec, &error);
|
|
|
|
if (error != 0) {
|
|
|
|
/*
|
|
|
|
* Hack: -EINVAL is used to signal that a packet
|
|
|
|
* should be silently discarded. This is typically
|
|
|
|
* because we asked key management for an SA and
|
|
|
|
* it was delayed (e.g. kicked up to IKE).
|
|
|
|
*/
|
|
|
|
if (error == -EINVAL)
|
|
|
|
error = 0;
|
|
|
|
goto freecopy;
|
|
|
|
}
|
2007-02-10 12:43:05 +03:00
|
|
|
}
|
2013-06-05 23:01:26 +04:00
|
|
|
#endif /* IPSEC */
|
2007-02-10 12:43:05 +03:00
|
|
|
|
2008-01-12 05:58:58 +03:00
|
|
|
if (srcrt) {
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
union {
|
|
|
|
struct sockaddr dst;
|
|
|
|
struct sockaddr_in6 dst6;
|
|
|
|
} u;
|
|
|
|
|
|
|
|
sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0);
|
2008-01-14 07:16:45 +03:00
|
|
|
if ((rt = rtcache_lookup(&ip6_forward_rt, &u.dst)) == NULL) {
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_NOROUTE);
|
1999-12-13 18:17:17 +03:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
|
|
|
|
if (mcopy) {
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_NOROUTE, 0);
|
|
|
|
}
|
|
|
|
m_freem(m);
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
|
|
|
}
|
2008-01-14 07:16:45 +03:00
|
|
|
} else if ((rt = rtcache_validate(&ip6_forward_rt)) == NULL &&
|
|
|
|
(rt = rtcache_update(&ip6_forward_rt, 1)) == NULL) {
|
2008-01-12 05:58:58 +03:00
|
|
|
/*
|
|
|
|
* rtcache_getdst(ip6_forward_rt)->sin6_addr was equal to
|
|
|
|
* ip6->ip6_dst
|
|
|
|
*/
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_NOROUTE);
|
2008-01-12 05:58:58 +03:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
|
|
|
|
if (mcopy) {
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_NOROUTE, 0);
|
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
dst = satocsin6(rtcache_getdst(&ip6_forward_rt));
|
2000-02-26 11:39:18 +03:00
|
|
|
|
|
|
|
/*
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
* Source scope check: if a packet can't be delivered to its
|
|
|
|
* destination for the reason that the destination is beyond the scope
|
|
|
|
* of the source address, discard the packet and return an icmp6
|
|
|
|
* destination unreachable error with Code 2 (beyond scope of source
|
|
|
|
* address). We use a local copy of ip6_src, since in6_setscope()
|
|
|
|
* will possibly modify its first argument.
|
|
|
|
* [draft-ietf-ipngwg-icmp-v3-07, Section 3.1]
|
2000-02-26 11:39:18 +03:00
|
|
|
*/
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
src_in6 = ip6->ip6_src;
|
2014-12-08 03:19:37 +03:00
|
|
|
inzone = outzone = ~0;
|
|
|
|
if (in6_setscope(&src_in6, rt->rt_ifp, &outzone) != 0 ||
|
|
|
|
in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
|
|
|
|
inzone != outzone) {
|
|
|
|
ip6_cantforward(ip6, m->m_pkthdr.rcvif, rt->rt_ifp,
|
2014-12-10 04:10:14 +03:00
|
|
|
"src[%s] inzone %d outzone %d",
|
|
|
|
in6_getscopename(&ip6->ip6_src), inzone, outzone);
|
2000-02-26 11:39:18 +03:00
|
|
|
if (mcopy)
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
2014-12-08 03:19:37 +03:00
|
|
|
|
2013-06-05 23:01:26 +04:00
|
|
|
#ifdef IPSEC
|
|
|
|
/*
|
|
|
|
* If we need to encapsulate the packet, do it here
|
|
|
|
* ipsec6_proces_packet will send the packet using ip6_output
|
|
|
|
*/
|
2007-02-10 12:43:05 +03:00
|
|
|
if (needipsec) {
|
2014-05-30 05:39:03 +04:00
|
|
|
int s = splsoftnet();
|
|
|
|
error = ipsec6_process_packet(m, sp->req);
|
2007-02-10 12:43:05 +03:00
|
|
|
splx(s);
|
|
|
|
if (mcopy)
|
|
|
|
goto freecopy;
|
2013-06-05 23:01:26 +04:00
|
|
|
}
|
2007-02-10 12:43:05 +03:00
|
|
|
#endif
|
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* Destination scope check: if a packet is going to break the scope
|
|
|
|
* zone of packet's destination address, discard it. This case should
|
|
|
|
* usually be prevented by appropriately-configured routing table, but
|
|
|
|
* we need an explicit check because we may mistakenly forward the
|
|
|
|
* packet to a different zone by (e.g.) a default route.
|
|
|
|
*/
|
|
|
|
dst_in6 = ip6->ip6_dst;
|
2014-12-08 03:19:37 +03:00
|
|
|
inzone = outzone = ~0;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
|
|
|
|
in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
|
|
|
|
inzone != outzone) {
|
2014-12-08 03:19:37 +03:00
|
|
|
ip6_cantforward(ip6, m->m_pkthdr.rcvif, rt->rt_ifp,
|
2014-12-10 04:10:14 +03:00
|
|
|
"dst[%s] inzone %d outzone %d",
|
|
|
|
in6_getscopename(&ip6->ip6_dst), inzone, outzone);
|
2014-12-08 03:19:37 +03:00
|
|
|
if (mcopy)
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
|
|
|
|
if (mcopy) {
|
|
|
|
u_long mtu;
|
|
|
|
|
2002-05-29 11:53:39 +04:00
|
|
|
mtu = IN6_LINKMTU(rt->rt_ifp);
|
1999-12-13 18:17:17 +03:00
|
|
|
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
|
|
|
|
}
|
|
|
|
m_freem(m);
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (rt->rt_flags & RTF_GATEWAY)
|
|
|
|
dst = (struct sockaddr_in6 *)rt->rt_gateway;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are to forward the packet using the same interface
|
|
|
|
* as one we got the packet from, perhaps we should send a redirect
|
|
|
|
* to sender to shortcut a hop.
|
|
|
|
* Only send redirect if source is sending directly to us,
|
|
|
|
* and if packet was not source routed (or has any options).
|
|
|
|
* Also, don't send redirect if forwarding using a route
|
|
|
|
* modified by a redirect.
|
|
|
|
*/
|
2003-08-07 12:52:32 +04:00
|
|
|
if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects &&
|
2001-06-22 16:33:05 +04:00
|
|
|
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
|
2001-07-18 13:24:26 +04:00
|
|
|
if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
nd6_is_addr_neighbor(
|
Eliminate address family-specific route caches (struct route, struct
route_in6, struct route_iso), replacing all caches with a struct
route.
The principle benefit of this change is that all of the protocol
families can benefit from route cache-invalidation, which is
necessary for correct routing. Route-cache invalidation fixes an
ancient PR, kern/3508, at long last; it fixes various other PRs,
also.
Discussions with and ideas from Joerg Sonnenberger influenced this
work tremendously. Of course, all design oversights and bugs are
mine.
DETAILS
1 I added to each address family a pool of sockaddrs. I have
introduced routines for allocating, copying, and duplicating,
and freeing sockaddrs:
struct sockaddr *sockaddr_alloc(sa_family_t af, int flags);
struct sockaddr *sockaddr_copy(struct sockaddr *dst,
const struct sockaddr *src);
struct sockaddr *sockaddr_dup(const struct sockaddr *src, int flags);
void sockaddr_free(struct sockaddr *sa);
sockaddr_alloc() returns either a sockaddr from the pool belonging
to the specified family, or NULL if the pool is exhausted. The
returned sockaddr has the right size for that family; sa_family
and sa_len fields are initialized to the family and sockaddr
length---e.g., sa_family = AF_INET and sa_len = sizeof(struct
sockaddr_in). sockaddr_free() puts the given sockaddr back into
its family's pool.
sockaddr_dup() and sockaddr_copy() work analogously to strdup()
and strcpy(), respectively. sockaddr_copy() KASSERTs that the
family of the destination and source sockaddrs are alike.
The 'flags' argumet for sockaddr_alloc() and sockaddr_dup() is
passed directly to pool_get(9).
2 I added routines for initializing sockaddrs in each address
family, sockaddr_in_init(), sockaddr_in6_init(), sockaddr_iso_init(),
etc. They are fairly self-explanatory.
3 structs route_in6 and route_iso are no more. All protocol families
use struct route. I have changed the route cache, 'struct route',
so that it does not contain storage space for a sockaddr. Instead,
struct route points to a sockaddr coming from the pool the sockaddr
belongs to. I added a new method to struct route, rtcache_setdst(),
for setting the cache destination:
int rtcache_setdst(struct route *, const struct sockaddr *);
rtcache_setdst() returns 0 on success, or ENOMEM if no memory is
available to create the sockaddr storage.
It is now possible for rtcache_getdst() to return NULL if, say,
rtcache_setdst() failed. I check the return value for NULL
everywhere in the kernel.
4 Each routing domain (struct domain) has a list of live route
caches, dom_rtcache. rtflushall(sa_family_t af) looks up the
domain indicated by 'af', walks the domain's list of route caches
and invalidates each one.
2007-05-03 00:40:22 +04:00
|
|
|
satocsin6(rtcache_getdst(&ip6_forward_rt)),
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
rt->rt_ifp)) {
|
2001-06-22 16:33:05 +04:00
|
|
|
/*
|
|
|
|
* If the incoming interface is equal to the outgoing
|
2001-07-18 13:24:26 +04:00
|
|
|
* one, the link attached to the interface is
|
|
|
|
* point-to-point, and the IPv6 destination is
|
|
|
|
* regarded as on-link on the link, then it will be
|
|
|
|
* highly probable that the destination address does
|
|
|
|
* not exist on the link and that the packet is going
|
|
|
|
* to loop. Thus, we immediately drop the packet and
|
|
|
|
* send an ICMPv6 error message.
|
|
|
|
* For other routing loops, we dare to let the packet
|
|
|
|
* go to the loop, so that a remote diagnosing host
|
|
|
|
* can detect the loop by traceroute.
|
2001-06-22 16:33:05 +04:00
|
|
|
* 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;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
type = ND_REDIRECT;
|
2001-06-22 16:33:05 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-05-19 05:40:18 +04:00
|
|
|
/*
|
|
|
|
* Fake scoped addresses. Note that even link-local source or
|
|
|
|
* destinaion can appear, if the originating node just sends the
|
|
|
|
* packet to us (without address resolution for the destination).
|
|
|
|
* Since both icmp6_error and icmp6_redirect_output fill the embedded
|
2001-02-10 07:14:26 +03:00
|
|
|
* link identifiers, we can do this stuff after making a copy for
|
|
|
|
* returning an error.
|
2000-05-19 05:40:18 +04:00
|
|
|
*/
|
|
|
|
if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
|
|
|
|
/*
|
|
|
|
* See corresponding comments in ip6_output.
|
|
|
|
* XXX: but is it possible that ip6_forward() sends a packet
|
|
|
|
* to a loopback interface? I don't think so, and thus
|
|
|
|
* I bark here. (jinmei@kame.net)
|
2000-06-03 18:36:32 +04:00
|
|
|
* XXX: it is common to route invalid packets to loopback.
|
2000-06-30 23:46:05 +04:00
|
|
|
* also, the codepath will be visited on use of ::1 in
|
|
|
|
* rthdr. (itojun)
|
2000-05-19 05:40:18 +04:00
|
|
|
*/
|
2000-06-30 23:46:05 +04:00
|
|
|
#if 1
|
|
|
|
if (0)
|
|
|
|
#else
|
|
|
|
if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
|
|
|
|
#endif
|
|
|
|
{
|
2000-06-03 18:36:32 +04:00
|
|
|
printf("ip6_forward: outgoing interface is loopback. "
|
|
|
|
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
|
|
|
|
ip6_sprintf(&ip6->ip6_src),
|
|
|
|
ip6_sprintf(&ip6->ip6_dst),
|
|
|
|
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
|
|
|
|
if_name(rt->rt_ifp));
|
|
|
|
}
|
2000-06-30 23:46:05 +04:00
|
|
|
|
2001-03-30 15:08:56 +04:00
|
|
|
/* we can just use rcvif in forwarding. */
|
|
|
|
origifp = m->m_pkthdr.rcvif;
|
2000-05-19 05:40:18 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
origifp = rt->rt_ifp;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/*
|
|
|
|
* clear embedded scope identifiers if necessary.
|
|
|
|
* in6_clearscope will touch the addresses only when necessary.
|
|
|
|
*/
|
|
|
|
in6_clearscope(&ip6->ip6_src);
|
|
|
|
in6_clearscope(&ip6->ip6_dst);
|
2000-05-19 05:40:18 +04:00
|
|
|
|
2001-06-12 19:12:33 +04:00
|
|
|
/*
|
|
|
|
* Run through list of hooks for output packets.
|
|
|
|
*/
|
2013-06-30 01:06:57 +04:00
|
|
|
if ((error = pfil_run_hooks(inet6_pfil_hook, &m, rt->rt_ifp,
|
2003-06-30 07:30:50 +04:00
|
|
|
PFIL_OUT)) != 0)
|
2001-06-12 19:12:33 +04:00
|
|
|
goto senderr;
|
|
|
|
if (m == NULL)
|
|
|
|
goto freecopy;
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
|
2000-05-19 05:40:18 +04:00
|
|
|
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
|
1999-12-13 18:17:17 +03:00
|
|
|
if (error) {
|
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_CANTFORWARD);
|
1999-12-13 18:17:17 +03:00
|
|
|
} else {
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_FORWARD);
|
1999-12-13 18:17:17 +03:00
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (type)
|
2008-04-15 07:57:04 +04:00
|
|
|
IP6_STATINC(IP6_STAT_REDIRECTSENT);
|
1999-06-28 10:36:47 +04:00
|
|
|
else {
|
2007-03-08 01:20:04 +03:00
|
|
|
#ifdef GATEWAY
|
|
|
|
if (m->m_flags & M_CANFASTFWD)
|
|
|
|
ip6flow_create(&ip6_forward_rt, m);
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
if (mcopy)
|
|
|
|
goto freecopy;
|
|
|
|
}
|
|
|
|
}
|
2001-06-12 19:12:33 +04:00
|
|
|
|
|
|
|
senderr:
|
1999-06-28 10:36:47 +04:00
|
|
|
if (mcopy == NULL)
|
|
|
|
return;
|
|
|
|
switch (error) {
|
|
|
|
case 0:
|
|
|
|
if (type == ND_REDIRECT) {
|
|
|
|
icmp6_redirect_output(mcopy, rt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
goto freecopy;
|
|
|
|
|
|
|
|
case EMSGSIZE:
|
|
|
|
/* xxx MTU is constant in PPP? */
|
|
|
|
goto freecopy;
|
|
|
|
|
|
|
|
case ENOBUFS:
|
|
|
|
/* Tell source to slow down like source quench in IP? */
|
|
|
|
goto freecopy;
|
|
|
|
|
|
|
|
case ENETUNREACH: /* shouldn't happen, checked above */
|
|
|
|
case EHOSTUNREACH:
|
|
|
|
case ENETDOWN:
|
|
|
|
case EHOSTDOWN:
|
|
|
|
default:
|
|
|
|
type = ICMP6_DST_UNREACH;
|
|
|
|
code = ICMP6_DST_UNREACH_ADDR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
icmp6_error(mcopy, type, code, 0);
|
|
|
|
return;
|
|
|
|
|
|
|
|
freecopy:
|
|
|
|
m_freem(mcopy);
|
1999-12-13 18:17:17 +03:00
|
|
|
return;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|