route(8) cannot set a link-layer address as a gateway

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

route(8) cannot set a link-layer address as a gateway

Demi M. Obenour
>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
                         [hidden email]:/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).  1.1.1.1 is used as an example of a widely
        reachable IP address, but any other pingable address will also
        work.

        # 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");


signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

route(8) cannot set a link-layer address as a gateway

Demi M. Obenour
>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
                         [hidden email]:/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");