git: f262b06a57b0 - main - route: fix route get netlink translation.

From: Alexander V. Chernikov <melifaro_at_FreeBSD.org>
Date: Tue, 04 Apr 2023 08:42:41 UTC
The branch main has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=f262b06a57b03a2025bdc0ce628514cd68af73db

commit f262b06a57b03a2025bdc0ce628514cd68af73db
Author:     Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2023-04-04 08:37:14 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-04-04 08:42:33 +0000

    route: fix route get netlink translation.
    
    route.c uses newroute() to handle the "route get" command. The logic
     inside newroute() adds RTF_GATEWAY flag if "-interface" flag is not
     specified. That results in the inconsistent RTM_GET message with
     RTF_GATEWAY set but no RTAX_GATEWAY provided. Address this in the
     translation code by checking if the gateway is actually provided.
---
 sbin/route/route.c         |  4 ++--
 sbin/route/route_netlink.c | 48 +++++++++++++++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/sbin/route/route.c b/sbin/route/route.c
index 947c97ce794a..4002cbe5867b 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -118,7 +118,7 @@ static int	rtmsg_rtsock(int, int, int);
 static int	flushroutes_fib_rtsock(int);
 static void	monitor_rtsock(void);
 #else
-int		rtmsg_nl(int, int, int, struct sockaddr_storage *, struct rt_metrics *);
+int		rtmsg_nl(int, int, int, int, struct sockaddr_storage *, struct rt_metrics *);
 int		flushroutes_fib_nl(int, int);
 void		monitor_nl(int);
 #endif
@@ -1524,7 +1524,7 @@ rtmsg(int cmd, int flags, int fib)
 #ifdef WITHOUT_NETLINK
 	return (rtmsg_rtsock(cmd, flags, fib));
 #else
-	errno = rtmsg_nl(cmd, flags, fib, so, &rt_metrics);
+	errno = rtmsg_nl(cmd, flags, fib, rtm_addrs, so, &rt_metrics);
 	return (errno == 0 ? 0 : -1);
 #endif
 }
diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c
index ce7da288496f..a3e9860244a9 100644
--- a/sbin/route/route_netlink.c
+++ b/sbin/route/route_netlink.c
@@ -33,7 +33,7 @@ void printb(int, const char *);
 extern const char routeflags[];
 extern int verbose, debugonly;
 
-int rtmsg_nl(int cmd, int rtm_flags, int fib, struct sockaddr_storage *so,
+int rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs, struct sockaddr_storage *so,
     struct rt_metrics *rt_metrics);
 int flushroutes_fib_nl(int fib, int af);
 void monitor_nl(int fib);
@@ -125,8 +125,18 @@ nl_helper_free(struct nl_helper *h)
 	snl_free(&h->ss_cmd);
 }
 
+static struct sockaddr *
+get_addr(struct sockaddr_storage *so, int rtm_addrs, int addr_type)
+{
+	struct sockaddr *sa = NULL;
+
+	if (rtm_addrs & (1 << addr_type))
+		sa = (struct sockaddr *)&so[addr_type];
+	return (sa);
+}
+
 static int
-rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib,
+rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib, int rtm_addrs,
     struct sockaddr_storage *so, struct rt_metrics *rt_metrics)
 {
 	struct snl_state *ss = &h->ss_cmd;
@@ -154,9 +164,9 @@ rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib,
 		exit(1);
 	}
 
-	struct sockaddr *dst = (struct sockaddr *)&so[RTAX_DST];
-	struct sockaddr *mask = (struct sockaddr *)&so[RTAX_NETMASK];
-	struct sockaddr *gw = (struct sockaddr *)&so[RTAX_GATEWAY];
+	struct sockaddr *dst = get_addr(so, rtm_addrs, RTAX_DST);
+	struct sockaddr *mask = get_addr(so, rtm_addrs, RTAX_NETMASK);
+	struct sockaddr *gw = get_addr(so, rtm_addrs, RTAX_GATEWAY);
 
 	if (dst == NULL)
 		return (EINVAL);
@@ -210,16 +220,18 @@ rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib,
 	snl_add_msg_attr_ip(&nw, RTA_DST, dst);
 	snl_add_msg_attr_u32(&nw, RTA_TABLE, fib);
 
-	if (rtm_flags & RTF_GATEWAY) {
-		if (gw->sa_family == dst->sa_family)
-			snl_add_msg_attr_ip(&nw, RTA_GATEWAY, gw);
-		else
-			snl_add_msg_attr_ipvia(&nw, RTA_VIA, gw);
-	} else if (gw != NULL) {
-		/* Should be AF_LINK */
-		struct sockaddr_dl *sdl = (struct sockaddr_dl *)gw;
-		if (sdl->sdl_index != 0)
-			snl_add_msg_attr_u32(&nw, RTA_OIF, sdl->sdl_index);
+	if (gw != NULL) {
+		if (rtm_flags & RTF_GATEWAY) {
+			if (gw->sa_family == dst->sa_family)
+				snl_add_msg_attr_ip(&nw, RTA_GATEWAY, gw);
+			else
+				snl_add_msg_attr_ipvia(&nw, RTA_VIA, gw);
+		} else {
+			/* Should be AF_LINK */
+			struct sockaddr_dl *sdl = (struct sockaddr_dl *)gw;
+			if (sdl->sdl_index != 0)
+				snl_add_msg_attr_u32(&nw, RTA_OIF, sdl->sdl_index);
+		}
 	}
 
 	if (rtm_flags != 0)
@@ -259,13 +271,13 @@ rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib,
 }
 
 int
-rtmsg_nl(int cmd, int rtm_flags, int fib, struct sockaddr_storage *so,
-    struct rt_metrics *rt_metrics)
+rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs,
+    struct sockaddr_storage *so, struct rt_metrics *rt_metrics)
 {
 	struct nl_helper h = {};
 
 	nl_helper_init(&h);
-	int error = rtmsg_nl_int(&h, cmd, rtm_flags, fib, so, rt_metrics);
+	int error = rtmsg_nl_int(&h, cmd, rtm_flags, fib, rtm_addrs, so, rt_metrics);
 	nl_helper_free(&h);
 
 	return (error);