2005-01-07 02:30:35 +00:00
|
|
|
/*-
|
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"
|
2011-08-20 17:05:11 +00:00
|
|
|
#include "opt_ipfw.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>
|
|
|
|
|
2007-07-03 12:13:45 +00:00
|
|
|
#ifdef IPSEC
|
2014-12-11 19:09:57 +00:00
|
|
|
#include <netinet6/ip6_ipsec.h>
|
2002-10-16 02:25:05 +00:00
|
|
|
#include <netipsec/ipsec.h>
|
|
|
|
#include <netipsec/ipsec6.h>
|
|
|
|
#include <netipsec/key.h>
|
2007-07-03 12:13:45 +00:00
|
|
|
#endif /* IPSEC */
|
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;
|
2007-07-03 12:13:45 +00:00
|
|
|
#ifdef IPSEC
|
1999-11-22 02:45:11 +00:00
|
|
|
struct secpolicy *sp = NULL;
|
2011-08-20 17:05:11 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCTP
|
|
|
|
int sw_csum;
|
|
|
|
#endif
|
|
|
|
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;
|
|
|
|
}
|
2014-12-11 19:09:57 +00:00
|
|
|
#ifdef IPSEC
|
|
|
|
/*
|
|
|
|
* Check if this packet has an active SA and needs to be dropped
|
|
|
|
* instead of forwarded.
|
|
|
|
*/
|
|
|
|
if (ip6_ipsec_fwd(m) != 0) {
|
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif /* IPSEC */
|
1999-11-22 02:45:11 +00:00
|
|
|
|
2005-08-10 09:13:35 +00:00
|
|
|
#ifdef IPSTEALTH
|
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_ip6stealth) {
|
2005-08-10 09:13:35 +00:00
|
|
|
#endif
|
1999-11-22 02:45:11 +00:00
|
|
|
if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
|
|
|
|
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
|
|
|
icmp6_error(m, ICMP6_TIME_EXCEEDED,
|
|
|
|
ICMP6_TIME_EXCEED_TRANSIT, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ip6->ip6_hlim -= IPV6_HLIMDEC;
|
|
|
|
|
2005-08-10 09:13:35 +00:00
|
|
|
#ifdef IPSTEALTH
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
|
|
|
|
|
2007-07-03 12:13:45 +00:00
|
|
|
#ifdef IPSEC
|
1999-11-22 02:45:11 +00:00
|
|
|
/* get a security policy for this packet */
|
2014-12-11 18:35:34 +00:00
|
|
|
sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, &error);
|
1999-11-22 02:45:11 +00:00
|
|
|
if (sp == NULL) {
|
2013-07-23 14:14:24 +00:00
|
|
|
IPSEC6STAT_INC(ips_out_inval);
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
2000-07-04 16:35:15 +00:00
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
|
|
|
|
/* check policy */
|
|
|
|
switch (sp->policy) {
|
|
|
|
case IPSEC_POLICY_DISCARD:
|
|
|
|
/*
|
|
|
|
* This packet is just discarded.
|
|
|
|
*/
|
2013-07-23 14:14:24 +00:00
|
|
|
IPSEC6STAT_INC(ips_out_polvio);
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
2007-07-01 11:41:27 +00:00
|
|
|
KEY_FREESP(&sp);
|
2000-07-04 16:35:15 +00:00
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_BYPASS:
|
|
|
|
case IPSEC_POLICY_NONE:
|
|
|
|
/* no need to do IPsec. */
|
2007-07-01 11:41:27 +00:00
|
|
|
KEY_FREESP(&sp);
|
1999-11-22 02:45:11 +00:00
|
|
|
goto skip_ipsec;
|
2000-07-04 16:35:15 +00:00
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
|
|
|
if (sp->req == NULL) {
|
|
|
|
/* XXX should be panic ? */
|
|
|
|
printf("ip6_forward: No IPsec request specified.\n");
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
2007-07-01 11:41:27 +00:00
|
|
|
KEY_FREESP(&sp);
|
2000-07-04 16:35:15 +00:00
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* do IPsec */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
|
|
|
default:
|
|
|
|
/* should be panic ?? */
|
|
|
|
printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
|
2007-07-01 11:41:27 +00:00
|
|
|
KEY_FREESP(&sp);
|
1999-11-22 02:45:11 +00:00
|
|
|
goto skip_ipsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
- 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 ipsecrequest *isr = NULL;
|
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
|
|
|
/*
|
|
|
|
* when the kernel forwards a packet, it is not proper to apply
|
2015-04-27 00:55:56 +00:00
|
|
|
* IPsec transport mode to the packet. This check avoid from this.
|
- 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
|
|
|
* at present, if there is even a transport mode SA request in the
|
|
|
|
* security policy, the kernel does not apply IPsec to the packet.
|
|
|
|
* this check is not enough because the following case is valid.
|
|
|
|
* ipsec esp/tunnel/xxx-xxx/require esp/transport//require;
|
|
|
|
*/
|
|
|
|
for (isr = sp->req; isr; isr = isr->next) {
|
2004-02-19 14:57:22 +00:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_ANY)
|
|
|
|
goto doipsectunnel;
|
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
|
|
|
|
goto doipsectunnel;
|
- 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
|
|
|
}
|
|
|
|
|
2004-02-19 14:57:22 +00:00
|
|
|
/*
|
|
|
|
* if there's no need for tunnel mode IPsec, skip.
|
|
|
|
*/
|
|
|
|
if (!isr)
|
|
|
|
goto skip_ipsec;
|
|
|
|
|
|
|
|
doipsectunnel:
|
1999-11-22 02:45:11 +00:00
|
|
|
/*
|
|
|
|
* All the extension headers will become inaccessible
|
|
|
|
* (since they can be encrypted).
|
|
|
|
* Don't panic, we need no more updates to extension headers
|
|
|
|
* on inner IPv6 packet (since they are now encapsulated).
|
|
|
|
*
|
|
|
|
* IPv6 [ESP|AH] IPv6 [extension headers] payload
|
|
|
|
*/
|
|
|
|
|
2014-05-28 12:45:27 +00:00
|
|
|
/*
|
|
|
|
* If we need to encapsulate the packet, do it here
|
|
|
|
* ipsec6_proces_packet will send the packet using ip6_output
|
|
|
|
*/
|
|
|
|
error = ipsec6_process_packet(m, sp->req);
|
2015-04-27 00:55:56 +00:00
|
|
|
/* Release SP if an error occured */
|
|
|
|
if (error != 0)
|
|
|
|
KEY_FREESP(&sp);
|
2014-05-28 12:45:27 +00:00
|
|
|
if (error == EJUSTRETURN) {
|
|
|
|
/*
|
|
|
|
* We had a SP with a level of 'use' and no SA. We
|
|
|
|
* will just continue to process the packet without
|
|
|
|
* IPsec processing.
|
|
|
|
*/
|
|
|
|
error = 0;
|
|
|
|
goto skip_ipsec;
|
|
|
|
}
|
|
|
|
|
1999-11-22 02:45:11 +00:00
|
|
|
if (error) {
|
2014-05-28 12:45:27 +00:00
|
|
|
/* mbuf is already reclaimed in ipsec6_process_packet. */
|
1999-11-22 02:45:11 +00:00
|
|
|
switch (error) {
|
|
|
|
case EHOSTUNREACH:
|
|
|
|
case ENETUNREACH:
|
|
|
|
case EMSGSIZE:
|
|
|
|
case ENOBUFS:
|
|
|
|
case ENOMEM:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("ip6_output (ipsec): error code %d\n", error);
|
2003-10-08 18:26:08 +00:00
|
|
|
/* FALLTHROUGH */
|
1999-11-22 02:45:11 +00:00
|
|
|
case ENOENT:
|
|
|
|
/* don't show these error codes to the user */
|
|
|
|
break;
|
|
|
|
}
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_cantforward);
|
2000-07-04 16:35:15 +00:00
|
|
|
if (mcopy) {
|
|
|
|
#if 0
|
|
|
|
/* XXX: what icmp ? */
|
|
|
|
#else
|
|
|
|
m_freem(mcopy);
|
|
|
|
#endif
|
|
|
|
}
|
1999-11-22 02:45:11 +00:00
|
|
|
return;
|
2007-07-01 11:41:27 +00:00
|
|
|
} else {
|
2007-07-05 16:29:40 +00:00
|
|
|
/*
|
|
|
|
* In the FAST IPSec case we have already
|
2007-07-01 11:41:27 +00:00
|
|
|
* re-injected the packet and it has been freed
|
2007-07-05 16:29:40 +00:00
|
|
|
* by the ipsec_done() function. So, just clean
|
2007-07-01 11:41:27 +00:00
|
|
|
* up after ourselves.
|
|
|
|
*/
|
|
|
|
m = NULL;
|
|
|
|
goto freecopy;
|
1999-11-22 02:45:11 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-31 12:24:53 +00:00
|
|
|
skip_ipsec:
|
- 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));
|
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
|
|
|
}
|
2009-02-01 21:11:08 +00:00
|
|
|
rt = rin6.ro_rt;
|
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;
|
2004-08-27 15:16:24 +00:00
|
|
|
/* Run through list of hooks for output packets. */
|
2009-10-11 05:59:43 +00:00
|
|
|
error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, 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;
|
2015-04-06 19:08:44 +00:00
|
|
|
else
|
2011-08-20 17:05:11 +00:00
|
|
|
goto again; /* Redo the routing table lookup. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
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);
|
|
|
|
if (mcopy) {
|
|
|
|
u_long mtu;
|
|
|
|
#ifdef IPSEC
|
|
|
|
size_t ipsechdrsiz;
|
|
|
|
#endif /* IPSEC */
|
|
|
|
|
|
|
|
mtu = IN6_LINKMTU(rt->rt_ifp);
|
|
|
|
#ifdef IPSEC
|
|
|
|
/*
|
|
|
|
* When we do IPsec tunnel ingress, we need to play
|
|
|
|
* with the link value (decrement IPsec header size
|
|
|
|
* from mtu value). The code is much simpler than v4
|
|
|
|
* case, as we have the outgoing interface for
|
|
|
|
* encapsulated packet as "rt->rt_ifp".
|
|
|
|
*/
|
|
|
|
ipsechdrsiz = ipsec_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND,
|
|
|
|
NULL);
|
|
|
|
if (ipsechdrsiz < mtu)
|
|
|
|
mtu -= ipsechdrsiz;
|
|
|
|
/*
|
|
|
|
* if mtu becomes less than minimum MTU,
|
|
|
|
* tell minimum MTU (and I'll need to fragment it).
|
|
|
|
*/
|
|
|
|
if (mtu < IPV6_MMTU)
|
|
|
|
mtu = IPV6_MMTU;
|
|
|
|
#endif /* IPSEC */
|
|
|
|
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|