📄 in6_src.c
字号:
//==========================================================================
//
// src/sys/netinet6/in6_src.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: in6_src.c,v 1.96 2001/12/24 10:39:29 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, 1991, 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.
*
* @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sockio.h>
#include <sys/errno.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/nd6.h>
#include <netinet6/scope6_var.h>
#ifdef MIP6
#include <netinet6/mip6.h>
#endif /* MIP6 */
#if defined(__NetBSD__)
extern struct ifnet loif[NLOOP];
#endif
#define ADDR_LABEL_NOTAPP (-1)
struct in6_addrpolicy defaultaddrpolicy;
int ip6_prefer_tempaddr = 0;
#ifdef NEW_STRUCT_ROUTE
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *,
struct route *ro,
struct ifnet **));
#else
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *,
struct route_in6 *ro,
struct ifnet **));
#endif
static struct in6_addrpolicy *lookup_addrsel_policy __P((struct sockaddr_in6 *));
static void init_policy_queue __P((void));
static int add_addrsel_policyent __P((struct in6_addrpolicy *));
static int delete_addrsel_policyent __P((struct in6_addrpolicy *));
static struct in6_addrpolicy *match_addrsel_policy __P((struct sockaddr_in6 *));
/*
* Return an IPv6 address, which is the most appropriate for a given
* destination and user specified options.
* If necessary, this function lookups the routing table and returns
* an entry to the caller for later use.
*/
#define REPLACE(r) do {\ if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \ sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \ ip6stat.ip6s_sources_rule[(r)]++; \ /* printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \ goto replace; \} while(0)
#define NEXT(r) do {\ if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \ sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \ ip6stat.ip6s_sources_rule[(r)]++; \ /* printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \ goto next; /* XXX: we can't use 'continue' here */ \} while(0)
#define BREAK(r) do { \ if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \ sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \ ip6stat.ip6s_sources_rule[(r)]++; \ goto out; /* XXX: we can't use 'break' here */ \} while(0)
struct in6_addr *
in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct ip6_moptions *mopts, struct route *ro,
struct ifnet **ifpp, struct in6_addr *laddr,
int *errorp)
{
struct in6_addr *dst;
struct ifnet *ifp = NULL;
struct in6_ifaddr *ia = NULL, *ia_best = NULL;
struct in6_pktinfo *pi = NULL;
int dst_scope = -1, best_scope = -1, best_matchlen = -1;
struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL;
#ifdef MIP6
struct hif_softc *sc;
#ifdef MIP6_ALLOW_COA_FALLBACK
struct mip6_bu *mbu_dst;
u_int8_t coafallback = 0;
#endif
#endif
dst = &dstsock->sin6_addr;
*errorp = 0;
if (ifpp)
*ifpp = NULL;
/*
* If the source address is explicitly specified by the caller,
* check if the requested source address is indeed a unicast address
* assigned to the node, and can be used as the packet's source
* address. If everything is okay, use the address as source.
*/
if (opts && (pi = opts->ip6po_pktinfo) &&
!IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
struct sockaddr_in6 srcsock;
struct in6_ifaddr *ia6;
/* get the outgoing interface */
if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp))
!= 0) {
return(NULL);
}
/*
* determine the appropriate zone id of the source based on
* the zone of the destination and the outgoing interface.
*/
bzero(&srcsock, sizeof(srcsock));
srcsock.sin6_family = AF_INET6;
srcsock.sin6_len = sizeof(srcsock);
srcsock.sin6_addr = pi->ipi6_addr;
if (ifp) {
int64_t zone;
zone = in6_addr2zoneid(ifp, &pi->ipi6_addr);
if (zone < 0) { /* XXX: this should not happen */
*errorp = EINVAL;
return(NULL);
}
srcsock.sin6_scope_id = zone;
}
if ((*errorp = in6_embedscope(&srcsock.sin6_addr, &srcsock))
!= 0) {
return(NULL);
}
#ifndef SCOPEDROUTING
srcsock.sin6_scope_id = 0; /* XXX: ifa_ifwithaddr expects 0 */
#endif
ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
if (ia6 == NULL ||
(ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
*errorp = EADDRNOTAVAIL;
return(NULL);
}
pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
if (*ifpp)
*ifpp = ifp;
return(&pi->ipi6_addr);
}
/*
* Otherwise, if the socket has already bound the source, just use it.
*/
if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
return(laddr);
/*
* If the address is not specified, choose the best one based on
* the outgoing interface and the destination address.
*/
/* get the outgoing interface */
if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
return(NULL);
#ifdef MIP6
#ifdef MIP6_ALLOW_COA_FALLBACK
for (sc = TAILQ_FIRST(&hif_softc_list);
sc;
sc = TAILQ_NEXT(sc, hif_entry)) {
mbu_dst = mip6_bu_list_find_withpaddr(&sc->hif_bu_list, dst);
if (mbu_dst != NULL)
coafallback = mbu_dst->mbu_coafallback;
}
#endif /* MIP6_ALLOW_COA_FALLBACK */
#endif /* MIP6 */
#ifdef DIAGNOSTIC
if (ifp == NULL) /* this should not happen */
panic("in6_selectsrc: NULL ifp");
#endif
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
int new_scope = -1, new_matchlen = -1;
struct in6_addrpolicy *new_policy = NULL;
int64_t srczone, dstzone;
struct ifnet *ifp1 = ia->ia_ifp;
/*
* We'll never take an address that breaks the scope zone
* of the destination. We also skip an address if its zone
* does not contain the outgoing interface.
* XXX: we should probably use sin6_scope_id here.
*/
if ((dstzone = in6_addr2zoneid(ifp1, dst)) < 0 ||
dstzone != in6_addr2zoneid(ifp, dst)) {
continue;
}
if ((srczone = in6_addr2zoneid(ifp1, &ia->ia_addr.sin6_addr))
< 0 ||
srczone != in6_addr2zoneid(ifp, &ia->ia_addr.sin6_addr)) {
continue;
}
/* avoid unusable addresses */
if ((ia->ia6_flags &
(IN6_IFF_NOTREADY | IN6_IFF_ANYCAST | IN6_IFF_DETACHED))) {
continue;
}
if (!ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))
continue;
/* Rule 1: Prefer same address */
if (IN6_ARE_ADDR_EQUAL(dst, &ia->ia_addr.sin6_addr)) {
ia_best = ia;
BREAK(1); /* there should be no better candidate */
}
if (ia_best == NULL)
REPLACE(0);
/* Rule 2: Prefer appropriate scope */
if (dst_scope < 0)
dst_scope = in6_addrscope(dst);
new_scope = in6_addrscope(&ia->ia_addr.sin6_addr);
if (IN6_ARE_SCOPE_CMP(best_scope, new_scope) < 0) {
if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0)
REPLACE(2);
NEXT(2);
} else if (IN6_ARE_SCOPE_CMP(new_scope, best_scope) < 0) {
if (IN6_ARE_SCOPE_CMP(new_scope, dst_scope) < 0)
NEXT(2);
REPLACE(2);
}
/*
* Rule 3: Avoid deprecated addresses. Note that the case of
* !ip6_use_deprecated is already rejected above.
*/
if (!IFA6_IS_DEPRECATED(ia_best) && IFA6_IS_DEPRECATED(ia))
NEXT(3);
if (IFA6_IS_DEPRECATED(ia_best) && !IFA6_IS_DEPRECATED(ia))
REPLACE(3);
/* Rule 4: Prefer home addresses */
/*
* XXX: This is a TODO. We should probably merge the MIP6
* case above.
*/
#ifdef MIP6
/*
* If SA is simultaneously a home address and care-of address
* and SB is not, then prefer SA. Similarly, if SB is
* simultaneously a home address and care-of address and SA is
* not, then prefer SB.
*/
{
struct mip6_bu *mbu_ia_best = NULL, *mbu_ia = NULL;
if (ia_best->ia6_flags & IN6_IFF_HOME) {
/*
* find a binding update entry for ia_best.
*/
for (sc = TAILQ_FIRST(&hif_softc_list);
sc;
sc = TAILQ_NEXT(sc, hif_entry)) {
mbu_ia_best = mip6_bu_list_find_home_registration(
&sc->hif_bu_list,
&ia->ia_addr.sin6_addr);
if (mbu_ia_best)
break;
}
}
if (ia->ia6_flags & IN6_IFF_HOME) {
/*
* find a binding update entry for ia.
*/
for (sc = TAILQ_FIRST(&hif_softc_list);
sc;
sc = TAILQ_NEXT(sc, hif_entry)) {
mbu_ia = mip6_bu_list_find_home_registration(
&sc->hif_bu_list,
&ia->ia_addr.sin6_addr);
if (mbu_ia)
break;
}
}
/*
* if the binding update entry for a certain address
* exists and its registration status is
* MIP6_BU_REG_STATE_NOTREG, the address is a home
* address and a care of addres simultaneously.
*/
if ((mbu_ia_best &&
(mbu_ia_best->mbu_reg_state
== MIP6_BU_REG_STATE_NOTREG))
&&
!(mbu_ia &&
(mbu_ia->mbu_reg_state
== MIP6_BU_REG_STATE_NOTREG))) {
NEXT(4);
}
if (!(mbu_ia_best &&
(mbu_ia_best->mbu_reg_state
== MIP6_BU_REG_STATE_NOTREG))
&&
(mbu_ia &&
(mbu_ia->mbu_reg_state
== MIP6_BU_REG_STATE_NOTREG))) {
REPLACE(4);
}
}
#ifdef MIP6_ALLOW_COA_FALLBACK
if (coafallback) {
/*
* if the peer doesn't recognize a home
* address destination option, we will use a
* CoA as a source address instead of a home
* address we have registered before. Though
* this behavior may arouse a mip6 beleiver's
* anger, is very useful in the current
* transition period that many hosts don't
* recognize a home address destination
* option...
*/
if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&
(ia->ia6_flags & IN6_IFF_HOME) != 0) {
/* XXX will break stat! */
NEXT(0);
}
if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&
(ia->ia6_flags & IN6_IFF_HOME) == 0) {
/* XXX will break stat! */
REPLACE(0);
}
} else
#endif
{
/*
* If SA is just a home address and SB is just
* a care-of address, then prefer
* SA. Similarly, if SB is just a home address
* and SA is just a care-of address, then
* prefer SB.
*/
if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&
(ia->ia6_flags & IN6_IFF_HOME) == 0) {
NEXT(4);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -