📄 ip6_output.c
字号:
//==========================================================================
//
// src/sys/netinet6/ip6_output.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/* $KAME: ip6_output.c,v 1.272 2001/12/26 01:03:28 jinmei Exp $ */
/*
* 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.
*/
/*
* Copyright (c) 1982, 1986, 1988, 1990, 1993
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
#include <netinet/in_pcb.h>
#include <netinet6/nd6.h>
#include <netinet6/ip6protosw.h>
#include <netinet6/scope6_var.h>
#ifdef IPSEC
#ifdef __OpenBSD__
#include <netinet/ip_ah.h>
#include <netinet/ip_esp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <net/pfkeyv2.h>
extern u_int8_t get_sa_require __P((struct inpcb *));
extern int ipsec_auth_default_level;
extern int ipsec_esp_trans_default_level;
extern int ipsec_esp_network_default_level;
extern int ipsec_ipcomp_default_level;
#else
#include <netinet6/ipsec.h>
#include <netkey/key.h>
#endif
#endif /* IPSEC */
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
#include <netinet6/ip6_fw.h>
#endif
#ifdef MIP6
#include <sys/syslog.h>
#include <netinet6/mip6.h>
#endif /* MIP6 */
struct ip6_exthdrs {
struct mbuf *ip6e_ip6;
struct mbuf *ip6e_hbh;
struct mbuf *ip6e_dest1;
struct mbuf *ip6e_rthdr;
struct mbuf *ip6e_haddr; /* for MIP6 */
struct mbuf *ip6e_dest2;
};
static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **, int));
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
struct socket *, struct sockopt *));
static int ip6_getpcbopt __P((struct ip6_pktopts *, int, struct sockopt *));
#else
static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
struct socket *));
static int ip6_getpcbopt __P((struct ip6_pktopts *, int, struct mbuf **));
#endif
static int ip6_setpktoption __P((int, u_char *, int, struct ip6_pktopts *, int,
int, int));
static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *));
static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **));
static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int));
static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
struct ip6_frag **));
static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
#ifdef NEW_STRUCT_ROUTE
static int ip6_getpmtu __P((struct route *, struct route *, struct ifnet *,
struct in6_addr *, u_long *));
#else
static int ip6_getpmtu __P((struct route *, struct route *, struct ifnet *,
struct in6_addr *, u_long *));
#endif
#ifdef __bsdi__
#if _BSDI_VERSION < 199802
extern struct ifnet loif;
#else
extern struct ifnet *loifp;
#endif
#endif
#if defined(__NetBSD__)
extern struct ifnet loif[NLOOP];
#endif
/*
* IP6 output. The packet in mbuf chain m contains a skeletal IP6
* header (with pri, len, nxt, hlim, src, dst).
* This function may modify ver and hlim only.
* The mbuf chain containing the packet will be freed.
* The mbuf opt, if present, will not be freed.
*
* type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and
* nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one,
* which is rt_rmx.rmx_mtu.
*/
int
ip6_output(m0, opt, ro, flags, im6o, ifpp)
struct mbuf *m0;
struct ip6_pktopts *opt;
#ifdef NEW_STRUCT_ROUTE
struct route *ro;
#else
struct route_in6 *ro;
#endif
int flags;
struct ip6_moptions *im6o;
struct ifnet **ifpp; /* XXX: just for statistics */
{
struct ip6_hdr *ip6, *mhip6;
struct ifnet *ifp, *origifp;
struct mbuf *m = m0;
int hlen, tlen, len, off;
#ifdef NEW_STRUCT_ROUTE
struct route ip6route;
#else
struct route_in6 ip6route;
#endif
struct rtentry *rt = NULL;
struct sockaddr_in6 *dst;
int error = 0;
struct in6_ifaddr *ia = NULL;
u_long mtu;
u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
struct ip6_exthdrs exthdrs;
struct in6_addr finaldst;
#ifdef NEW_STRUCT_ROUTE
struct route *ro_pmtu = NULL;
#else
struct route_in6 *ro_pmtu = NULL;
#endif
int hdrsplit = 0;
#ifdef __OpenBSD__
u_int8_t sproto = 0;
#else
int needipsec = 0;
#endif
#if defined(__NetBSD__) && defined(PFIL_HOOKS)
struct packet_filter_hook *pfh;
struct mbuf *m1;
int rv;
#endif /* PFIL_HOOKS */
#if defined(__bsdi__) && _BSDI_VERSION < 199802
struct ifnet *loifp = &loif;
#endif
#ifdef MIP6
struct mip6_pktopts mip6opt;
#ifdef NEW_STRUCT_ROUTE
struct route mip6_ip6route;
#else
struct route_in6 mip6_ip6route;
#endif
#endif /* MIP6 */
#ifdef IPSEC
#ifdef __OpenBSD__
struct m_tag *mtag;
union sockaddr_union sdst;
struct tdb_ident *tdbi;
u_int32_t sspi;
struct inpcb *inp;
struct tdb *tdb;
int s;
inp = NULL; /* XXX */
if (inp && (inp->inp_flags & INP_IPV6) == 0)
panic("ip6_output: IPv4 pcb is passed");
#else
int needipsectun = 0;
struct socket *so;
struct secpolicy *sp = NULL;
/* for AH processing. stupid to have "socket" variable in IP layer... */
so = ipsec_getsocket(m);
(void)ipsec_setsocket(m, NULL);
ip6 = mtod(m, struct ip6_hdr *);
#endif
#endif /* IPSEC */
#define MAKE_EXTHDR(hp, mp) \
do { \
if (hp) { \
struct ip6_ext *eh = (struct ip6_ext *)(hp); \
error = ip6_copyexthdr((mp), (caddr_t)(hp), \
((eh)->ip6e_len + 1) << 3); \
if (error) \
goto freehdrs; \
} \
} while (0)
bzero(&exthdrs, sizeof(exthdrs));
if (opt) {
/* Hop-by-Hop options header */
MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
/* Destination options header(1st part) */
if (opt->ip6po_rthdr) {
/*
* Destination options header(1st part)
* This only makes sence with a routing header.
* See Section 9.2 of
* draft-ietf-ipngwg-rfc2292bis-02.txt.
* Disabling this part just for MIP6 convenience is
* a bad idea. We need to think carefully about a
* way to make the advanced API coexist with MIP6
* options, which might automatically be inserted in
* the kernel.
*/
MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
}
/* Routing header */
MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
/* Destination options header(2nd part) */
MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
}
#ifdef MIP6
bzero((caddr_t)&mip6opt, sizeof(mip6opt));
if ((flags & IPV6_FORWARDING) == 0) {
/*
* XXX: reconsider the following routine.
*/
/*
* MIP6 extention headers handling.
* insert HA, BU, BA, BR options if necessary.
*/
if (mip6_exthdr_create(m, opt, &mip6opt))
goto freehdrs;
if (((opt != NULL) && (opt->ip6po_rthdr != NULL))
|| (mip6opt.mip6po_rthdr != NULL)) {
m_freem(exthdrs.ip6e_rthdr);
if (mip6opt.mip6po_rthdr != NULL) {
/*
* there is no rthdr specified in the
* ip6_pktopts. but mip6 create a
* rthdr for the router optimization
* purpose.
*/
MAKE_EXTHDR(mip6opt.mip6po_rthdr,
&exthdrs.ip6e_rthdr);
} else {
/*
* there is a rthdr specified in the
* ip6_pktopts. if mip6 require the
* route optimization, the rthdr for
* that purpose is already included in
* the ip6po_rthdr in the
* mip6_destopt_create().
*/
MAKE_EXTHDR(opt->ip6po_rthdr,
&exthdrs.ip6e_rthdr);
}
/*
* if a routing header exists dest1 must be
* inserted if it exists.
*/
if ((opt != NULL) && (opt->ip6po_dest1)) {
m_freem(exthdrs.ip6e_dest1);
MAKE_EXTHDR(opt->ip6po_dest1,
&exthdrs.ip6e_dest1);
}
}
MAKE_EXTHDR(mip6opt.mip6po_haddr, &exthdrs.ip6e_haddr);
if (mip6opt.mip6po_dest2) {
m_freem(exthdrs.ip6e_dest2);
MAKE_EXTHDR(mip6opt.mip6po_dest2, &exthdrs.ip6e_dest2);
}
} else {
/*
* this is the forwarding packet. do not modify any
* extension headers.
*/
}
#endif /* MIP6 */
#ifdef IPSEC
#ifdef __OpenBSD__
/*
* splnet is chosen over spltdb because we are not allowed to
* lower the level, and udp6_output calls us in splnet(). XXX check
*/
s = splnet();
/*
* Check if there was an outgoing SA bound to the flow
* from a transport protocol.
*/
ip6 = mtod(m, struct ip6_hdr *);
/* Do we have any pending SAs to apply ? */
mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
if (mtag != NULL) {
#ifdef DIAGNOSTIC
if (mtag->m_tag_len != sizeof (struct tdb_ident))
panic("ip6_output: tag of length %d (should be %d",
mtag->m_tag_len, sizeof (struct tdb_ident));
#endif
tdbi = (struct tdb_ident *)(mtag + 1);
tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
if (tdb == NULL)
error = -EINVAL;
m_tag_delete(m, mtag);
}
else
tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
&error, IPSP_DIRECTION_OUT, NULL, inp);
if (tdb == NULL) {
splx(s);
if (error == 0) {
/*
* No IPsec processing required, we'll just send the
* packet out.
*/
sproto = 0;
/* Fall through to routing/multicast handling */
} else {
/*
* -EINVAL is used to indicate that the packet should
* be silently dropped, typically because we've asked
* key management for an SA.
*/
if (error == -EINVAL) /* Should silently drop packet */
error = 0;
goto freehdrs;
}
} else {
/* Loop detection */
for (mtag = m_tag_first(m); mtag != NULL;
mtag = m_tag_next(m, mtag)) {
if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
mtag->m_tag_id !=
PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
continue;
tdbi = (struct tdb_ident *)(mtag + 1);
if (tdbi->spi == tdb->tdb_spi &&
tdbi->proto == tdb->tdb_sproto &&
!bcmp(&tdbi->dst, &tdb->tdb_dst,
sizeof(union sockaddr_union))) {
splx(s);
sproto = 0; /* mark as no-IPsec-needed */
goto done_spd;
}
}
/* We need to do IPsec */
bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
sspi = tdb->tdb_spi;
sproto = tdb->tdb_sproto;
splx(s);
#if 1 /* XXX */
/* if we have any extension header, we cannot perform IPsec */
if (exthdrs.ip6e_hbh || exthdrs.ip6e_dest1 ||
#ifdef MIP6
exthdrs.ip6e_haddr ||
#endif /* MIP6 */
exthdrs.ip6e_rthdr || exthdrs.ip6e_dest2) {
error = EHOSTUNREACH;
goto freehdrs;
}
#endif
}
/* Fall through to the routing/multicast handling code */
done_spd:
#else
/* get a security policy for this packet */
if (so == NULL)
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
else
sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
if (sp == NULL) {
ipsec6stat.out_inval++;
goto freehdrs;
}
error = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -