Thank you for the code and review! I've synthesized the existing patch
and review into something that successfully advertises router
preferences in local testing (verified w/ rdisc6). This patch does not
implement the route information option specified in RFC 4191 section
2.3.
diff --git a/usr.sbin/rad/frontend.c b/usr.sbin/rad/frontend.c
index 8178b058629..4031da6b99d 100644
--- a/usr.sbin/rad/frontend.c
+++ b/usr.sbin/rad/frontend.c
@@ -411,7 +411,7 @@ frontend_dispatch_main(int fd, short event, void *bula)
ra_prefix_conf))
fatalx("%s: IMSG_RECONF_RA_PREFIX wrong "
"length: %lu", __func__,
- IMSG_DATA_SIZE(imsg));
+ IMSG_DATA_SIZE(imsg));
if ((ra_prefix_conf = malloc(sizeof(struct
ra_prefix_conf))) == NULL)
fatal(NULL);
@@ -1023,6 +1023,18 @@ build_packet(struct ra_iface *ra_iface)
ra->nd_ra_router_lifetime =
htons(ra_options_conf->router_lifetime);
}
+
+ /* add router preference flags */
+ if (ra_options_conf->preference == ND_RA_FLAG_RTPREF_RSV) {
+ fatalx("Invalid router preference found during RA packet
construction.");
+ }
+
+ if (ra_options_conf->router_lifetime == 0) {
+ log_debug("Router lifetime set to zero; ignoring router
preference per https://tools.ietf.org/html/rfc4191#section-2.2");
+ } else {
+ ra->nd_ra_flags_reserved |= ra_options_conf->preference;
+ }
+
ra->nd_ra_reachable = htonl(ra_options_conf->reachable_time);
ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer);
p += sizeof(*ra);
diff --git a/usr.sbin/rad/parse.y b/usr.sbin/rad/parse.y
index 004e5e22f92..74480148246 100644
--- a/usr.sbin/rad/parse.y
+++ b/usr.sbin/rad/parse.y
@@ -32,6 +32,7 @@
#include <net/if.h>
#include <arpa/inet.h>
+#include <netinet/icmp6.h>
#include <ctype.h>
#include <err.h>
@@ -117,10 +118,12 @@ typedef struct {
%token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
%token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
%token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU
+%token PREFERENCE LOW MEDIUM HIGH
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> yesno
+%type <v.number> preference
%type <v.string> string
%%
@@ -166,6 +169,11 @@ yesno : YES { $$ = 1; }
| NO { $$ = 0; }
;
+preference : LOW { $$ = ND_RA_FLAG_RTPREF_LOW; }
+ | MEDIUM { $$ = ND_RA_FLAG_RTPREF_MEDIUM; }
+ | HIGH { $$ = ND_RA_FLAG_RTPREF_HIGH; }
+ ;
+
varset : STRING '=' string {
char *s = $1;
if (cmd_opts & OPT_VERBOSE)
@@ -213,6 +221,9 @@ ra_opt_block : DEFAULT ROUTER yesno {
| MTU NUMBER {
ra_options->mtu = $2;
}
+ | PREFERENCE preference {
+ ra_options->preference = $2;
+ }
| DNS dns_block
;
@@ -426,16 +437,20 @@ lookup(char *s)
{"default", DEFAULT},
{"dns", DNS},
{"hop", HOP},
+ {"high", HIGH},
{"include", INCLUDE},
{"interface", RA_IFACE},
{"lifetime", LIFETIME},
{"limit", LIMIT},
+ {"low", LOW},
{"managed", MANAGED},
+ {"medium", MEDIUM},
{"mtu", MTU},
{"nameserver", NAMESERVER},
{"no", NO},
{"on-link", ONLINK},
{"other", OTHER},
+ {"preference", PREFERENCE},
{"preferred", PREFERRED},
{"prefix", PREFIX},
{"reachable", REACHABLE},
diff --git a/usr.sbin/rad/printconf.c b/usr.sbin/rad/printconf.c
index d42890da518..c2173d2142f 100644
--- a/usr.sbin/rad/printconf.c
+++ b/usr.sbin/rad/printconf.c
@@ -26,6 +26,7 @@
#include <net/if.h>
#include <arpa/inet.h>
+#include <netinet/icmp6.h>
#include <event.h>
#include <imsg.h>
@@ -34,6 +35,7 @@
#include "rad.h"
const char* yesno(int);
+const char* preference(int);
void print_ra_options(const char*, const struct ra_options_conf*);
void print_prefix_options(const char*, const struct ra_prefix_conf*);
@@ -42,6 +44,20 @@ yesno(int flag)
{
return flag ? "yes" : "no";
}
+const char*
+preference(int p)
+{
+ switch (p) {
+ case ND_RA_FLAG_RTPREF_LOW:
+ return "low";
+ case ND_RA_FLAG_RTPREF_MEDIUM:
+ return "medium";
+ case ND_RA_FLAG_RTPREF_HIGH:
+ return "high";
+ default:
+ return "invalid";
+ }
+}
void
print_ra_options(const char *indent, const struct ra_options_conf *ra_options)
@@ -60,6 +76,9 @@ print_ra_options(const char *indent, const struct
ra_options_conf *ra_options)
printf("%sretrans timer %u\n", indent, ra_options->retrans_timer);
if (ra_options->mtu > 0)
printf("%smtu %u\n", indent, ra_options->mtu);
+ if (ra_options->preference != ND_RA_FLAG_RTPREF_RSV)
+ printf("%spreference %s\n", indent,
+ preference(ra_options->preference));
if (!SIMPLEQ_EMPTY(&ra_options->ra_rdnss_list) ||
!SIMPLEQ_EMPTY(&ra_options->ra_dnssl_list)) {
diff --git a/usr.sbin/rad/rad.c b/usr.sbin/rad/rad.c
index 93675167b6b..cb0593f11ab 100644
--- a/usr.sbin/rad/rad.c
+++ b/usr.sbin/rad/rad.c
@@ -433,7 +433,7 @@ main_dispatch_frontend(int fd, short event, void *bula)
case IMSG_CTL_LOG_VERBOSE:
if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
- "%lu", __func__, IMSG_DATA_SIZE(imsg));
+ "%lu", __func__, IMSG_DATA_SIZE(imsg));
memcpy(&verbose, imsg.data, sizeof(verbose));
log_setverbose(verbose);
break;
@@ -754,6 +754,7 @@ config_new_empty(void)
xconf->ra_options.cur_hl = 0;
xconf->ra_options.m_flag = 0;
xconf->ra_options.o_flag = 0;
+ xconf->ra_options.preference = ND_RA_FLAG_RTPREF_MEDIUM;
xconf->ra_options.router_lifetime = 1800;
xconf->ra_options.reachable_time = 0;
xconf->ra_options.retrans_timer = 0;
diff --git a/usr.sbin/rad/rad.conf.5 b/usr.sbin/rad/rad.conf.5
index f651a715d1a..b822f3d195d 100644
--- a/usr.sbin/rad/rad.conf.5
+++ b/usr.sbin/rad/rad.conf.5
@@ -107,6 +107,8 @@ The default is 1800 seconds.
.\" XXX
.\" .It Ic retrans timer Ar number
.\" XXX
+.It Ic preference Pq Ic low Ns | Ns Ic medium Ns | Ns Ic high
+Communicate router preference to clients. The default is medium.
.El
.Sh INTERFACES
A list of interfaces or interface groups to send advertisments on:
diff --git a/usr.sbin/rad/rad.h b/usr.sbin/rad/rad.h
index 2bbf7c8ed5c..cfaa5e88638 100644
--- a/usr.sbin/rad/rad.h
+++ b/usr.sbin/rad/rad.h
@@ -92,6 +92,7 @@ struct ra_options_conf {
int cur_hl; /* current hop limit */
int m_flag; /* managed address conf flag */
int o_flag; /* other conf flag */
+ int preference; /* router preference (see RFC 4191 2.2) */
int router_lifetime; /* default router lifetime */
uint32_t reachable_time;
uint32_t retrans_timer;
On Wed, Aug 7, 2019 at 2:04 AM Florian Obser <[email protected]> wrote:
>
> On Tue, Aug 06, 2019 at 11:17:04PM +0200, Sebastian Benoit wrote:
> > Caleb([email protected]) on 2019.08.06 08:05:48 -0700:
> > > How do I publish default router preferences as defined in RFC 4191
> > > (https://tools.ietf.org/html/rfc4191) using rad in OpenBSD 6.5?
> > > I've read the friendly rad.conf man page
> > > (https://man.openbsd.org/rad.conf.5) and scanned the source
> > > (https://github.com/openbsd/src/tree/master/usr.sbin/rad) with no
> > > success.
> >
> > You can't, because it was not implemented.
> >
> > That is, until now.
> >
> > I wrote a patch, which you can test if you like. It's completly untested
> > though.
> >
>
> needs more yak shaving
>
> >
> > diff --git usr.sbin/rad/frontend.c usr.sbin/rad/frontend.c
> > index 8178b058629..75723797fcf 100644
> > --- usr.sbin/rad/frontend.c
> > +++ usr.sbin/rad/frontend.c
> > @@ -1016,6 +1016,8 @@ build_packet(struct ra_iface *ra_iface)
> > ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
> > if (ra_options_conf->o_flag)
> > ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
> > + ra->nd_ra_flags_reserved |=
> > + ra_options_conf->preference;
> > if (ra_iface->removed)
> > /* tell clients that we are no longer a default router */
> > ra->nd_ra_router_lifetime = 0;
> > @@ -1048,6 +1050,8 @@ build_packet(struct ra_iface *ra_iface)
> > if (ra_prefix_conf->aflag)
> > ndopt_pi->nd_opt_pi_flags_reserved |=
> > ND_OPT_PI_FLAG_AUTO;
> > + ndopt_pi->nd_opt_pi_flags_reserved |=
> > + ra_prefix_conf->preference;
>
> This is a prefix information option (type 3) not a route information option
> (type 24).
> Option 3 does not have a preference.
>
> > ndopt_pi->nd_opt_pi_valid_time =
> > htonl(ra_prefix_conf->vltime);
> > ndopt_pi->nd_opt_pi_preferred_time =
> > htonl(ra_prefix_conf->pltime);
> > diff --git usr.sbin/rad/parse.y usr.sbin/rad/parse.y
> > index 004e5e22f92..b004ab37356 100644
> > --- usr.sbin/rad/parse.y
> > +++ usr.sbin/rad/parse.y
> > @@ -106,6 +106,7 @@ typedef struct {
> > union {
> > int64_t number;
> > char *string;
> > + short pref;
>
> eek, just treat it as a number?
>
> > } v;
> > int lineno;
> > } YYSTYPE;
> > @@ -117,11 +118,13 @@ typedef struct {
> > %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
> > %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
> > %token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU
> > +%token PREFERENCE LOW MEDIUM HIGH
> >
> > %token <v.string> STRING
> > %token <v.number> NUMBER
> > %type <v.number> yesno
> > %type <v.string> string
> > +%type <v.pref> preftype
> >
> > %%
> >
> > @@ -213,6 +216,9 @@ ra_opt_block : DEFAULT ROUTER yesno {
> > | MTU NUMBER {
> > ra_options->mtu = $2;
> > }
> > + | PREFERENCE preftype {
> > + ra_options->preference = $2;
> > + }
> > | DNS dns_block
> > ;
> >
> > @@ -298,6 +304,19 @@ ra_prefixoptsl : VALID LIFETIME NUMBER {
> > | AUTONOMOUS ADDRESS_CONFIGURATION yesno {
> > ra_prefix_conf->aflag = $3;
> > }
> > + | PREFERENCE preftype {
> > + ra_prefix_conf->preference = $2;
> > + }
> > + ;
>
> see above, we are announcing prefix information, not route information
>
> > +preftype : LOW {
> > + $$ = RA_PREFIXOPT_PREF_LOW;
> > + }
> > + | MEDIUM {
> > + $$ = RA_PREFIXOPT_PREF_MEDIUM;
> > + }
> > + | HIGH {
> > + $$ = RA_PREFIXOPT_PREF_HIGH;
> > + }
>
> please use the defines from icmp6.h:
>
> #define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */
> #define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */
> #define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */
> #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
>
>
> > ;
> > dns_block : '{' optnl dnsopts_l '}'
> > | '{' optnl '}'
> > @@ -425,17 +444,21 @@ lookup(char *s)
> > {"configuration", CONFIGURATION},
> > {"default", DEFAULT},
> > {"dns", DNS},
> > + {"high", HIGH},
> > {"hop", HOP},
> > {"include", INCLUDE},
> > {"interface", RA_IFACE},
> > {"lifetime", LIFETIME},
> > {"limit", LIMIT},
> > + {"low", LOW},
> > {"managed", MANAGED},
> > + {"medium", MEDIUM},
> > {"mtu", MTU},
> > {"nameserver", NAMESERVER},
> > {"no", NO},
> > {"on-link", ONLINK},
> > {"other", OTHER},
> > + {"preference", PREFERENCE},
> > {"preferred", PREFERRED},
> > {"prefix", PREFIX},
> > {"reachable", REACHABLE},
> > diff --git usr.sbin/rad/printconf.c usr.sbin/rad/printconf.c
> > index d42890da518..e063daaa19f 100644
> > --- usr.sbin/rad/printconf.c
> > +++ usr.sbin/rad/printconf.c
> > @@ -34,6 +34,7 @@
> > #include "rad.h"
> >
> > const char* yesno(int);
> > +const char* preference(short);
>
> make this an in ^
>
> > void print_ra_options(const char*, const struct ra_options_conf*);
> > void print_prefix_options(const char*, const struct
> > ra_prefix_conf*);
> >
> > @@ -43,6 +44,21 @@ yesno(int flag)
> > return flag ? "yes" : "no";
> > }
> >
> > +const char*
> > +preference(short p)
> ^ and here
> > +{
> > + switch (p) {
> > + case RA_PREFIXOPT_PREF_LOW:
> > + return "low";
> > + case RA_PREFIXOPT_PREF_MEDIUM:
> > + return "medium";
> > + case RA_PREFIXOPT_PREF_HIGH:
> > + return "high";
> > + default:
> > + return "invalid";
>
> use the defines from icmp6.h
>
> > + }
> > +}
> > +
> > void
> > print_ra_options(const char *indent, const struct ra_options_conf
> > *ra_options)
> > {
> > @@ -60,6 +76,9 @@ print_ra_options(const char *indent, const struct
> > ra_options_conf *ra_options)
> > printf("%sretrans timer %u\n", indent, ra_options->retrans_timer);
> > if (ra_options->mtu > 0)
> > printf("%smtu %u\n", indent, ra_options->mtu);
> > + if (ra_options->preference > 0)
>
> this does not work, if you set the default in the config file (medium)
> it will never get printed since it's 0, but maybe that's your
> intention? I'd store ND_RA_FLAG_RTPREF_RSV as default and map it to
> medium when building the packet. Then you can match on it here.
>
>
> > + printf("%spreference %s\n", indent,
> > + preference(ra_options->preference));
> >
> > if (!SIMPLEQ_EMPTY(&ra_options->ra_rdnss_list) ||
> > !SIMPLEQ_EMPTY(&ra_options->ra_dnssl_list)) {
> > @@ -95,6 +114,8 @@ print_prefix_options(const char *indent, const struct
> > ra_prefix_conf
> > printf("%son-link %s\n", indent, yesno(ra_prefix_conf->lflag));
> > printf("%sautonomous address-configuration %s\n", indent,
> > yesno(ra_prefix_conf->aflag));
> > + printf("%spreference %s\n", indent,
> > + preference(ra_prefix_conf->preference));
>
> Prefix Information, not Route Information
>
> > }
> >
> > void
> > diff --git usr.sbin/rad/rad.conf.5 usr.sbin/rad/rad.conf.5
> > index f651a715d1a..888a8f79b76 100644
> > --- usr.sbin/rad/rad.conf.5
> > +++ usr.sbin/rad/rad.conf.5
> > @@ -107,6 +107,11 @@ The default is 1800 seconds.
> > .\" XXX
> > .\" .It Ic retrans timer Ar number
> > .\" XXX
> > +.It Ic preference Pq Ic low Ns | Ns Ic medium Ns | Ns Ic high
> > +Specify the router preference that is communicated to hosts through
> > +router advertisements.
> > +It can be used to communicate a prefered default router to IPv6 hosts.
> > +The default is medium.
> > .El
> > .Sh INTERFACES
> > A list of interfaces or interface groups to send advertisments on:
> > @@ -147,6 +152,9 @@ The default is 604800.
> > The valid lifetime (vltime) in seconds for addresses generated from this
> > prefix.
> > The default is 2592000.
> > +.It Ic preference Pq Ic low Ns | Ns Ic medium Ns | Ns Ic high
> > +The preference of the prefix is low, medium or high.
> > +The default is medium.
>
> Prefix Information vs. Route Informatiuon
>
> > .El
> > .Sh FILES
> > .Bl -tag -width "/etc/rad.conf" -compact
> > diff --git usr.sbin/rad/rad.h usr.sbin/rad/rad.h
> > index 2bbf7c8ed5c..9508783da2e 100644
> > --- usr.sbin/rad/rad.h
> > +++ usr.sbin/rad/rad.h
> > @@ -93,6 +93,7 @@ struct ra_options_conf {
> > int m_flag; /* managed address conf flag
> > */
> > int o_flag; /* other conf flag */
> > int router_lifetime; /* default router lifetime */
> > + short preference; /* rfc4191 def. router pref.
> > */
>
> ^ make it an int
>
> > uint32_t reachable_time;
> > uint32_t retrans_timer;
> > uint32_t mtu;
> > @@ -112,8 +113,17 @@ struct ra_prefix_conf {
> > uint32_t pltime; /* prefered lifetime
> > */
> > int lflag; /* on-link flag*/
> > int aflag; /* autonom. addr flag
> > */
> > + short preference; /* preference rfc4191
> > */
>
>
> Prefix Information vs. Route Information
>
> > };
> >
> > +/*
> > + RFC4191 preference values, in the middle of the 8bit reserved field.
> > + 01 High, 00 Medium (default), 11 Low, 10 Reserved - MUST NOT be sent
> > +*/
> > +#define RA_PREFIXOPT_PREF_LOW 0x18
> > +#define RA_PREFIXOPT_PREF_MEDIUM 0x00
> > +#define RA_PREFIXOPT_PREF_HIGH 0x08
> > +
>
> see above, use the defines from icmp6.h
>
> > struct ra_iface_conf {
> > SIMPLEQ_ENTRY(ra_iface_conf) entry;
> > struct ra_options_conf ra_options;
>
> --
> I'm not entirely sure you are real.