Is anyone interested in this ? This diff allows to select the default source IP address (for TCP/UDP connections) on multi-homed & "multi-addressed" machines.
Looking for feedbacks on what I broke. Do not test with ping(8) as it uses another source address selection codepath. `curl ifconfig.co` is a good candidate to check if source is set correctly. Example usage : Set 2001:db8::1 as source : route source 2001:db8::1 Unset previously set IPv6 address on rdomain 10 : route -T10 source -inet6 default Show set address : route source Comments ? OK ? Denis Index: sbin/route/keywords.h =================================================================== RCS file: /cvs/src/sbin/route/keywords.h,v retrieving revision 1.34 diff -u -p -r1.34 keywords.h --- sbin/route/keywords.h 10 Aug 2017 13:44:48 -0000 1.34 +++ sbin/route/keywords.h 17 Sep 2020 09:59:25 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: keywords.h,v 1.34 2017/08/10 13:44:48 benno Exp $ */ +/* $OpenBSD$ */ /* WARNING! This file was generated by keywords.sh */ @@ -66,6 +66,7 @@ enum { K_SA, K_SENDPIPE, K_SHOW, + K_SOURCE, K_SSTHRESH, K_STATIC, K_SWAP, @@ -129,6 +130,7 @@ struct keytab keywords[] = { { "sa", K_SA }, { "sendpipe", K_SENDPIPE }, { "show", K_SHOW }, + { "source", K_SOURCE }, { "ssthresh", K_SSTHRESH }, { "static", K_STATIC }, { "swap", K_SWAP }, Index: sbin/route/keywords.sh =================================================================== RCS file: /cvs/src/sbin/route/keywords.sh,v retrieving revision 1.32 diff -u -p -r1.32 keywords.sh --- sbin/route/keywords.sh 10 Aug 2017 13:44:48 -0000 1.32 +++ sbin/route/keywords.sh 17 Sep 2020 09:59:25 -0000 @@ -67,6 +67,7 @@ rttvar sa sendpipe show +source ssthresh static swap Index: sbin/route/route.8 =================================================================== RCS file: /cvs/src/sbin/route/route.8,v retrieving revision 1.91 diff -u -p -r1.91 route.8 --- sbin/route/route.8 19 Jan 2020 18:22:31 -0000 1.91 +++ sbin/route/route.8 17 Sep 2020 09:59:25 -0000 @@ -195,6 +195,17 @@ or .Cm bgp . If the priority is negative, then routes that do not match the numeric priority are shown. +.It Xo +.Nm route +.Op Fl T Ar rtable +.Tg +.Cm source +.Ar address +.Xc +Set the preferred source address. If +.Ar address +is the word "default", 0.0.0.0 or ::, source address will be chosen by +the kernel for the matching address family. .El .Pp .Tg destination Index: sbin/route/route.c =================================================================== RCS file: /cvs/src/sbin/route/route.c,v retrieving revision 1.248 diff -u -p -r1.248 route.c --- sbin/route/route.c 7 Jul 2020 14:53:36 -0000 1.248 +++ sbin/route/route.c 17 Sep 2020 09:59:25 -0000 @@ -68,7 +68,8 @@ const struct if_status_description if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; -union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src, so_label; +union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src, so_label, + so_source; typedef union sockunion *sup; pid_t pid; @@ -85,6 +86,7 @@ struct rt_metrics rt_metrics; int flushroutes(int, char **); int newroute(int, char **); +int setsource(int, char **); int show(int, char *[]); int keycmp(const void *, const void *); int keyword(char *); @@ -132,7 +134,8 @@ usage(char *cp) "usage: %s [-dnqtv] [-T rtable] command [[modifiers] args]\n", __progname); fprintf(stderr, - "commands: add, change, delete, exec, flush, get, monitor, show\n"); + "commands: add, change, delete, exec, flush, get, monitor, show, " + "source\n"); exit(1); } @@ -258,6 +261,10 @@ main(int argc, char **argv) case K_FLUSH: exit(flushroutes(argc, argv)); break; + case K_SOURCE: + nflag = 1; + exit(setsource(argc, argv)); + break; } if (pledge("stdio dns", NULL) == -1) @@ -450,6 +457,52 @@ set_metric(char *value, int key) locking = 0; } + +int +setsource(int argc, char **argv) +{ + char *cmd, *srcaddr = ""; + int af = AF_UNSPEC, ret = 0; + struct hostent *hp = NULL; + int key; + + if (uid) + errx(1, "must be root to alter source address"); + cmd = argv[0]; + while (--argc > 0) { + if (**(++argv)== '-') { + switch (key = keyword(1 + *argv)) { + case K_INET: + af = AF_INET; + aflen = sizeof(struct sockaddr_in); + break; + case K_INET6: + af = AF_INET6; + aflen = sizeof(struct sockaddr_in6); + break; + } + } else if ((rtm_addrs & RTA_IFA) == 0) { + srcaddr = *argv; + getaddr(RTA_IFA, af, *argv, &hp); + } else + usage(NULL); + } + + if (strlen(srcaddr) == 0) + printsource(af, tableid); + + errno = 0; + ret = rtmsg(*cmd, 0, 0, 0); + if (!qflag && ret != 0) { + printf("%s %s", cmd, srcaddr); + if (ret == 0) + printf("\n"); + else + printf(": %s\n", strerror(errno)); + } + return (ret != 0); +} + int newroute(int argc, char **argv) { @@ -1067,6 +1120,8 @@ rtmsg(int cmd, int flags, int fmask, uin so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); rtm_addrs |= RTA_IFP; } + } else if (cmd == 's') { + cmd = RTM_SOURCE; } else cmd = RTM_DELETE; #define rtm m_rtmsg.m_rtm Index: sbin/route/show.c =================================================================== RCS file: /cvs/src/sbin/route/show.c,v retrieving revision 1.115 diff -u -p -r1.115 show.c --- sbin/route/show.c 15 Sep 2020 20:28:27 -0000 1.115 +++ sbin/route/show.c 17 Sep 2020 09:59:25 -0000 @@ -37,6 +37,7 @@ #include <net/if_dl.h> #include <net/if_types.h> #include <net/route.h> +#include <net/rtable.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <netmpls/mpls.h> @@ -130,6 +131,55 @@ get_sysctl(const int *mib, u_int mcnt, c return needed; } +/* + * Print preferred source address + */ +void +printsource(int af, u_int tableid) +{ + struct sockaddr *sa; + char *buf = NULL, *next, *lim = NULL; + size_t needed; + int mib[7], mcnt, size; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = af; + mib[4] = NET_RT_SOURCE; + mib[5] = tableid; + mcnt = 6; + + needed = get_sysctl(mib, mcnt, &buf); + lim = buf + needed; + + if (pledge("stdio", NULL) == -1) + err(1, "pledge"); + + printf("Preferred source address set for rdomain %d\n", tableid); + + if (buf) { + for (next = buf; next < lim; next += size) { + sa = (struct sockaddr *)next; + switch (sa->sa_family) { + case AF_INET: + size = sizeof(struct sockaddr_in); + printf("IPv4: "); + break; + case AF_INET6: + size = sizeof(struct sockaddr_in6); + printf("IPv6: "); + break; + } + p_sockaddr(sa, NULL, RTF_HOST, WID_DST(sa->sa_family)); + printf("\n"); + } + } + free(buf); + printf("\n"); + + exit(0); +} /* * Print routing tables. */ Index: sbin/route/show.h =================================================================== RCS file: /cvs/src/sbin/route/show.h,v retrieving revision 1.15 diff -u -p -r1.15 show.h --- sbin/route/show.h 31 Aug 2019 13:46:14 -0000 1.15 +++ sbin/route/show.h 17 Sep 2020 09:59:25 -0000 @@ -29,6 +29,7 @@ union sockunion { struct sockaddr_storage padding; }; +void printsource(int, u_int); void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); void p_rttables(int, u_int, char); void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int); Index: sys/kern/kern_pledge.c =================================================================== RCS file: /cvs/src/sys/kern/kern_pledge.c,v retrieving revision 1.266 diff -u -p -r1.266 kern_pledge.c --- sys/kern/kern_pledge.c 16 Sep 2020 13:50:42 -0000 1.266 +++ sys/kern/kern_pledge.c 17 Sep 2020 09:59:27 -0000 @@ -828,7 +828,7 @@ pledge_sysctl(struct proc *p, int miblen mib[0] == CTL_NET && mib[1] == PF_ROUTE && mib[2] == 0 && (mib[3] == 0 || mib[3] == AF_INET6 || mib[3] == AF_INET) && - mib[4] == NET_RT_TABLE) + (mib[4] == NET_RT_TABLE || mib[4] == NET_RT_SOURCE)) return (0); if (miblen == 7 && /* exposes MACs */ Index: sys/net/art.h =================================================================== RCS file: /cvs/src/sys/net/art.h,v retrieving revision 1.18 diff -u -p -r1.18 art.h --- sys/net/art.h 31 Mar 2019 14:03:40 -0000 1.18 +++ sys/net/art.h 17 Sep 2020 09:59:27 -0000 @@ -21,6 +21,7 @@ #include <sys/rwlock.h> #include <sys/srp.h> +#include <netinet/in.h> #define ART_MAXLVL 32 /* We currently use 32 levels for IPv6. */ @@ -35,6 +36,7 @@ struct art_root { uint8_t ar_alen; /* Address length in bits */ uint8_t ar_off; /* Offset of the key in bytes */ unsigned int ar_rtableid; /* ID of this routing table */ + struct sockaddr *source; /* optionnal src addr to use */ }; #define ISLEAF(e) (((unsigned long)(e) & 1) == 0) Index: sys/net/route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.396 diff -u -p -r1.396 route.c --- sys/net/route.c 13 Aug 2020 04:26:11 -0000 1.396 +++ sys/net/route.c 17 Sep 2020 09:59:27 -0000 @@ -1192,6 +1192,7 @@ rt_ifa_del(struct ifaddr *ifa, int flags if (flags & RTF_CONNECTED) prio = ifp->if_priority + RTP_CONNECTED; + rtable_clearsource(rdomain, ifa->ifa_addr); error = rtrequest_delete(&info, prio, ifp, &rt, rdomain); if (error == 0) { rtm_send(rt, RTM_DELETE, 0, rdomain); Index: sys/net/route.h =================================================================== RCS file: /cvs/src/sys/net/route.h,v retrieving revision 1.182 diff -u -p -r1.182 route.h --- sys/net/route.h 13 Aug 2020 04:58:22 -0000 1.182 +++ sys/net/route.h 17 Sep 2020 09:59:27 -0000 @@ -238,6 +238,7 @@ struct rt_msghdr { #define RTM_PROPOSAL 0x13 /* proposal for netconfigd */ #define RTM_CHGADDRATTR 0x14 /* address attribute change */ #define RTM_80211INFO 0x15 /* 80211 iface change */ +#define RTM_SOURCE 0x16 /* set source address */ #define RTV_MTU 0x1 /* init or lock _mtu */ #define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ Index: sys/net/rtable.c =================================================================== RCS file: /cvs/src/sys/net/rtable.c,v retrieving revision 1.69 diff -u -p -r1.69 rtable.c --- sys/net/rtable.c 21 Jun 2019 17:11:42 -0000 1.69 +++ sys/net/rtable.c 17 Sep 2020 09:59:27 -0000 @@ -31,6 +31,10 @@ #include <net/rtable.h> #include <net/route.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_var.h> + /* * Structures used by rtable_get() to retrieve the corresponding * routing table for a given pair of ``af'' and ``rtableid''. @@ -363,6 +367,79 @@ void * rtable_alloc(unsigned int rtableid, unsigned int alen, unsigned int off) { return (art_alloc(rtableid, alen, off)); +} + +int +rtable_setsource(unsigned int rtableid, struct sockaddr *src) +{ + struct art_root *ar; + + if ((ar = rtable_get(rtableid, src->sa_family)) == NULL) + return (EAFNOSUPPORT); + + /* + * Check if source address is assigned to an interface in the + * same rdomain + */ + if (ifa_ifwithaddr(src, rtableid) == NULL) { + /* Check if source address is 0.0.0.0 or :: */ + switch(src->sa_family) { + case AF_INET: + if(((struct sockaddr_in *) + src->sa_data)->sin_addr.s_addr != INADDR_ANY) + return (EINVAL); + break; + case AF_INET6: + if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) + src->sa_data)->sin6_addr)) + return (EINVAL); + break; + default: + return (EAFNOSUPPORT); + } + src = NULL; + } + + if (ar->source) { + free(ar->source, M_IFADDR, ar->source->sa_len); + ar->source = NULL; + } + + if (src) { + ar->source = malloc(src->sa_len, M_IFADDR, M_WAITOK|M_ZERO); + memcpy(ar->source, src, src->sa_len); + } + else + ar->source = NULL; + + return (0); +} + +struct sockaddr * +rtable_getsource(unsigned int rtableid, int af) +{ + struct art_root *ar; + + ar = rtable_get(rtableid, af); + if (ar == NULL) + return (NULL); + + return (ar->source); +} + +void +rtable_clearsource(unsigned int rtableid, struct sockaddr *src) +{ + struct sockaddr *addr; + + addr = rtable_getsource(rtableid, src->sa_family); + if (addr && (addr->sa_len == src->sa_len)) { + if (memcmp(src, addr, addr->sa_len) == 0) { + memset(addr->sa_data, 0, addr->sa_len- + sizeof(addr->sa_len)-sizeof(addr->sa_family)); + rtable_setsource(rtableid, addr); + } + } } struct rtentry * Index: sys/net/rtable.h =================================================================== RCS file: /cvs/src/sys/net/rtable.h,v retrieving revision 1.24 diff -u -p -r1.24 rtable.h --- sys/net/rtable.h 21 Jun 2019 17:11:42 -0000 1.24 +++ sys/net/rtable.h 17 Sep 2020 09:59:27 -0000 @@ -39,6 +39,9 @@ unsigned int rtable_l2(unsigned int); unsigned int rtable_loindex(unsigned int); void rtable_l2set(unsigned int, unsigned int, unsigned int); +int rtable_setsource(unsigned int, struct sockaddr *); +struct sockaddr *rtable_getsource(unsigned int, int); +void rtable_clearsource(unsigned int, struct sockaddr *); struct rtentry *rtable_lookup(unsigned int, struct sockaddr *, struct sockaddr *, struct sockaddr *, uint8_t); struct rtentry *rtable_match(unsigned int, struct sockaddr *, uint32_t *); Index: sys/net/rtsock.c =================================================================== RCS file: /cvs/src/sys/net/rtsock.c,v retrieving revision 1.300 diff -u -p -r1.300 rtsock.c --- sys/net/rtsock.c 13 Aug 2020 04:58:22 -0000 1.300 +++ sys/net/rtsock.c 17 Sep 2020 09:59:27 -0000 @@ -657,7 +657,10 @@ rtm_report(struct rtentry *rt, u_char ty ifp = if_get(rt->rt_ifidx); if (ifp != NULL) { info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl); - info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; + info.rti_info[RTAX_IFA] = + rtable_getsource(tableid, info.rti_info[RTAX_DST]->sa_family); + if (info.rti_info[RTAX_IFA] == NULL) + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; if (ifp->if_flags & IFF_POINTOPOINT) info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr; } @@ -691,6 +694,7 @@ route_output(struct mbuf *m, struct sock struct rt_msghdr *rtm = NULL; struct rtentry *rt = NULL; struct rt_addrinfo info; + struct ifnet *ifp; int len, seq, error = 0; u_int tableid; u_int8_t prio; @@ -733,6 +737,7 @@ route_output(struct mbuf *m, struct sock case RTM_GET: case RTM_CHANGE: case RTM_PROPOSAL: + case RTM_SOURCE: break; default: error = EOPNOTSUPP; @@ -771,7 +776,6 @@ route_output(struct mbuf *m, struct sock } } - /* Do not let userland play with kernel-only flags. */ if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0) { error = EINVAL; @@ -802,9 +806,12 @@ route_output(struct mbuf *m, struct sock if ((error = rtm_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info)) != 0) goto fail; + info.rti_flags = rtm->rtm_flags; - if (rtm->rtm_type != RTM_PROPOSAL && - (info.rti_info[RTAX_DST] == NULL || + + if (rtm->rtm_type != RTM_SOURCE && + rtm->rtm_type != RTM_PROPOSAL && + (info.rti_info[RTAX_DST] == NULL || info.rti_info[RTAX_DST]->sa_family >= AF_MAX || (info.rti_info[RTAX_GATEWAY] != NULL && info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX) || @@ -836,13 +843,20 @@ route_output(struct mbuf *m, struct sock * umb(4) will send a response to this event. */ if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { - struct ifnet *ifp; NET_LOCK(); TAILQ_FOREACH(ifp, &ifnet, if_list) { ifp->if_rtrequest(ifp, RTM_PROPOSAL, NULL); } NET_UNLOCK(); } + } else if (rtm->rtm_type == RTM_SOURCE) { + if (info.rti_info[RTAX_IFA] == NULL) { + error = EINVAL; + goto fail; + } + if ((error = + rtable_setsource(tableid, info.rti_info[RTAX_IFA])) != 0) + goto fail; } else { error = rtm_output(rtm, &rt, &info, prio, tableid); if (!error) { @@ -1666,7 +1680,10 @@ rtm_send(struct rtentry *rt, int cmd, in ifp = if_get(rt->rt_ifidx); if (ifp != NULL) { info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl); - info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; + info.rti_info[RTAX_IFA] = + rtable_getsource(rtableid, info.rti_info[RTAX_DST]->sa_family); + if (info.rti_info[RTAX_IFA] == NULL) + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; } rtm_miss(cmd, &info, rt->rt_flags, rt->rt_priority, rt->rt_ifidx, error, @@ -1904,7 +1921,10 @@ sysctl_dumpentry(struct rtentry *rt, voi ifp = if_get(rt->rt_ifidx); if (ifp != NULL) { info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl); - info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; + info.rti_info[RTAX_IFA] = + rtable_getsource(id, info.rti_info[RTAX_DST]->sa_family); + if (info.rti_info[RTAX_IFA] == NULL) + info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; if (ifp->if_flags & IFF_POINTOPOINT) info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr; } @@ -2040,6 +2060,32 @@ sysctl_ifnames(struct walkarg *w) } int +sysctl_source(int af, u_int tableid, struct walkarg *w) +{ + struct sockaddr *sa; + int size, error = 0; + + sa = rtable_getsource(tableid, af); + if (sa) { + switch (sa->sa_family) { + case AF_INET: + size = sizeof(struct sockaddr_in); + break; + case AF_INET6: + size = sizeof(struct sockaddr_in6); + break; + } + w->w_needed += size; + if (w->w_where && w->w_needed <= 0) { + if ((error = copyout(sa, w->w_where, size))) + return (error); + w->w_where += size; + } + } + return (0); +} + +int sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, size_t newlen) { @@ -2107,6 +2153,23 @@ sysctl_rtable(int *name, u_int namelen, case NET_RT_IFNAMES: NET_LOCK(); error = sysctl_ifnames(&w); + NET_UNLOCK(); + break; + case NET_RT_SOURCE: + tableid = w.w_arg; + if (!rtable_exists(tableid)) + return (ENOENT); + NET_LOCK(); + for (i = 1; i <= AF_MAX; i++) { + if (af != 0 && af != i) + continue; + + error = sysctl_source(i, tableid, &w); + if (error == EAFNOSUPPORT) + error = 0; + if (error) + break; + } NET_UNLOCK(); break; } Index: sys/netinet/in_pcb.c =================================================================== RCS file: /cvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.249 diff -u -p -r1.249 in_pcb.c --- sys/netinet/in_pcb.c 27 May 2020 20:44:07 -0000 1.249 +++ sys/netinet/in_pcb.c 17 Sep 2020 09:59:27 -0000 @@ -887,6 +887,7 @@ in_pcbselsrc(struct in_addr **insrc, str struct route *ro = &inp->inp_route; struct in_addr *laddr = &inp->inp_laddr; u_int rtableid = inp->inp_rtableid; + struct sockaddr *ip4_source = NULL; struct sockaddr_in *sin2; struct in_ifaddr *ia = NULL; @@ -923,6 +924,7 @@ in_pcbselsrc(struct in_addr **insrc, str return (0); } } + /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. @@ -947,12 +949,34 @@ in_pcbselsrc(struct in_addr **insrc, str sin2 = satosin(&ro->ro_dst); memset(sin2->sin_zero, 0, sizeof(sin2->sin_zero)); } + /* * If we found a route, use the address * corresponding to the outgoing interface. */ if (ro->ro_rt != NULL) ia = ifatoia(ro->ro_rt->rt_ifa); + + /* + * Use preferred source address if : + * - destination is not onlink + * - output interface is not PtoP + * - preferred source addresss is set + * - output interface is UP + */ + if ((ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO)) && + (ia && !(ia->ia_ifp->if_flags & IFF_POINTOPOINT))) { + ip4_source = rtable_getsource(rtableid, AF_INET); + if (ip4_source != NULL) { + struct ifaddr *ifa; + if ((ifa = ifa_ifwithaddr(ip4_source, rtableid)) != + NULL && ISSET(ifa->ifa_ifp->if_flags, IFF_UP)) { + *insrc = &((struct sockaddr_in *) + ip4_source)->sin_addr; + return (0); + } + } + } if (ia == NULL) return (EADDRNOTAVAIL); Index: sys/netinet6/in6_src.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6_src.c,v retrieving revision 1.81 diff -u -p -r1.81 in6_src.c --- sys/netinet6/in6_src.c 2 Dec 2016 11:16:04 -0000 1.81 +++ sys/netinet6/in6_src.c 17 Sep 2020 09:59:27 -0000 @@ -100,6 +100,7 @@ in6_pcbselsrc(struct in6_addr **in6src, struct in6_addr *laddr = &inp->inp_laddr6; u_int rtableid = inp->inp_rtableid; struct ifnet *ifp = NULL; + struct sockaddr *ip6_source = NULL; struct in6_addr *dst; struct in6_ifaddr *ia6 = NULL; struct in6_pktinfo *pi = NULL; @@ -215,6 +216,28 @@ in6_pcbselsrc(struct in6_addr **in6src, if (ia6 == NULL) /* xxx scope error ?*/ ia6 = ifatoia6(ro->ro_rt->rt_ifa); } + + /* + * Use preferred source address if : + * - destination is not onlink + * - output interface is not PtoP + * - preferred source addresss is set + * - output interface is UP + */ + if ((ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO)) && + (ia6 && !(ia6->ia_ifp->if_flags & IFF_POINTOPOINT))) { + ip6_source = rtable_getsource(rtableid, AF_INET6); + if (ip6_source != NULL) { + struct ifaddr *ifa; + if ((ifa = ifa_ifwithaddr(ip6_source, rtableid)) != + NULL && ISSET(ifa->ifa_ifp->if_flags, IFF_UP)) { + *in6src = &((struct sockaddr_in6 *) + ip6_source)->sin6_addr; + return (0); + } + } + } + if (ia6 == NULL) return (EHOSTUNREACH); /* no route */ Index: sys/sys/socket.h =================================================================== RCS file: /cvs/src/sys/sys/socket.h,v retrieving revision 1.98 diff -u -p -r1.98 socket.h --- sys/sys/socket.h 22 Jul 2019 15:34:07 -0000 1.98 +++ sys/sys/socket.h 17 Sep 2020 09:59:27 -0000 @@ -368,7 +368,8 @@ struct sockpeercred { #define NET_RT_STATS 4 /* routing table statistics */ #define NET_RT_TABLE 5 #define NET_RT_IFNAMES 6 -#define NET_RT_MAXID 7 +#define NET_RT_SOURCE 7 +#define NET_RT_MAXID 8 #define CTL_NET_RT_NAMES { \ { 0, 0 }, \ @@ -378,6 +379,7 @@ struct sockpeercred { { "stats", CTLTYPE_STRUCT }, \ { "table", CTLTYPE_STRUCT }, \ { "ifnames", CTLTYPE_STRUCT }, \ + { "source", CTLTYPE_STRUCT }, \ } /*