2005-01-07 02:30:35 +00:00
|
|
|
/*-
|
2017-11-20 19:43:44 +00:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
1999-11-22 02:45:11 +00:00
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* 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.
|
2007-12-10 16:03:40 +00:00
|
|
|
*
|
|
|
|
* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $
|
1999-11-22 02:45:11 +00:00
|
|
|
*/
|
|
|
|
|
2007-12-10 16:03:40 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
#include "opt_inet.h"
|
|
|
|
#include "opt_inet6.h"
|
1999-12-22 19:13:38 +00:00
|
|
|
#include "opt_ipsec.h"
|
2005-08-10 09:13:35 +00:00
|
|
|
#include "opt_ipstealth.h"
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <sys/malloc.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/domain.h>
|
|
|
|
#include <sys/protosw.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/time.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <sys/kernel.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <sys/syslog.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
2013-10-26 17:58:36 +00:00
|
|
|
#include <net/if_var.h>
|
2011-08-20 17:05:11 +00:00
|
|
|
#include <net/netisr.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <net/route.h>
|
2001-10-15 14:16:18 +00:00
|
|
|
#include <net/pfil.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet/ip_var.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <netinet6/in6_var.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet/ip6.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <netinet6/ip6_var.h>
|
2005-07-25 12:31:43 +00:00
|
|
|
#include <netinet6/scope6_var.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet/icmp6.h>
|
1999-11-22 02:45:11 +00:00
|
|
|
#include <netinet6/nd6.h>
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <netinet/in_pcb.h>
|
|
|
|
|
2017-02-06 08:49:57 +00:00
|
|
|
#include <netipsec/ipsec_support.h>
|
2002-10-16 02:25:05 +00:00
|
|
|
|
1999-11-22 02:45:11 +00: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-07-05 16:23:49 +00:00
|
|
|
ip6_forward(struct mbuf *m, int srcrt)
|
1999-11-22 02:45:11 +00:00
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
- cleanup SP refcnt issue.
- share policy-on-socket for listening socket.
- don't copy policy-on-socket at all. secpolicy no longer contain
spidx, which saves a lot of memory.
- deep-copy pcb policy if it is an ipsec policy. assign ID field to
all SPD entries. make it possible for racoon to grab SPD entry on
pcb.
- fixed the order of searching SA table for packets.
- fixed to get a security association header. a mode is always needed
to compare them.
- fixed that the incorrect time was set to
sadb_comb_{hard|soft}_usetime.
- disallow port spec for tunnel mode policy (as we don't reassemble).
- an user can define a policy-id.
- clear enc/auth key before freeing.
- fixed that the kernel crashed when key_spdacquire() was called
because key_spdacquire() had been implemented imcopletely.
- preparation for 64bit sequence number.
- maintain ordered list of SA, based on SA id.
- cleanup secasvar management; refcnt is key.c responsibility;
alloc/free is keydb.c responsibility.
- cleanup, avoid double-loop.
- use hash for spi-based lookup.
- mark persistent SP "persistent".
XXX in theory refcnt should do the right thing, however, we have
"spdflush" which would touch all SPs. another solution would be to
de-register persistent SPs from sptree.
- u_short -> u_int16_t
- reduce kernel stack usage by auto variable secasindex.
- clarify function name confusion. ipsec_*_policy ->
ipsec_*_pcbpolicy.
- avoid variable name confusion.
(struct inpcbpolicy *)pcb_sp, spp (struct secpolicy **), sp (struct
secpolicy *)
- count number of ipsec encapsulations on ipsec4_output, so that we
can tell ip_output() how to handle the packet further.
- When the value of the ul_proto is ICMP or ICMPV6, the port field in
"src" of the spidx specifies ICMP type, and the port field in "dst"
of the spidx specifies ICMP code.
- avoid from applying IPsec transport mode to the packets when the
kernel forwards the packets.
Tested by: nork
Obtained from: KAME
2003-11-04 16:02:05 +00:00
|
|
|
struct sockaddr_in6 *dst = NULL;
|
|
|
|
struct rtentry *rt = NULL;
|
2009-02-01 21:11:08 +00:00
|
|
|
struct route_in6 rin6;
|
1999-11-22 02:45:11 +00:00
|
|
|
int error, type = 0, code = 0;
|
2000-07-04 16:35:15 +00:00
|
|
|
struct mbuf *mcopy = NULL;
|
|
|
|
struct ifnet *origifp; /* maybe unnecessary */
|
2005-07-25 12:31:43 +00:00
|
|
|
u_int32_t inzone, outzone;
|
2011-08-20 17:05:11 +00:00
|
|
|
struct in6_addr src_in6, dst_in6, odst;
|
|
|
|
struct m_tag *fwd_tag;
|
2006-12-12 12:17:58 +00:00
|
|
|
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
/*
|
|
|
|
* Do not forward packets to multicast destination (should be handled
|
|
|
|
* by ip6_mforward().
|
|
|
|
* Do not forward packets with unspecified source. It was discussed
|
2003-10-08 18:26:08 +00:00
|
|
|
* in July 2000, on the ipngwg mailing list.
|
2001-06-11 12:39:29 +00:00
|
|
|
*/
|
2000-07-04 16:35:15 +00:00
|
|
|
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
|
2001-06-11 12:39:29 +00:00
|
|
|
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
|
|
|
|
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
1999-11-22 02:45:11 +00:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
2013-08-05 20:13:02 +00:00
|
|
|
if (V_ip6_log_time + V_ip6_log_interval < time_uptime) {
|
|
|
|
V_ip6_log_time = time_uptime;
|
1999-11-22 02:45:11 +00:00
|
|
|
log(LOG_DEBUG,
|
|
|
|
"cannot forward "
|
|
|
|
"from %s to %s nxt %d received on %s\n",
|
2006-12-12 12:17:58 +00:00
|
|
|
ip6_sprintf(ip6bufs, &ip6->ip6_src),
|
|
|
|
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
|
1999-11-22 02:45:11 +00:00
|
|
|
ip6->ip6_nxt,
|
|
|
|
if_name(m->m_pkthdr.rcvif));
|
|
|
|
}
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-06 08:49:57 +00:00
|
|
|
if (
|
2005-08-10 09:13:35 +00:00
|
|
|
#ifdef IPSTEALTH
|
2017-02-06 08:49:57 +00:00
|
|
|
V_ip6stealth == 0 &&
|
2005-08-10 09:13:35 +00:00
|
|
|
#endif
|
2017-02-06 08:49:57 +00:00
|
|
|
ip6->ip6_hlim <= IPV6_HLIMDEC) {
|
1999-11-22 02:45:11 +00:00
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
|
|
|
icmp6_error(m, ICMP6_TIME_EXCEEDED,
|
2017-02-06 08:49:57 +00:00
|
|
|
ICMP6_TIME_EXCEED_TRANSIT, 0);
|
1999-11-22 02:45:11 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-08-10 09:13:35 +00:00
|
|
|
|
2000-07-04 16:35:15 +00: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.
|
|
|
|
*/
|
2016-09-15 07:41:48 +00:00
|
|
|
mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
|
|
|
|
M_NOWAIT);
|
2017-02-06 08:49:57 +00:00
|
|
|
#ifdef IPSTEALTH
|
|
|
|
if (V_ip6stealth == 0)
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
2017-02-06 08:49:57 +00:00
|
|
|
ip6->ip6_hlim -= IPV6_HLIMDEC;
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2017-02-06 08:49:57 +00:00
|
|
|
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
|
|
|
if (IPSEC_ENABLED(ipv6)) {
|
|
|
|
if ((error = IPSEC_FORWARD(ipv6, m)) != 0) {
|
|
|
|
/* mbuf consumed by IPsec */
|
2000-07-04 16:35:15 +00:00
|
|
|
m_freem(mcopy);
|
2017-02-06 08:49:57 +00:00
|
|
|
if (error != EINPROGRESS)
|
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
1999-11-22 02:45:11 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-02-06 08:49:57 +00:00
|
|
|
/* No IPsec processing required */
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
- cleanup SP refcnt issue.
- share policy-on-socket for listening socket.
- don't copy policy-on-socket at all. secpolicy no longer contain
spidx, which saves a lot of memory.
- deep-copy pcb policy if it is an ipsec policy. assign ID field to
all SPD entries. make it possible for racoon to grab SPD entry on
pcb.
- fixed the order of searching SA table for packets.
- fixed to get a security association header. a mode is always needed
to compare them.
- fixed that the incorrect time was set to
sadb_comb_{hard|soft}_usetime.
- disallow port spec for tunnel mode policy (as we don't reassemble).
- an user can define a policy-id.
- clear enc/auth key before freeing.
- fixed that the kernel crashed when key_spdacquire() was called
because key_spdacquire() had been implemented imcopletely.
- preparation for 64bit sequence number.
- maintain ordered list of SA, based on SA id.
- cleanup secasvar management; refcnt is key.c responsibility;
alloc/free is keydb.c responsibility.
- cleanup, avoid double-loop.
- use hash for spi-based lookup.
- mark persistent SP "persistent".
XXX in theory refcnt should do the right thing, however, we have
"spdflush" which would touch all SPs. another solution would be to
de-register persistent SPs from sptree.
- u_short -> u_int16_t
- reduce kernel stack usage by auto variable secasindex.
- clarify function name confusion. ipsec_*_policy ->
ipsec_*_pcbpolicy.
- avoid variable name confusion.
(struct inpcbpolicy *)pcb_sp, spp (struct secpolicy **), sp (struct
secpolicy *)
- count number of ipsec encapsulations on ipsec4_output, so that we
can tell ip_output() how to handle the packet further.
- When the value of the ul_proto is ICMP or ICMPV6, the port field in
"src" of the spidx specifies ICMP type, and the port field in "dst"
of the spidx specifies ICMP code.
- avoid from applying IPsec transport mode to the packets when the
kernel forwards the packets.
Tested by: nork
Obtained from: KAME
2003-11-04 16:02:05 +00:00
|
|
|
#endif
|
2011-08-20 17:05:11 +00:00
|
|
|
again:
|
2009-02-01 21:11:08 +00:00
|
|
|
bzero(&rin6, sizeof(struct route_in6));
|
|
|
|
dst = (struct sockaddr_in6 *)&rin6.ro_dst;
|
|
|
|
dst->sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
dst->sin6_family = AF_INET6;
|
|
|
|
dst->sin6_addr = ip6->ip6_dst;
|
2011-08-20 17:05:11 +00:00
|
|
|
again2:
|
2012-02-03 13:08:44 +00:00
|
|
|
rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
|
2016-01-20 11:25:30 +00:00
|
|
|
rt = rin6.ro_rt;
|
2009-02-01 21:11:08 +00:00
|
|
|
if (rin6.ro_rt != NULL)
|
|
|
|
RT_UNLOCK(rin6.ro_rt);
|
|
|
|
else {
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_noroute);
|
2009-02-01 21:11:08 +00:00
|
|
|
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
|
|
|
|
if (mcopy) {
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_NOROUTE, 0);
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
2009-02-01 21:11:08 +00:00
|
|
|
goto bad;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
2005-07-25 12:31:43 +00: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-04.txt, Section 3.1]
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2005-07-25 12:31:43 +00:00
|
|
|
src_in6 = ip6->ip6_src;
|
|
|
|
if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
|
- cleanup SP refcnt issue.
- share policy-on-socket for listening socket.
- don't copy policy-on-socket at all. secpolicy no longer contain
spidx, which saves a lot of memory.
- deep-copy pcb policy if it is an ipsec policy. assign ID field to
all SPD entries. make it possible for racoon to grab SPD entry on
pcb.
- fixed the order of searching SA table for packets.
- fixed to get a security association header. a mode is always needed
to compare them.
- fixed that the incorrect time was set to
sadb_comb_{hard|soft}_usetime.
- disallow port spec for tunnel mode policy (as we don't reassemble).
- an user can define a policy-id.
- clear enc/auth key before freeing.
- fixed that the kernel crashed when key_spdacquire() was called
because key_spdacquire() had been implemented imcopletely.
- preparation for 64bit sequence number.
- maintain ordered list of SA, based on SA id.
- cleanup secasvar management; refcnt is key.c responsibility;
alloc/free is keydb.c responsibility.
- cleanup, avoid double-loop.
- use hash for spi-based lookup.
- mark persistent SP "persistent".
XXX in theory refcnt should do the right thing, however, we have
"spdflush" which would touch all SPs. another solution would be to
de-register persistent SPs from sptree.
- u_short -> u_int16_t
- reduce kernel stack usage by auto variable secasindex.
- clarify function name confusion. ipsec_*_policy ->
ipsec_*_pcbpolicy.
- avoid variable name confusion.
(struct inpcbpolicy *)pcb_sp, spp (struct secpolicy **), sp (struct
secpolicy *)
- count number of ipsec encapsulations on ipsec4_output, so that we
can tell ip_output() how to handle the packet further.
- When the value of the ul_proto is ICMP or ICMPV6, the port field in
"src" of the spidx specifies ICMP type, and the port field in "dst"
of the spidx specifies ICMP code.
- avoid from applying IPsec transport mode to the packets when the
kernel forwards the packets.
Tested by: nork
Obtained from: KAME
2003-11-04 16:02:05 +00:00
|
|
|
/* XXX: this should not happen */
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
|
|
|
IP6STAT_INC(ip6s_badscope);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto bad;
|
- cleanup SP refcnt issue.
- share policy-on-socket for listening socket.
- don't copy policy-on-socket at all. secpolicy no longer contain
spidx, which saves a lot of memory.
- deep-copy pcb policy if it is an ipsec policy. assign ID field to
all SPD entries. make it possible for racoon to grab SPD entry on
pcb.
- fixed the order of searching SA table for packets.
- fixed to get a security association header. a mode is always needed
to compare them.
- fixed that the incorrect time was set to
sadb_comb_{hard|soft}_usetime.
- disallow port spec for tunnel mode policy (as we don't reassemble).
- an user can define a policy-id.
- clear enc/auth key before freeing.
- fixed that the kernel crashed when key_spdacquire() was called
because key_spdacquire() had been implemented imcopletely.
- preparation for 64bit sequence number.
- maintain ordered list of SA, based on SA id.
- cleanup secasvar management; refcnt is key.c responsibility;
alloc/free is keydb.c responsibility.
- cleanup, avoid double-loop.
- use hash for spi-based lookup.
- mark persistent SP "persistent".
XXX in theory refcnt should do the right thing, however, we have
"spdflush" which would touch all SPs. another solution would be to
de-register persistent SPs from sptree.
- u_short -> u_int16_t
- reduce kernel stack usage by auto variable secasindex.
- clarify function name confusion. ipsec_*_policy ->
ipsec_*_pcbpolicy.
- avoid variable name confusion.
(struct inpcbpolicy *)pcb_sp, spp (struct secpolicy **), sp (struct
secpolicy *)
- count number of ipsec encapsulations on ipsec4_output, so that we
can tell ip_output() how to handle the packet further.
- When the value of the ul_proto is ICMP or ICMPV6, the port field in
"src" of the spidx specifies ICMP type, and the port field in "dst"
of the spidx specifies ICMP code.
- avoid from applying IPsec transport mode to the packets when the
kernel forwards the packets.
Tested by: nork
Obtained from: KAME
2003-11-04 16:02:05 +00:00
|
|
|
}
|
2005-07-25 12:31:43 +00:00
|
|
|
if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
|
|
|
IP6STAT_INC(ip6s_badscope);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto bad;
|
2005-07-25 12:31:43 +00:00
|
|
|
}
|
2014-06-08 09:08:51 +00:00
|
|
|
if (inzone != outzone) {
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
|
|
|
IP6STAT_INC(ip6s_badscope);
|
2000-07-04 16:35:15 +00:00
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
|
|
|
|
|
2013-08-05 20:13:02 +00:00
|
|
|
if (V_ip6_log_time + V_ip6_log_interval < time_uptime) {
|
|
|
|
V_ip6_log_time = time_uptime;
|
2000-07-04 16:35:15 +00:00
|
|
|
log(LOG_DEBUG,
|
|
|
|
"cannot forward "
|
|
|
|
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
|
2006-12-12 12:17:58 +00:00
|
|
|
ip6_sprintf(ip6bufs, &ip6->ip6_src),
|
|
|
|
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
|
2000-07-04 16:35:15 +00:00
|
|
|
ip6->ip6_nxt,
|
|
|
|
if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
|
|
|
|
}
|
|
|
|
if (mcopy)
|
|
|
|
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto bad;
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
2005-07-25 12:31:43 +00: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;
|
|
|
|
if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
|
|
|
|
in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
|
|
|
|
inzone != outzone) {
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
|
|
|
IP6STAT_INC(ip6s_badscope);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto bad;
|
2005-07-25 12:31:43 +00:00
|
|
|
}
|
|
|
|
|
1999-11-22 02:45:11 +00: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.
|
|
|
|
*/
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
if (V_ip6_sendredirects && rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
|
2001-06-11 12:39:29 +00:00
|
|
|
(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);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto bad;
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
type = ND_REDIRECT;
|
2001-06-11 12:39:29 +00:00
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2000-07-04 16:35:15 +00: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-06-11 12:39:29 +00:00
|
|
|
* link identifiers, we can do this stuff after making a copy for
|
|
|
|
* returning an error.
|
2000-07-04 16:35:15 +00: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)
|
|
|
|
* XXX: it is common to route invalid packets to loopback.
|
|
|
|
* also, the codepath will be visited on use of ::1 in
|
|
|
|
* rthdr. (itojun)
|
|
|
|
*/
|
|
|
|
#if 1
|
|
|
|
if (0)
|
|
|
|
#else
|
|
|
|
if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
printf("ip6_forward: outgoing interface is loopback. "
|
2003-10-08 18:26:08 +00:00
|
|
|
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
|
2006-12-12 12:17:58 +00:00
|
|
|
ip6_sprintf(ip6bufs, &ip6->ip6_src),
|
|
|
|
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
|
2003-10-08 18:26:08 +00:00
|
|
|
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
|
|
|
|
if_name(rt->rt_ifp));
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
/* we can just use rcvif in forwarding. */
|
|
|
|
origifp = m->m_pkthdr.rcvif;
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
origifp = rt->rt_ifp;
|
2001-06-11 12:39:29 +00: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-07-04 16:35:15 +00:00
|
|
|
|
2004-08-27 15:16:24 +00:00
|
|
|
/* Jump over all PFIL processing if hooks are not active. */
|
2009-10-11 05:59:43 +00:00
|
|
|
if (!PFIL_HOOKED(&V_inet6_pfil_hook))
|
2004-08-27 15:16:24 +00:00
|
|
|
goto pass;
|
|
|
|
|
2011-08-20 17:05:11 +00:00
|
|
|
odst = ip6->ip6_dst;
|
2018-03-23 16:56:44 +00:00
|
|
|
/* Run through list of hooks for forwarded packets. */
|
|
|
|
error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT,
|
|
|
|
PFIL_FWD, NULL);
|
2014-03-31 14:27:22 +00:00
|
|
|
if (error != 0 || m == NULL)
|
|
|
|
goto freecopy; /* consumed by filter */
|
2003-09-23 17:54:04 +00:00
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
2001-10-15 14:16:18 +00:00
|
|
|
|
2011-08-20 17:05:11 +00:00
|
|
|
/* See if destination IP address was changed by packet filter. */
|
|
|
|
if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
|
|
|
|
m->m_flags |= M_SKIP_FIREWALL;
|
|
|
|
/* If destination is now ourself drop to ip6_input(). */
|
2015-04-06 19:08:44 +00:00
|
|
|
if (in6_localip(&ip6->ip6_dst))
|
2011-08-20 17:05:11 +00:00
|
|
|
m->m_flags |= M_FASTFWD_OURS;
|
2016-01-20 11:25:30 +00:00
|
|
|
else {
|
|
|
|
RTFREE(rt);
|
2011-08-20 17:05:11 +00:00
|
|
|
goto again; /* Redo the routing table lookup. */
|
2016-01-20 11:25:30 +00:00
|
|
|
}
|
2011-08-20 17:05:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* See if local, if yes, send it to netisr. */
|
|
|
|
if (m->m_flags & M_FASTFWD_OURS) {
|
|
|
|
if (m->m_pkthdr.rcvif == NULL)
|
|
|
|
m->m_pkthdr.rcvif = V_loif;
|
It turns out that too many drivers are not only parsing the L2/3/4
headers for TSO but also for generic checksum offloading. Ideally we
would only have one common function shared amongst all drivers, and
perhaps when updating them for IPv6 we should introduce that.
Eventually we should provide the meta information along with mbufs to
avoid (re-)parsing entirely.
To not break IPv6 (checksums and offload) and to be able to MFC the
changes without risking to hurt 3rd party drivers, duplicate the v4
framework, as other OSes have done as well.
Introduce interface capability flags for TX/RX checksum offload with
IPv6, to allow independent toggling (where possible). Add CSUM_*_IPV6
flags for UDP/TCP over IPv6, and reserve further for SCTP, and IPv6
fragmentation. Define CSUM_DELAY_DATA_IPV6 as we do for legacy IP and
add an alias for CSUM_DATA_VALID_IPV6.
This pretty much brings IPv6 handling in line with IPv4.
TSO is still handled in a different way and not via if_hwassist.
Update ifconfig to allow (un)setting of the new capability flags.
Update loopback to announce the new capabilities and if_hwassist flags.
Individual driver updates will have to follow, as will SCTP.
Reported by: gallatin, dim, ..
Reviewed by: gallatin (glanced at?)
MFC after: 3 days
X-MFC with: r235961,235959,235958
2012-05-28 09:30:13 +00:00
|
|
|
if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
|
2011-08-20 17:05:11 +00:00
|
|
|
m->m_pkthdr.csum_flags |=
|
It turns out that too many drivers are not only parsing the L2/3/4
headers for TSO but also for generic checksum offloading. Ideally we
would only have one common function shared amongst all drivers, and
perhaps when updating them for IPv6 we should introduce that.
Eventually we should provide the meta information along with mbufs to
avoid (re-)parsing entirely.
To not break IPv6 (checksums and offload) and to be able to MFC the
changes without risking to hurt 3rd party drivers, duplicate the v4
framework, as other OSes have done as well.
Introduce interface capability flags for TX/RX checksum offload with
IPv6, to allow independent toggling (where possible). Add CSUM_*_IPV6
flags for UDP/TCP over IPv6, and reserve further for SCTP, and IPv6
fragmentation. Define CSUM_DELAY_DATA_IPV6 as we do for legacy IP and
add an alias for CSUM_DATA_VALID_IPV6.
This pretty much brings IPv6 handling in line with IPv4.
TSO is still handled in a different way and not via if_hwassist.
Update ifconfig to allow (un)setting of the new capability flags.
Update loopback to announce the new capabilities and if_hwassist flags.
Individual driver updates will have to follow, as will SCTP.
Reported by: gallatin, dim, ..
Reviewed by: gallatin (glanced at?)
MFC after: 3 days
X-MFC with: r235961,235959,235958
2012-05-28 09:30:13 +00:00
|
|
|
CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
|
2011-08-20 17:05:11 +00:00
|
|
|
m->m_pkthdr.csum_data = 0xffff;
|
|
|
|
}
|
|
|
|
#ifdef SCTP
|
2012-05-30 20:56:07 +00:00
|
|
|
if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
|
|
|
|
m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
|
|
|
|
#endif
|
2011-08-20 17:05:11 +00:00
|
|
|
error = netisr_queue(NETISR_IPV6, m);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/* Or forward to some other address? */
|
2012-11-02 01:20:55 +00:00
|
|
|
if ((m->m_flags & M_IP6_NEXTHOP) &&
|
|
|
|
(fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
|
2011-08-20 17:05:11 +00:00
|
|
|
dst = (struct sockaddr_in6 *)&rin6.ro_dst;
|
|
|
|
bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6));
|
|
|
|
m->m_flags |= M_SKIP_FIREWALL;
|
2012-11-02 01:20:55 +00:00
|
|
|
m->m_flags &= ~M_IP6_NEXTHOP;
|
2011-08-20 17:05:11 +00:00
|
|
|
m_tag_delete(m, fwd_tag);
|
2016-01-20 11:25:30 +00:00
|
|
|
RTFREE(rt);
|
2011-08-20 17:05:11 +00:00
|
|
|
goto again2;
|
|
|
|
}
|
|
|
|
|
2004-08-27 15:16:24 +00:00
|
|
|
pass:
|
2015-04-07 20:29:03 +00:00
|
|
|
/* See if the size was changed by the packet filter. */
|
|
|
|
if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
|
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
|
2017-02-06 08:49:57 +00:00
|
|
|
if (mcopy)
|
|
|
|
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,
|
|
|
|
IN6_LINKMTU(rt->rt_ifp));
|
2015-04-07 20:29:03 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2015-11-15 16:02:22 +00:00
|
|
|
error = nd6_output_ifp(rt->rt_ifp, origifp, m, dst, NULL);
|
1999-11-22 02:45:11 +00:00
|
|
|
if (error) {
|
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
1999-11-22 02:45:11 +00:00
|
|
|
} else {
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_forward);
|
1999-11-22 02:45:11 +00:00
|
|
|
in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
|
|
|
|
if (type)
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_redirectsent);
|
1999-11-22 02:45:11 +00:00
|
|
|
else {
|
|
|
|
if (mcopy)
|
|
|
|
goto freecopy;
|
|
|
|
}
|
|
|
|
}
|
2003-10-08 18:26:08 +00:00
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
if (mcopy == NULL)
|
2009-02-01 21:11:08 +00:00
|
|
|
goto out;
|
1999-11-22 02:45:11 +00:00
|
|
|
switch (error) {
|
|
|
|
case 0:
|
|
|
|
if (type == ND_REDIRECT) {
|
|
|
|
icmp6_redirect_output(mcopy, rt);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto out;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
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);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto out;
|
1999-11-22 02:45:11 +00:00
|
|
|
|
|
|
|
freecopy:
|
|
|
|
m_freem(mcopy);
|
2009-02-01 21:11:08 +00:00
|
|
|
goto out;
|
|
|
|
bad:
|
|
|
|
m_freem(m);
|
|
|
|
out:
|
2014-06-08 09:08:51 +00:00
|
|
|
if (rt != NULL)
|
2009-02-01 21:11:08 +00:00
|
|
|
RTFREE(rt);
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|