Page MenuHomeFreeBSD

D31868.diff
No OneTemporary

D31868.diff

diff --git a/sys/net/route.c b/sys/net/route.c
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -534,6 +534,41 @@
return (NULL);
}
+/*
+ * Calculates proper ifa/ifp for the cases when gateway AF is different
+ * from dst AF.
+ *
+ * Returns 0 on success.
+ */
+__noinline static int
+rt_getifa_family(struct rt_addrinfo *info, uint32_t fibnum)
+{
+ if (info->rti_ifp == NULL) {
+ struct ifaddr *ifa = NULL;
+ /*
+ * No transmit interface specified. Guess it by checking gw sa.
+ */
+ const struct sockaddr *gw = info->rti_info[RTAX_GATEWAY];
+ ifa = ifa_ifwithroute(RTF_GATEWAY, gw, gw, fibnum);
+ if (ifa == NULL)
+ return (ENETUNREACH);
+ info->rti_ifp = ifa->ifa_ifp;
+ }
+
+ /* Prefer address from outgoing interface */
+ info->rti_ifa = ifaof_ifpforaddr(info->rti_info[RTAX_DST], info->rti_ifp);
+#ifdef INET
+ if (info->rti_ifa == NULL) {
+ /* Use first found IPv4 address */
+ bool loopback_ok = info->rti_ifp->if_flags & IFF_LOOPBACK;
+ info->rti_ifa = (struct ifaddr *)in_findlocal(fibnum, loopback_ok);
+ }
+#endif
+ if (info->rti_ifa == NULL)
+ return (ENETUNREACH);
+ return (0);
+}
+
/*
* Look up rt_addrinfo for a specific fib.
*
@@ -566,6 +601,9 @@
*/
if (info->rti_ifa == NULL && ifaaddr != NULL)
info->rti_ifa = ifa_ifwithaddr(ifaaddr);
+ if ((info->rti_ifa == NULL) && ((info->rti_flags & RTF_GATEWAY) != 0) &&
+ (gateway->sa_family != dst->sa_family))
+ return (rt_getifa_family(info, fibnum));
if (info->rti_ifa == NULL) {
const struct sockaddr *sa;
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -651,6 +651,7 @@
int in_localaddr(struct in_addr);
int in_localip(struct in_addr);
int in_ifhasaddr(struct ifnet *, struct in_addr);
+struct in_ifaddr *in_findlocal(uint32_t, bool);
int inet_aton(const char *, struct in_addr *); /* in libkern */
char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */
char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -188,6 +188,40 @@
return (NULL);
}
+/*
+ * Tries to find first IPv4 address in the provided fib.
+ * Prefers non-loopback addresses and return loopback IFF
+ * @loopback_ok is set.
+ *
+ * Returns ifa or NULL.
+ */
+struct in_ifaddr *
+in_findlocal(uint32_t fibnum, bool loopback_ok)
+{
+ struct rm_priotracker in_ifa_tracker;
+ struct in_ifaddr *ia = NULL, *ia_lo = NULL;
+
+ NET_EPOCH_ASSERT();
+
+ IN_IFADDR_RLOCK(&in_ifa_tracker);
+ CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
+ uint32_t ia_fib = ia->ia_ifa.ifa_ifp->if_fib;
+ if (!V_rt_add_addr_allfibs && (fibnum != ia_fib))
+ continue;
+
+ if (!IN_LOOPBACK(ntohl(IA_SIN(ia)->sin_addr.s_addr)))
+ break;
+ if (loopback_ok)
+ ia_lo = ia;
+ }
+ IN_IFADDR_RUNLOCK(&in_ifa_tracker);
+
+ if (ia == NULL)
+ ia = ia_lo;
+
+ return (ia);
+}
+
/*
* Determine whether an IP address is in a reserved set of addresses
* that may not be forwarded, or whether datagrams to that destination

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 9, 5:50 PM (20 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14563658
Default Alt Text
D31868.diff (2 KB)

Event Timeline