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