From: florian Date: Fri, 17 May 2024 06:50:14 +0000 (+0000) Subject: Send source link-layer address option in router advertisements. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=30ca340796a98c20c16842cbd6e4c25de4709bdb;p=openbsd Send source link-layer address option in router advertisements. With this, hosts immediately learn the layer 2 (i.e. ethernet mac) address of their default router and don't need to do another round trip. It also turns out that apple devices (macOS & iOS) install the default route as what they call "interface scoped" if a DNS option is present and the source link-layer address option is absent. This effectively makes the default route unusable. Problem with fruit devices tracked down & diff by Ryan Vogt (rvogt.ca AT gmail), thanks! OK sthen, bket --- diff --git a/usr.sbin/rad/frontend.c b/usr.sbin/rad/frontend.c index 6748e43732d..ca8719a4a1b 100644 --- a/usr.sbin/rad/frontend.c +++ b/usr.sbin/rad/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.45 2024/04/23 22:11:59 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.46 2024/05/17 06:50:14 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -120,6 +121,12 @@ struct nd_opt_pref64 { u_int8_t nd_opt_pref64[12]; }; +struct nd_opt_source_link_addr { + u_int8_t nd_opt_source_link_addr_type; + u_int8_t nd_opt_source_link_addr_len; + struct ether_addr nd_opt_source_link_addr_hw_addr; +}; + TAILQ_HEAD(, ra_iface) ra_interfaces; __dead void frontend_shutdown(void); @@ -1099,6 +1106,7 @@ void build_packet(struct ra_iface *ra_iface) { struct nd_router_advert *ra; + struct nd_opt_source_link_addr *ndopt_source_link_addr; struct nd_opt_mtu *ndopt_mtu; struct nd_opt_prefix_info *ndopt_pi; struct ra_iface_conf *ra_iface_conf; @@ -1110,6 +1118,8 @@ build_packet(struct ra_iface *ra_iface) struct ra_rdnss_conf *ra_rdnss; struct ra_dnssl_conf *ra_dnssl; struct ra_pref64_conf *pref64; + struct ifaddrs *ifap, *ifa; + struct sockaddr_dl *sdl; size_t len, label_len; uint8_t *p, buf[RA_MAX_SIZE]; char *label_start, *label_end; @@ -1119,6 +1129,8 @@ build_packet(struct ra_iface *ra_iface) ra_options_conf = &ra_iface_conf->ra_options; len = sizeof(*ra); + if (ra_iface_conf->ra_options.source_link_addr) + len += sizeof(*ndopt_source_link_addr); if (ra_options_conf->mtu > 0) len += sizeof(*ndopt_mtu); len += sizeof(*ndopt_pi) * ra_iface->prefix_count; @@ -1170,6 +1182,37 @@ build_packet(struct ra_iface *ra_iface) ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer); p += sizeof(*ra); + if (ra_iface_conf->ra_options.source_link_addr) { + ndopt_source_link_addr = (struct nd_opt_source_link_addr *)p; + ndopt_source_link_addr->nd_opt_source_link_addr_type = + ND_OPT_SOURCE_LINKADDR; + ndopt_source_link_addr->nd_opt_source_link_addr_len = 1; + if (getifaddrs(&ifap) != 0) { + ifap = NULL; + log_warn("getifaddrs"); + } + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || + ifa->ifa_addr->sa_family != AF_LINK) + continue; + if (strcmp(ra_iface->name, ifa->ifa_name) != 0) + continue; + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + if (sdl->sdl_type != IFT_ETHER || + sdl->sdl_alen != ETHER_ADDR_LEN) + continue; + memcpy(&ndopt_source_link_addr-> + nd_opt_source_link_addr_hw_addr, + LLADDR(sdl), ETHER_ADDR_LEN); + break; + } + if (ifap != NULL) { + freeifaddrs(ifap); + p += sizeof(*ndopt_source_link_addr); + } else + len -= sizeof(*ndopt_source_link_addr); + } + if (ra_options_conf->mtu > 0) { ndopt_mtu = (struct nd_opt_mtu *)p; ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; diff --git a/usr.sbin/rad/parse.y b/usr.sbin/rad/parse.y index 66cc0c0ab64..bf6b6e6b86d 100644 --- a/usr.sbin/rad/parse.y +++ b/usr.sbin/rad/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.22 2024/04/23 22:11:59 florian Exp $ */ +/* $OpenBSD: parse.y,v 1.23 2024/05/17 06:50:14 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -122,6 +122,7 @@ typedef struct { %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER %token AUTO PREFIX VALID PREFERENCE PREFERRED LIFETIME ONLINK AUTONOMOUS %token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64 HIGH MEDIUM LOW +%token SOURCE LINK_LAYER %token STRING %token NUMBER @@ -226,6 +227,9 @@ ra_opt_block : DEFAULT ROUTER yesno { | RETRANS TIMER NUMBER { ra_options->retrans_timer = $3; } + | SOURCE LINK_LAYER ADDRESS yesno { + ra_options->source_link_addr = $4; + } | MTU NUMBER { ra_options->mtu = $2; } @@ -523,6 +527,7 @@ lookup(char *s) {"interface", RA_IFACE}, {"lifetime", LIFETIME}, {"limit", LIMIT}, + {"link-layer", LINK_LAYER}, {"low", LOW}, {"managed", MANAGED}, {"medium", MEDIUM}, @@ -539,6 +544,7 @@ lookup(char *s) {"retrans", RETRANS}, {"router", ROUTER}, {"search", SEARCH}, + {"source", SOURCE}, {"time", TIME}, {"timer", TIMER}, {"valid", VALID}, diff --git a/usr.sbin/rad/printconf.c b/usr.sbin/rad/printconf.c index 184a5df2dc1..b49a7748ae7 100644 --- a/usr.sbin/rad/printconf.c +++ b/usr.sbin/rad/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.8 2024/04/23 22:11:59 florian Exp $ */ +/* $OpenBSD: printconf.c,v 1.9 2024/05/17 06:50:14 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -78,6 +78,8 @@ print_ra_options(const char *indent, const struct ra_options_conf *ra_options) printf("%srouter lifetime %d\n", indent, ra_options->router_lifetime); printf("%sreachable time %u\n", indent, ra_options->reachable_time); printf("%sretrans timer %u\n", indent, ra_options->retrans_timer); + printf("%ssource link-layer address %s\n", indent, + yesno(ra_options->source_link_addr)); if (ra_options->mtu > 0) printf("%smtu %u\n", indent, ra_options->mtu); diff --git a/usr.sbin/rad/rad.c b/usr.sbin/rad/rad.c index b283e58fbf1..a0c317265b0 100644 --- a/usr.sbin/rad/rad.c +++ b/usr.sbin/rad/rad.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rad.c,v 1.29 2023/04/19 12:58:16 jsg Exp $ */ +/* $OpenBSD: rad.c,v 1.30 2024/05/17 06:50:14 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -757,6 +757,7 @@ config_new_empty(void) xconf->ra_options.router_lifetime = ADV_DEFAULT_LIFETIME; xconf->ra_options.reachable_time = 0; xconf->ra_options.retrans_timer = 0; + xconf->ra_options.source_link_addr = 1; xconf->ra_options.mtu = 0; xconf->ra_options.rdns_lifetime = DEFAULT_RDNS_LIFETIME; SIMPLEQ_INIT(&xconf->ra_options.ra_rdnss_list); diff --git a/usr.sbin/rad/rad.conf.5 b/usr.sbin/rad/rad.conf.5 index f82ccfd216e..87c2b328662 100644 --- a/usr.sbin/rad/rad.conf.5 +++ b/usr.sbin/rad/rad.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rad.conf.5,v 1.23 2024/04/23 22:17:49 florian Exp $ +.\" $OpenBSD: rad.conf.5,v 1.24 2024/05/17 06:50:14 florian Exp $ .\" .\" Copyright (c) 2018 Florian Obser .\" Copyright (c) 2005 Esben Norby @@ -18,7 +18,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 23 2024 $ +.Dd $Mdocdate: May 17 2024 $ .Dt RAD.CONF 5 .Os .Sh NAME @@ -127,6 +127,10 @@ The default is medium. .\" XXX .\" .It Ic retrans timer Ar number .\" XXX +.It Ic source link-layer address Pq Ic yes Ns | Ns Ic no +Add a source link-layer address option to router advertisement messages, to +communicate the link-layer address of the sending interface. +The default is yes. .El .Sh INTERFACES A list of interfaces or interface groups to send advertisements on: diff --git a/usr.sbin/rad/rad.h b/usr.sbin/rad/rad.h index 787e78c7c4a..442ff00fcce 100644 --- a/usr.sbin/rad/rad.h +++ b/usr.sbin/rad/rad.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rad.h,v 1.26 2024/04/23 22:11:59 florian Exp $ */ +/* $OpenBSD: rad.h,v 1.27 2024/05/17 06:50:14 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -97,6 +97,7 @@ struct ra_options_conf { int router_lifetime; /* default router lifetime */ uint32_t reachable_time; uint32_t retrans_timer; + int source_link_addr; /* source link-layer address */ uint32_t mtu; uint32_t rdns_lifetime; SIMPLEQ_HEAD(, ra_rdnss_conf) ra_rdnss_list;