73#include <sys/malloc.h>
76#include <sys/protosw.h>
77#include <sys/socket.h>
78#include <sys/socketvar.h>
79#include <sys/sockio.h>
80#include <sys/sysctl.h>
84#include <sys/kernel.h>
85#include <sys/rmlock.h>
89#include <net/if_var.h>
92#include <net/route/nhop.h>
93#include <net/if_llatbl.h>
95#include <netinet/in.h>
96#include <netinet/in_var.h>
97#include <netinet/in_systm.h>
98#include <netinet/ip.h>
99#include <netinet/in_pcb.h>
100#include <netinet/ip_var.h>
101#include <netinet/udp.h>
102#include <netinet/udp_var.h>
105#include <netinet/ip6.h>
113#define ADDRSEL_LOCK_INIT() mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF)
114#define ADDRSEL_LOCK() mtx_lock(&addrsel_lock)
115#define ADDRSEL_UNLOCK() mtx_unlock(&addrsel_lock)
116#define ADDRSEL_LOCK_ASSERT() mtx_assert(&addrsel_lock, MA_OWNED)
119#define ADDRSEL_SXLOCK_INIT() sx_init(&addrsel_sxlock, "addrsel_sxlock")
120#define ADDRSEL_SLOCK() sx_slock(&addrsel_sxlock)
121#define ADDRSEL_SUNLOCK() sx_sunlock(&addrsel_sxlock)
122#define ADDRSEL_XLOCK() sx_xlock(&addrsel_sxlock)
123#define ADDRSEL_XUNLOCK() sx_xunlock(&addrsel_sxlock)
125#define ADDR_LABEL_NOTAPP (-1)
127#define V_defaultaddrpolicy VNET(defaultaddrpolicy)
132 struct ip6_moptions *,
struct route_in6 *,
struct ifnet **,
133 struct nhop_object **,
int, u_int, uint32_t);
135 struct ip6_moptions *,
struct ifnet **,
136 struct ifnet *, u_int);
138 struct ip6_pktopts *,
struct inpcb *,
struct ucred *,
139 struct ifnet **,
struct in6_addr *);
157#define REPLACE(r) do {\
158 IP6STAT_INC(ip6s_sources_rule[(r)]); \
172#define BREAK(r) do { \
173 IP6STAT_INC(ip6s_sources_rule[(r)]); \
179 struct ip6_pktopts *opts,
struct inpcb *inp,
struct ucred *cred,
180 struct ifnet **ifpp,
struct in6_addr *srcp)
182 struct rm_priotracker in6_ifa_tracker;
184 struct ifnet *ifp = NULL, *oifp = NULL;
185 struct in6_ifaddr *ia = NULL, *ia_best = NULL;
187 int dst_scope = -1, best_scope = -1, best_matchlen = -1;
192 struct ip6_moptions *mopts;
195 KASSERT(srcp != NULL, (
"%s: srcp is NULL", __func__));
212 INP_LOCK_ASSERT(inp);
213 mopts = inp->in6p_moptions;
227 if ((error =
in6_selectif(dstsock, opts, mopts, &ifp, oifp,
246 &tmp, (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
254 if ((inp->inp_flags & INP_BINDANY) == 0) {
258 return (EADDRNOTAVAIL);
261 bcopy(&tmp, srcp,
sizeof(*srcp));
274 ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
276 bcopy(&inp->in6p_laddr, srcp,
sizeof(*srcp));
292 if ((error =
in6_selectif(dstsock, opts, mopts, &ifp, oifp,
293 (inp != NULL) ? inp->inp_inc.inc_fibnum : fibnum)) != 0)
298 panic(
"in6_selectsrc: NULL ifp");
306 int new_scope = -1, new_matchlen = -1;
308 u_int32_t srczone, osrczone, dstzone;
310 struct ifnet *ifp1 = ia->ia_ifp;
319 odstzone != dstzone) {
325 osrczone != srczone) {
382 if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)
384 if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)
392 if (dst_policy == NULL)
396 if (dst_policy->
label == best_policy->label &&
399 if (dst_policy->
label != best_policy->label &&
437 if ((ia_best->ia_ifp->if_flags & IFF_UP) &&
438 !(ia->ia_ifp->if_flags & IFF_UP))
440 if (!(ia_best->ia_ifp->if_flags & IFF_UP) &&
441 (ia->ia_ifp->if_flags & IFF_UP))
447 if (ifa_preferred(&ia_best->ia_ifa, &ia->
ia_ifa))
449 if (ifa_preferred(&ia->
ia_ifa, &ia_best->ia_ifa))
471 if (best_matchlen < new_matchlen)
473 if (new_matchlen < best_matchlen)
486 best_scope = (new_scope >= 0 ? new_scope :
488 best_policy = (new_policy ? new_policy :
490 best_matchlen = (new_matchlen >= 0 ? new_matchlen :
501 if ((ia = ia_best) == NULL) {
504 return (EADDRNOTAVAIL);
518 (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) {
521 return (EADDRNOTAVAIL);
527 bcopy(&tmp, srcp,
sizeof(*srcp));
528 if (ia->ia_ifp == ifp)
532 if (dst_scope == best_scope)
551 struct inpcb *inp,
struct ucred *cred,
int scope_ambiguous,
554 struct ifnet *retifp;
558 fibnum = inp->inp_inc.inc_fibnum;
561 error =
in6_selectsrc(fibnum, dstsock, opts, inp, cred, &retifp, srcp);
568 if (retifp == NULL || scope_ambiguous == 0)
593 uint32_t scopeid,
struct ifnet *ifp,
struct in6_addr *srcp,
596 struct ifnet *retifp;
601 bzero(&dst_sa,
sizeof(dst_sa));
608 error =
in6_selectsrc(fibnum, &dst_sa, NULL, NULL, NULL, &retifp, srcp);
620 struct ip6_moptions *mopts,
struct route_in6 *ro,
621 struct ifnet **retifp,
struct nhop_object **retnh,
int norouteok,
622 u_int fibnum, uint32_t flowid)
625 struct ifnet *ifp = NULL;
626 struct nhop_object *nh = NULL;
634 if (dstsock->
sin6_addr.s6_addr32[0] == 0 &&
637 printf(
"%s: strange destination %s\n", __func__,
640 printf(
"%s: destination = %s%%%d\n", __func__,
651 (norouteok || retnh == NULL ||
666 mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
687 if (opts && opts->ip6po_nexthop) {
688 struct route_in6 *ron;
690 sin6_next =
satosin6(opts->ip6po_nexthop);
702 ron = &opts->ip6po_nextroute;
704 if (ron->ro_nh != NULL && (
705 !NH_IS_VALID(ron->ro_nh) ||
706 ron->ro_dst.sin6_family != AF_INET6 ||
710 if (ron->ro_nh == NULL) {
711 ron->ro_dst = *sin6_next;
717 &sin6_next->
sin6_addr, 0, NHR_REF, flowid);
723 if (ron->ro_nh == NULL ||
724 (ron->ro_nh->nh_flags & NHF_GATEWAY) != 0)
725 error = EHOSTUNREACH;
740 (!NH_IS_VALID(ro->ro_nh) ||
741 ((
struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 ||
746 if (ro->ro_nh == (
struct nhop_object *)NULL) {
760 uint32_t scopeid = 0;
763 scopeid = ntohs(sa6->
sin6_addr.s6_addr16[1]);
768 &sa6->
sin6_addr, scopeid, NHR_REF, flowid);
771 sa6->
sin6_addr.s6_addr16[1] = htons(scopeid);
778 if (opts && opts->ip6po_nexthop)
782 ifp = ro->ro_nh->nh_ifp;
784 error = EHOSTUNREACH;
796 if (!(ifp->if_flags & IFF_LOOPBACK) &&
799 error = EHOSTUNREACH;
806 if (ifp == NULL && nh == NULL) {
811 error = EHOSTUNREACH;
813 if (error == EHOSTUNREACH)
816 if (retifp != NULL) {
818 *retifp = nh->nh_aifp;
831 struct ip6_moptions *mopts,
struct ifnet **retifp,
832 struct ifnet *oifp, u_int fibnum)
835 struct route_in6 sro;
836 struct nhop_object *nh = NULL;
839 KASSERT(retifp != NULL, (
"%s: retifp is NULL", __func__));
841 bzero(&sro,
sizeof(sro));
844 error =
selectroute(dstsock, opts, mopts, &sro, retifp, &nh, 1, fibnum, 0);
847 nh_flags = nh->nh_flags;
848 if (nh != NULL && nh == sro.ro_nh)
853 if (oifp != NULL && fibnum == RT_DEFAULT_FIB) {
878 if (nh_flags & (NHF_REJECT | NHF_BLACKHOLE)) {
879 error = (nh_flags & NHF_HOST ? EHOSTUNREACH : ENETUNREACH);
889 struct ip6_moptions *mopts,
struct route_in6 *ro,
890 struct ifnet **retifp,
struct nhop_object **retnh, u_int fibnum, uint32_t flowid)
893 return (
selectroute(dstsock, opts, mopts, ro, retifp,
894 retnh, 0, fibnum, flowid));
908 if (inp && inp->in6p_hops >= 0)
909 return (inp->in6p_hops);
913 struct nhop_object *nh;
915 uint32_t fibnum, scopeid;
918 fibnum = inp->inp_inc.inc_fibnum;
939 if (!IS_DEFAULT_VNET(curvnet))
967 struct sysctl_req *
w_req;
972static SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
984 bzero(&w,
sizeof(w));
1033#define V_addrsel_policytab VNET(addrsel_policytab)
1047 new = malloc(
sizeof(*
new), M_IFADDR,
1055 &pol->ape_policy.addr.sin6_addr) &&
1057 &pol->ape_policy.addrmask.sin6_addr)) {
1060 free(
new, M_IFADDR);
1065 bzero(
new,
sizeof(*
new));
1068 new->ape_policy = *newpolicy;
1088 &pol->ape_policy.addr.sin6_addr) &&
1090 &pol->ape_policy.addrmask.sin6_addr)) {
1103 free(pol, M_IFADDR);
1116 if ((error = (*callback)(&pol->ape_policy, w)) != 0) {
1131 error = SYSCTL_OUT(w->
w_req, pol,
sizeof(*pol));
1141 int matchlen, bestmatchlen = -1;
1142 u_char *mp, *ep, *k, *p, m;
1147 pol = &pent->ape_policy;
1148 mp = (u_char *)&pol->addrmask.sin6_addr;
1151 p = (u_char *)&pol->addr.sin6_addr;
1152 for (; mp < ep && *mp; mp++, k++, p++) {
1167 if (bestpol == NULL ||
1168 matchlen > bestmatchlen) {
1170 bestmatchlen = matchlen;
int in6_matchlen(struct in6_addr *src, struct in6_addr *dst)
char * ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
int in6_mask2len(struct in6_addr *mask, u_char *lim0)
struct in6_ifaddr * in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid, bool referenced)
int in6_addrscope(const struct in6_addr *)
#define IN6_IS_ADDR_LINKLOCAL(a)
#define IN6_IS_ADDR_MC_LINKLOCAL(a)
#define IN6_IS_ADDR_UNSPECIFIED(a)
#define IN6_IS_ADDR_LOOPBACK(a)
#define IN6_ARE_ADDR_EQUAL(a, b)
#define IFA6_IS_DEPRECATED(a)
#define IN6_IS_ADDR_MULTICAST(a)
#define IN6_IS_ADDR_MC_NODELOCAL(a)
#define IN6_IS_SCOPE_LINKLOCAL(a)
struct nhop_object * fib6_lookup(uint32_t fibnum, const struct in6_addr *dst6, uint32_t scopeid, uint32_t flags, uint32_t flowid)
int prison_check_ip6(const struct ucred *cred, const struct in6_addr *ia6)
int prison_saddrsel_ip6(struct ucred *cred, struct in6_addr *ia6)
int prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only)
int in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, struct ifnet *ifp, struct in6_addr *srcp, int *hlim)
static struct mtx addrsel_lock
SYSCTL_DECL(_net_inet6_ip6)
int in6_src_ioctl(u_long cmd, caddr_t data)
static int in6_selectsrc(uint32_t, struct sockaddr_in6 *, struct ip6_pktopts *, struct inpcb *, struct ucred *, struct ifnet **, struct in6_addr *)
VNET_DEFINE_STATIC(struct in6_addrpolicy, defaultaddrpolicy)
static struct in6_addrpolicy * match_addrsel_policy(struct sockaddr_in6 *)
static void init_policy_queue(void)
static int add_addrsel_policyent(struct in6_addrpolicy *)
TAILQ_HEAD(addrsel_policyhead, addrsel_policyent)
static int delete_addrsel_policyent(struct in6_addrpolicy *)
int in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct inpcb *inp, struct ucred *cred, int scope_ambiguous, struct in6_addr *srcp, int *hlim)
static SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy, CTLFLAG_RD|CTLFLAG_MPSAFE, in6_src_sysctl, "")
static int dump_addrsel_policyent(struct in6_addrpolicy *, void *)
#define ADDRSEL_XUNLOCK()
static int walk_addrsel_policy(int(*)(struct in6_addrpolicy *, void *), void *)
#define V_defaultaddrpolicy
int in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp, struct nhop_object **retnh, u_int fibnum, uint32_t flowid)
#define V_addrsel_policytab
#define ADDR_LABEL_NOTAPP
#define ADDRSEL_SUNLOCK()
static struct in6_addrpolicy * lookup_addrsel_policy(struct sockaddr_in6 *)
#define ADDRSEL_SXLOCK_INIT()
static int in6_src_sysctl(SYSCTL_HANDLER_ARGS)
static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, struct nhop_object **, int, u_int, uint32_t)
int in6_selecthlim(struct inpcb *inp, struct ifnet *ifp)
static struct sx addrsel_sxlock
VNET_DEFINE(int, ip6_prefer_tempaddr)=0
#define ADDRSEL_LOCK_INIT()
void addrsel_policy_init(void)
static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct ifnet **, struct ifnet *, u_int)
#define SIOCAADDRCTL_POLICY
#define IN6_IFF_PREFER_SOURCE
#define IN6_IFADDR_RLOCK(t)
#define IN6_ARE_SCOPE_CMP(a, b)
#define SIOCDADDRCTL_POLICY
#define IN6_IFADDR_RUNLOCK(t)
#define IN6_IFF_TEMPORARY
#define IN6_MASK_ADDR(a, m)
#define IP6STAT_INC(name)
#define V_ip6_prefer_tempaddr
#define IP6PO_TEMPADDR_SYSTEM
#define V_ip6_use_deprecated
#define IP6PO_TEMPADDR_NOTPREFER
#define ND6_IFF_NO_PREFER_IFACE
int in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
void in6_splitscope(const struct in6_addr *src, struct in6_addr *dst, uint32_t *scopeid)
struct ifnet * in6_getlinkifnet(uint32_t zoneid)
uint16_t in6_getscope(const struct in6_addr *in6)
int sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
struct sockaddr_in6 addrmask
struct sockaddr_in6 ia_addr
struct in6_addr ipi6_addr
unsigned int ipi6_ifindex
int ip6po_prefer_tempaddr
struct in6_pktinfo * ip6po_pktinfo
struct in6_addr sin6_addr
struct sysctl_req * w_req