Both RTA_IFP and RTA_GATEWAY can use a sockaddr_dl struct.  If either
specifies an explicit interface index, it must be honored.  If both do,
and they are not equal, that is an error.  It is also an error if RTA_IFP
specifies an index of 0.

Furthermore, if RTA_GATEWAY specifies a sockaddr_dl, it must not be used
where an AF_INET or AF_INET6 address is required.
---
 sys/net/rtsock.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git sys/net/rtsock.c sys/net/rtsock.c
index a156674fa6a..0ddab28272a 100644
--- sys/net/rtsock.c
+++ sys/net/rtsock.c
@@ -1221,6 +1221,7 @@ int
 rtm_getifa(struct rt_addrinfo *info, unsigned int rtid)
 {
        struct ifnet    *ifp = NULL;
+       uint16_t        if_index = 0;
 
        /*
         * The "returned" `ifa' is guaranteed to be alive only if
@@ -1229,16 +1230,29 @@ rtm_getifa(struct rt_addrinfo *info, unsigned int rtid)
        NET_ASSERT_LOCKED();
 
        /*
-        * ifp may be specified by sockaddr_dl; if so, it must be honored.
+        * ifp and/or gateway may be specified by sockaddr_dl; if so, it must be
+        * honored.
         */
        if (info->rti_info[RTAX_IFP] != NULL) {
-               struct sockaddr_dl *sdl;
+               if_index = satosdl(info->rti_info[RTAX_IFP])->sdl_index;
+               if (if_index == 0)
+                       return (EINVAL);
+       }
+
+       if (info->rti_info[RTAX_GATEWAY] != NULL &&
+           info->rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) {
+               uint16_t gateway_if;
 
-               sdl = satosdl(info->rti_info[RTAX_IFP]);
-               if ((ifp = if_get(sdl->sdl_index)) == NULL)
-                       return (ENXIO);
+               gateway_if = satosdl(info->rti_info[RTAX_GATEWAY])->sdl_index;
+               if (if_index == 0)
+                       if_index = gateway_if;
+               else if (gateway_if != if_index)
+                       return (EINVAL);
        }
 
+       if (if_index != 0 && (ifp = if_get(if_index)) == NULL)
+               return (ENXIO);
+
 #ifdef IPSEC
        /*
         * If the destination is a PF_KEY address, we'll look
@@ -1269,7 +1283,8 @@ rtm_getifa(struct rt_addrinfo *info, unsigned int rtid)
                struct sockaddr *sa;
 
                if ((sa = info->rti_info[RTAX_IFA]) == NULL)
-                       if ((sa = info->rti_info[RTAX_GATEWAY]) == NULL)
+                       if ((sa = info->rti_info[RTAX_GATEWAY]) == NULL ||
+                           sa->sa_family == AF_LINK)
                                sa = info->rti_info[RTAX_DST];
 
                if (sa != NULL && ifp != NULL)
-- 
2.26.2


Reply via email to