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.
This commit is contained in:
Alexander V. Chernikov 2023-04-04 08:37:14 +00:00
parent e46be58cca
commit f262b06a57
2 changed files with 32 additions and 20 deletions

View file

@ -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
}

View file

@ -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);