>Synopsis:      Cannot set a link-layer address as a gateway with route(8)
>Category:      system
>Environment:
        System      : OpenBSD 6.7
        Details     : OpenBSD 6.7-current (GENERIC) #49: Sat Aug 29 09:59:25 
MDT 2020
                         
[email protected]:/usr/src/sys/arch/amd64/compile/GENERIC

        Architecture: OpenBSD.amd64
        Machine     : amd64
>Description:
        If I pass a link-layer address as the gateway argument to
        route(8), it (incorrectly) parses it as a (nonexistent)
        interface name.  This causes the route to be rejected by the
        kernel with a confusing error.
>How-To-Repeat:
        The following command reproduces the command 100% of the time
        for me.  GW_IFACE should be set to the IP address of the
        interface used to connect to your default gateway.  GW_MAC
        should be set to the link-layer address of your default gateway
        (*not* your computer).

        # route -vn -- add -static -iface -inet default -link "$GW_MAC" -inet 
-ifa "$GW_IFACE" -expire 0

        As indicated by the verbose output, route(8) sends a "link#0"
        sockaddr to the kernel, which is presumably not what the user
        intended.  I expect that it will send a sockaddr_dl containing
        the MAC address of the interface.

>Fix:
        The following patch remedies the problem for me:

Index: sbin/route/route.c
===================================================================
RCS file: /cvs/src/sbin/route/route.c,v
retrieving revision 1.248
diff -u -p -r1.248 route.c
--- sbin/route/route.c  7 Jul 2020 14:53:36 -0000       1.248
+++ sbin/route/route.c  19 Aug 2020 21:22:15 -0000
@@ -39,6 +39,7 @@
 #include <net/if_types.h>
 #include <net/route.h>
 #include <netinet/in.h>
+#include <netinet/if_ether.h>
 #include <netmpls/mpls.h>
 
 #ifdef BFD
@@ -791,6 +792,7 @@ int
 getaddr(int which, int af, char *s, struct hostent **hpp)
 {
        sup su = NULL;
+       struct ether_addr *ether;
        struct hostent *hp;
        int aflength, afamily, bits;
 
@@ -899,8 +901,16 @@ getaddr(int which, int af, char *s, stru
            }
 
        case AF_LINK:
-               su->sdl.sdl_index = if_nametoindex(s);
                memset(&su->sdl.sdl_data, 0, sizeof(su->sdl.sdl_data));
+               if (which == RTA_IFP) {
+                       if ((su->sdl.sdl_index = if_nametoindex(s)) == 0)
+                               errx(1, "no network interface %s", s);
+                       return (1);
+               }
+               if ((ether = ether_aton(s)) == NULL)
+                       errx(1, "invalid ethernet address %s", s);
+               memcpy(LLADDR(&su->sdl), ether, sizeof(*ether));
+               su->sdl.sdl_alen = sizeof(*ether);
                return (1);
        case AF_MPLS:
                errx(1, "mpls labels require -in or -out switch");

Reply via email to