Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102190577
D31868.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
2 KB
Referenced Files
None
Subscribers
None
D31868.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D31868: routing: fix source address selection rules for IPv4 over IPv6.
Attached
Detach File
Event Timeline
Log In to Comment