📄 in6_src.c
字号:
if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&
(ia->ia6_flags & IN6_IFF_HOME) != 0) {
REPLACE(4);
}
}
#endif /* MIP6 */
/* Rule 5: Prefer outgoing interface */
if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)
NEXT(5);
if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)
REPLACE(5);
/*
* Rule 6: Prefer matching label
* Note that best_policy should be non-NULL here.
*/
if (dst_policy == NULL)
dst_policy = lookup_addrsel_policy(dstsock);
if (dst_policy->label != ADDR_LABEL_NOTAPP) {
new_policy = lookup_addrsel_policy(&ia->ia_addr);
if (dst_policy->label == best_policy->label &&
dst_policy->label != new_policy->label)
NEXT(6);
if (dst_policy->label != best_policy->label &&
dst_policy->label == new_policy->label)
REPLACE(6);
}
/*
* Rule 7: Prefer public addresses.
* We allow users to reverse the logic by configuring
* a sysctl variable, so that privacy conscious users can
* always prefer temporary addresses.
*/
if (!(ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
(ia->ia6_flags & IN6_IFF_TEMPORARY)) {
if (ip6_prefer_tempaddr)
REPLACE(7);
else
NEXT(7);
}
if ((ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
!(ia->ia6_flags & IN6_IFF_TEMPORARY)) {
if (ip6_prefer_tempaddr)
NEXT(7);
else
REPLACE(7);
}
/*
* Rule 8: prefer addresses on alive interfaces.
* This is a KAME specific rule.
*/
if ((ia_best->ia_ifp->if_flags & IFF_UP) &&
!(ia->ia_ifp->if_flags & IFF_UP))
NEXT(8);
if (!(ia_best->ia_ifp->if_flags & IFF_UP) &&
(ia->ia_ifp->if_flags & IFF_UP))
REPLACE(8);
/*
* Rule 9: prefer addresses on "preferred" interfaces.
* This is a KAME specific rule.
*/
#define NDI_BEST (nd_ifinfo[ia_best->ia_ifp->if_index])
#define NDI_NEW (nd_ifinfo[ia->ia_ifp->if_index])
if ((NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&
!(NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))
NEXT(9);
if (!(NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&
(NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))
REPLACE(9);
#undef NDI_BEST
#undef NDI_NEW
/*
* Rule 14: Use longest matching prefix.
* Note: in the address selection draft, this rule is
* documented as "Rule 8". However, since it is also
* documented that this rule can be overridden, we assign
* a large number so that it is easy to assign smaller numbers
* to more preferred rules.
*/
new_matchlen = in6_matchlen(&ia->ia_addr.sin6_addr, dst);
if (best_matchlen < new_matchlen)
REPLACE(14);
if (new_matchlen < best_matchlen)
NEXT(14);
/* Rule 15 is reserved. */
/*
* Last resort: just keep the current candidate.
* Or, do we need more rules?
*/
continue;
replace:
ia_best = ia;
best_scope = (new_scope >= 0 ? new_scope :
in6_addrscope(&ia_best->ia_addr.sin6_addr));
best_policy = (new_policy ? new_policy :
lookup_addrsel_policy(&ia_best->ia_addr));
best_matchlen = (new_matchlen >= 0 ? new_matchlen :
in6_matchlen(&ia_best->ia_addr.sin6_addr,
dst));
next:
continue;
out:
break;
}
if ((ia = ia_best) == NULL) {
*errorp = EADDRNOTAVAIL;
return(NULL);
}
if (ifpp)
*ifpp = ifp;
return(&ia->ia_addr.sin6_addr);
}
#undef REPLACE
#undef BREAK
#undef NEXT
static int
in6_selectif(dstsock, opts, mopts, ro, retifp)
struct sockaddr_in6 *dstsock;
struct ip6_pktopts *opts;
struct ip6_moptions *mopts;
#ifdef NEW_STRUCT_ROUTE
struct route *ro;
#else
struct route_in6 *ro;
#endif
struct ifnet **retifp;
{
int error, clone;
struct rtentry *rt = NULL;
clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;
if ((error = in6_selectroute(dstsock, opts, mopts, ro, retifp,
&rt, clone)) != 0) {
return(error);
}
/*
* Adjust the "outgoing" interface. If we're going to loop the packet
* back to ourselves, the ifp would be the loopback interface.
* However, we'd rather know the interface associated to the
* destination address (which should probably be one of our own
* addresses.)
*/
if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp)
*retifp = rt->rt_ifa->ifa_ifp;
return(0);
}
int
in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt, clone)
struct sockaddr_in6 *dstsock;
struct ip6_pktopts *opts;
struct ip6_moptions *mopts;
#ifdef NEW_STRUCT_ROUTE
struct route *ro;
#else
struct route_in6 *ro;
#endif
struct ifnet **retifp;
struct rtentry **retrt;
int clone; /* meaningful only for bsdi and freebsd. */
{
int error = 0;
struct ifnet *ifp = NULL;
struct rtentry *rt = NULL;
struct sockaddr_in6 *sin6_next;
struct in6_pktinfo *pi = NULL;
struct in6_addr *dst = &dstsock->sin6_addr;
/* If the caller specify the outgoing interface explicitly, use it. */
if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
/* XXX boundary check is assumed to be already done. */
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
ifp = ifnet_byindex(pi->ipi6_ifindex);
#else
ifp = ifindex2ifnet[pi->ipi6_ifindex];
#endif
if (ifp != NULL &&
(retrt == NULL || IN6_IS_ADDR_MULTICAST(dst))) {
/*
* we do not have to check nor get the route for
* multicast.
*/
goto done;
} else
goto getroute;
}
/*
* If the destination address is a multicast address and the outgoing
* interface for the address is specified by the caller, use it.
*/
if (IN6_IS_ADDR_MULTICAST(dst) &&
mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
goto done; /* we do not need a route for multicast. */
}
getroute:
/*
* If the next hop address for the packet is specified by the caller,
* use it as the gateway.
*/
if (opts && opts->ip6po_nexthop) {
#ifdef NEW_STRUCT_ROUTE
struct route *ron;
#else
struct route_in6 *ron;
#endif
sin6_next = satosin6(opts->ip6po_nexthop);
/* at this moment, we only support AF_INET6 next hops */
if (sin6_next->sin6_family != AF_INET6) {
error = EAFNOSUPPORT; /* or should we proceed? */
goto done;
}
/*
* If the next hop is an IPv6 address, then the node identified
* by that address must be a neighbor of the sending host.
*/
ron = &opts->ip6po_nextroute;
if ((ron->ro_rt &&
(ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) !=
(RTF_UP | RTF_LLINFO)) ||
!SA6_ARE_ADDR_EQUAL(satosin6(&ron->ro_dst), sin6_next)) {
if (ron->ro_rt) {
RTFREE(ron->ro_rt);
ron->ro_rt = NULL;
}
*satosin6(&ron->ro_dst) = *sin6_next;
}
if (ron->ro_rt == NULL) {
rtalloc((struct route *)ron); /* multi path case? */
if (ron->ro_rt == NULL ||
!(ron->ro_rt->rt_flags & RTF_LLINFO)) {
if (ron->ro_rt) {
RTFREE(ron->ro_rt);
ron->ro_rt = NULL;
}
error = EHOSTUNREACH;
goto done;
}
}
rt = ron->ro_rt;
ifp = rt->rt_ifp;
/*
* When cloning is required, try to allocate a route to the
* destination so that the caller can store path MTU
* information.
*/
if (!clone)
goto done;
}
/*
* Use a cached route if it exists and is valid, else try to allocate
* a new one.
*/
if (ro) {
int newroute = 0;
if (ro->ro_rt &&
(!(ro->ro_rt->rt_flags & RTF_UP) ||
!IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
dst))) {
RTFREE(ro->ro_rt);
ro->ro_rt = (struct rtentry *)NULL;
}
if (ro->ro_rt == (struct rtentry *)NULL) {
struct sockaddr_in6 *sa6;
/* No route yet, so try to acquire one */
newroute = 1;
bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6);
sa6->sin6_addr = *dst;
#ifdef SCOPEDROUTING
sa6->sin6_scope_id = dstsock->sin6_scope_id;
#endif
if (clone) {
#ifdef __bsdi__
rtcalloc((struct route *)ro);
#else /* !bsdi */
#ifdef RADIX_MPATH
rtalloc_mpath((struct route *)ro,
ntohl(dstsock->sin6_addr.s6_addr32[3]));
#else
rtalloc((struct route *)ro);
#endif /* RADIX_MPATH */
#endif /* bsdi */
} else {
#ifdef __FreeBSD__
ro->ro_rt = rtalloc1(&((struct route *)ro)
->ro_dst, (int)NULL, 0UL);
#else
#ifdef RADIX_MPATH
rtalloc_mpath((struct route *)ro,
ntohl(dstsock->sin6_addr.s6_addr32[3]));
#else
ro->ro_rt = rtalloc1(&((struct route *)ro)
->ro_dst, NULL);
#endif /* RADIX_MPATH */
#endif /* __FreeBSD__ */
}
}
/*
* do not care about the result if we have the nexthop
* explicitly specified.
*/
if (opts && opts->ip6po_nexthop)
goto done;
if (ro->ro_rt) {
ifp = ro->ro_rt->rt_ifp;
if (ifp == NULL) { /* can this really happen? */
RTFREE(ro->ro_rt);
ro->ro_rt = NULL;
}
}
if (ro->ro_rt == NULL)
error = EHOSTUNREACH;
rt = ro->ro_rt;
/*
* Check if the outgoing interface conflicts with
* the interface specified by ipi6_ifindex (if specified).
* Note that loopback interface is always okay.
* (this may happen when we are sending a packet to one of
* our own addresses.)
*/
if (opts && opts->ip6po_pktinfo
&& opts->ip6po_pktinfo->ipi6_ifindex) {
if (!(ifp->if_flags & IFF_LOOPBACK) &&
ifp->if_index !=
opts->ip6po_pktinfo->ipi6_ifindex) {
error = EHOSTUNREACH;
goto done;
}
}
}
done:
if (error == EHOSTUNREACH)
ip6stat.ip6s_noroute++;
if (retifp != NULL)
*retifp = ifp;
if (retrt != NULL)
*retrt = rt; /* rt may be NULL */
return(error);
}
/*
* Default hop limit selection. The precedence is as follows:
* 1. Hoplimit value specified via ioctl.
* 2. (If the outgoing interface is detected) the current
* hop limit of the interface specified by router advertisement.
* 3. The system default hoplimit.
*/
#ifdef HAVE_NRL_INPCB
#define in6pcb inpcb
#define in6p_hops inp_hops
#endif
int
in6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp)
{
if (in6p && in6p->in6p_hops >= 0)
return(in6p->in6p_hops);
else if (ifp)
return(nd_ifinfo[ifp->if_index].chlim);
else
return(ip6_defhlim);
}
#ifdef HAVE_NRL_INPCB
#undef in6pcb
#undef in6p_hops
#endif
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
/*
* Find an empty port and set it to the specified PCB.
*/
#ifdef HAVE_NRL_INPCB /* XXX: I really hate such ugly macros...(jinmei) */
#define in6pcb inpcb
#define in6p_socket inp_socket
#define in6p_lport inp_lport
#define in6p_head inp_head
#define in6p_flags inp_flags
#define IN6PLOOKUP_WILDCARD INPLOOKUP_WILDCARD
#endif
int
in6_pcbsetport(struct in6_addr *laddr, struct in6pcb *in6p)
{
struct socket *so = in6p->in6p_socket;
struct in6pcb *head = in6p->in6p_head;
u_int16_t last_port, lport = 0;
int wild = 0;
void *t;
u_int16_t min, max;
/* XXX: this is redundant when called from in6_pcbbind */
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
(so->so_options & SO_ACCEPTCONN) == 0))
wild = IN6PLOOKUP_WILDCARD;
if (in6p->in6p_flags & IN6P_LOWPORT) {
min = ip6_lowportmin;
max = ip6_lowportmax;
} else {
min = ip6_anonportmin;
max = ip6_anonportmax;
}
/* value out of range */
if (head->in6p_lport < min)
head->in6p_lport = min;
else if (head->in6p_lport > max)
head->in6p_lport = min;
last_port = head->in6p_lport;
goto startover; /*to randomize*/
for (;;) {
lport = htons(head->in6p_lport);
if (IN6_IS_ADDR_V4MAPPED(laddr)) {
#ifdef HAVE_NRL_INPCB
#ifdef INPLOOKUP_WILDCARD6
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -