in6_src.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,336 行 · 第 1/3 页
C
1,336 行
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 NEXTstatic intin6_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);}intin6_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 #endifintin6_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#endifintin6_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 + =
减小字号Ctrl + -
显示快捷键?