Implement RFC 8106: IPv6 Router Advertisement Options for DNS
authorflorian <florian@openbsd.org>
Sun, 15 Jul 2018 09:28:21 +0000 (09:28 +0000)
committerflorian <florian@openbsd.org>
Sun, 15 Jul 2018 09:28:21 +0000 (09:28 +0000)
Configuration.

usr.sbin/rad/engine.c
usr.sbin/rad/frontend.c
usr.sbin/rad/parse.y
usr.sbin/rad/printconf.c
usr.sbin/rad/rad.c
usr.sbin/rad/rad.conf.5
usr.sbin/rad/rad.h

index 9ecb93d..5d18643 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: engine.c,v 1.6 2018/07/11 19:05:25 florian Exp $      */
+/*     $OpenBSD: engine.c,v 1.7 2018/07/15 09:28:21 florian Exp $      */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -43,9 +43,6 @@
 #include "rad.h"
 #include "engine.h"
 
-#define        MAX_RTR_ADV_INTERVAL            600
-#define        MIN_RTR_ADV_INTERVAL            200
-
 struct engine_iface {
        TAILQ_ENTRY(engine_iface)       entry;
        struct event                    timer;
@@ -267,6 +264,8 @@ engine_dispatch_main(int fd, short event, void *bula)
        struct imsgev                   *iev = bula;
        struct imsgbuf                  *ibuf;
        struct ra_prefix_conf           *ra_prefix_conf;
+       struct ra_rdnss_conf            *ra_rdnss_conf;
+       struct ra_dnssl_conf            *ra_dnssl_conf;
        ssize_t                          n;
        int                              shut = 0;
 
@@ -335,6 +334,8 @@ engine_dispatch_main(int fd, short event, void *bula)
                            sizeof(struct ra_iface_conf));
                        ra_iface_conf->autoprefix = NULL;
                        SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
+                       SIMPLEQ_INIT(&ra_iface_conf->ra_rdnss_list);
+                       SIMPLEQ_INIT(&ra_iface_conf->ra_dnssl_list);
                        SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
                            ra_iface_conf, entry);
                        break;
@@ -354,6 +355,27 @@ engine_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,
                            ra_prefix_conf, entry);
                        break;
+               case IMSG_RECONF_RA_RDNS_LIFETIME:
+                       ra_iface_conf->rdns_lifetime = *((uint32_t *)imsg.data);
+                       break;
+               case IMSG_RECONF_RA_RDNSS:
+                       if ((ra_rdnss_conf = malloc(sizeof(struct
+                           ra_rdnss_conf))) == NULL)
+                               fatal(NULL);
+                       memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
+                           ra_rdnss_conf));
+                       SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
+                           ra_rdnss_conf, entry);
+                       break;
+               case IMSG_RECONF_RA_DNSSL:
+                       if ((ra_dnssl_conf = malloc(sizeof(struct
+                           ra_dnssl_conf))) == NULL)
+                               fatal(NULL);
+                       memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
+                           ra_dnssl_conf));
+                       SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
+                           ra_dnssl_conf, entry);
+                       break;
                case IMSG_RECONF_END:
                        merge_config(engine_conf, nconf);
                        nconf = NULL;
index 2fa5d7c..c9d2c8e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: frontend.c,v 1.9 2018/07/15 09:26:26 florian Exp $    */
+/*     $OpenBSD: frontend.c,v 1.10 2018/07/15 09:28:21 florian Exp $   */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -308,6 +308,8 @@ frontend_dispatch_main(int fd, short event, void *bula)
        struct imsgev                   *iev = bula;
        struct imsgbuf                  *ibuf = &iev->ibuf;
        struct ra_prefix_conf           *ra_prefix_conf;
+       struct ra_rdnss_conf            *ra_rdnss_conf;
+       struct ra_dnssl_conf            *ra_dnssl_conf;
        int                              n, shut = 0;
 
        if (event & EV_READ) {
@@ -374,6 +376,8 @@ frontend_dispatch_main(int fd, short event, void *bula)
                            ra_iface_conf));
                        ra_iface_conf->autoprefix = NULL;
                        SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
+                       SIMPLEQ_INIT(&ra_iface_conf->ra_rdnss_list);
+                       SIMPLEQ_INIT(&ra_iface_conf->ra_dnssl_list);
                        SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
                            ra_iface_conf, entry);
                        break;
@@ -393,6 +397,27 @@ frontend_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,
                            ra_prefix_conf, entry);
                        break;
+               case IMSG_RECONF_RA_RDNS_LIFETIME:
+                       ra_iface_conf->rdns_lifetime = *((uint32_t *)imsg.data);
+                       break;
+               case IMSG_RECONF_RA_RDNSS:
+                       if ((ra_rdnss_conf = malloc(sizeof(struct
+                           ra_rdnss_conf))) == NULL)
+                               fatal(NULL);
+                       memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
+                           ra_rdnss_conf));
+                       SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
+                           ra_rdnss_conf, entry);
+                       break;
+               case IMSG_RECONF_RA_DNSSL:
+                       if ((ra_dnssl_conf = malloc(sizeof(struct
+                           ra_dnssl_conf))) == NULL)
+                               fatal(NULL);
+                       memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
+                           ra_dnssl_conf));
+                       SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
+                           ra_dnssl_conf, entry);
+                       break;
                case IMSG_RECONF_END:
                        merge_config(frontend_conf, nconf);
                        merge_ra_interfaces();
@@ -866,8 +891,13 @@ build_packet(struct ra_iface *ra_iface)
        struct ra_iface_conf            *ra_iface_conf;
        struct ra_options_conf          *ra_options_conf;
        struct ra_prefix_conf           *ra_prefix_conf;
-       size_t                           len;
+       struct nd_opt_rdnss             *ndopt_rdnss;
+       struct nd_opt_dnssl             *ndopt_dnssl;
+       struct ra_rdnss_conf            *ra_rdnss;
+       struct ra_dnssl_conf            *ra_dnssl;
+       size_t                           len, label_len;
        uint8_t                         *p, buf[RA_MAX_SIZE];
+       char                            *label_start, *label_end;
 
        ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
            ra_iface->name);
@@ -875,6 +905,14 @@ build_packet(struct ra_iface *ra_iface)
 
        len = sizeof(*ra);
        len += sizeof(*ndopt_pi) * ra_iface->prefix_count;
+       if (ra_iface_conf->rdnss_count > 0)
+               len += sizeof(*ndopt_rdnss) + ra_iface_conf->rdnss_count *
+                   sizeof(struct in6_addr);
+
+       if (ra_iface_conf->dnssl_len > 0)
+               /* round up to 8 byte boundary */
+               len += sizeof(*ndopt_dnssl) + ((ra_iface_conf->dnssl_len + 7)
+                   & ~7);
 
        if (len > sizeof(ra_iface->data))
                fatal("%s: packet too big", __func__); /* XXX send multiple */
@@ -922,6 +960,50 @@ build_packet(struct ra_iface *ra_iface)
                p += sizeof(*ndopt_pi);
        }
 
+       if (ra_iface_conf->rdnss_count > 0) {
+               ndopt_rdnss = (struct nd_opt_rdnss *)p;
+               ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+               ndopt_rdnss->nd_opt_rdnss_len = 1 +
+                   ra_iface_conf->rdnss_count * 2;
+               ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+               ndopt_rdnss->nd_opt_rdnss_lifetime =
+                   htonl(ra_iface_conf->rdns_lifetime);
+               p += sizeof(struct nd_opt_rdnss);
+               SIMPLEQ_FOREACH(ra_rdnss, &ra_iface_conf->ra_rdnss_list, 
+                   entry) {
+                       memcpy(p, &ra_rdnss->rdnss, sizeof(ra_rdnss->rdnss));
+                       p += sizeof(ra_rdnss->rdnss);
+               }
+       }
+
+       if (ra_iface_conf->dnssl_len > 0) {
+               ndopt_dnssl = (struct nd_opt_dnssl *)p;
+               ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+               /* round up to 8 byte boundary */
+               ndopt_dnssl->nd_opt_dnssl_len = 1 +
+                   ((ra_iface_conf->dnssl_len + 7) & ~7) / 8;
+               ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+               ndopt_dnssl->nd_opt_dnssl_lifetime =
+                   htonl(ra_iface_conf->rdns_lifetime);
+               p += sizeof(struct nd_opt_dnssl);
+
+               SIMPLEQ_FOREACH(ra_dnssl, &ra_iface_conf->ra_dnssl_list,
+                   entry) {
+                       label_start = ra_dnssl->search;
+                       while ((label_end = strchr(label_start, '.')) != NULL) {
+                               label_len = label_end - label_start;
+                               *p++ = label_len;
+                               memcpy(p, label_start, label_len);
+                               p += label_len;
+                               label_start = label_end + 1;
+                       }
+                       *p++ = '\0'; /* last dot */
+               }
+               /* zero pad */
+               while (((uintptr_t)p) % 8 != 0)
+                       *p++ = '\0';
+       }
+
        if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len)
            != 0) {
                memcpy(ra_iface->data, buf, len);
index bb2ce2b..582d165 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.2 2018/07/11 08:47:03 florian Exp $       */
+/*     $OpenBSD: parse.y,v 1.3 2018/07/15 09:28:21 florian Exp $       */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -115,7 +115,7 @@ typedef struct {
 %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
 %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
 %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
-%token ADDRESS_CONFIGURATION
+%token ADDRESS_CONFIGURATION DNS RESOLVER SEARCH
 
 %token <v.string>      STRING
 %token <v.number>      NUMBER
@@ -265,6 +265,7 @@ ra_ifaceoptsl       : NO AUTO PREFIX {
                } ra_prefix_block {
                        ra_prefix_conf = NULL;
                }
+               | DNS dns_block
                | ra_opt_block
                ;
 
@@ -290,7 +291,91 @@ ra_prefixoptsl     : VALID LIFETIME NUMBER {
                        ra_prefix_conf->aflag = $3;
                }
                ;
+dns_block      : '{' optnl dnsopts_l '}'
+               | '{' optnl '}'
+               | /* empty */
+               ;
+
+dnsopts_l      : dnsopts_l dnsoptsl nl
+               | dnsoptsl optnl
+               ;
 
+dnsoptsl       : LIFETIME NUMBER {
+                       ra_iface_conf->rdns_lifetime = $2;
+               }
+               | RESOLVER resolver_block
+               | SEARCH search_block
+               ;
+resolver_block : '{' optnl resolveropts_l '}'
+               | '{' optnl '}'
+               | resolveroptsl
+               | /* empty */
+               ;
+
+resolveropts_l : resolveropts_l resolveroptsl optnl
+               | resolveroptsl optnl
+               ;
+
+resolveroptsl  : STRING {
+                       struct ra_rdnss_conf    *ra_rdnss_conf;
+                       struct in6_addr          addr;
+
+                       memset(&addr, 0, sizeof(addr));
+                       if (inet_pton(AF_INET6, $1, &addr)
+                           != 1) {
+                               yyerror("error parsing resolver address %s",
+                                   $1);
+                               free($1);
+                               YYERROR;
+                       }
+                       if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf)))
+                           == NULL)
+                               err(1, "%s", __func__);
+                       memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr));
+                       SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
+                           ra_rdnss_conf, entry);
+                       ra_iface_conf->rdnss_count++;
+               }
+               ;
+search_block   : '{' optnl searchopts_l '}'
+               | '{' optnl '}'
+               | searchoptsl
+               | /* empty */
+               ;
+
+searchopts_l   : searchopts_l searchoptsl optnl
+               | searchoptsl optnl
+               ;
+
+searchoptsl    : STRING {
+                       struct ra_dnssl_conf    *ra_dnssl_conf;
+                       size_t                   len;
+
+                       if ((ra_dnssl_conf = calloc(1,
+                           sizeof(*ra_dnssl_conf))) == NULL)
+                               err(1, "%s", __func__);
+
+                       if ((len = strlcpy(ra_dnssl_conf->search, $1,
+                           sizeof(ra_dnssl_conf->search))) >
+                           sizeof(ra_dnssl_conf->search)) {
+                               yyerror("search string too long");
+                               free($1);
+                               YYERROR;
+                       }
+                       if (ra_dnssl_conf->search[len] != '.') {
+                               if ((len = strlcat(ra_dnssl_conf->search, ".",
+                                   sizeof(ra_dnssl_conf->search))) >
+                                   sizeof(ra_dnssl_conf->search)) {
+                                       yyerror("search string too long");
+                                       free($1);
+                                       YYERROR;
+                               }
+                       }
+                       SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
+                           ra_dnssl_conf, entry);
+                       ra_iface_conf->dnssl_len += len + 1;
+               }
+               ;
 %%
 
 struct keywords {
@@ -331,6 +416,7 @@ lookup(char *s)
                {"autonomous",          AUTONOMOUS},
                {"configuration",       CONFIGURATION},
                {"default",             DEFAULT},
+               {"dns",                 DNS},
                {"hop",                 HOP},
                {"include",             INCLUDE},
                {"interface",           RA_IFACE},
@@ -343,8 +429,10 @@ lookup(char *s)
                {"preferred",           PREFERRED},
                {"prefix",              PREFIX},
                {"reachable",           REACHABLE},
+               {"resolver",            RESOLVER},
                {"retrans",             RETRANS},
                {"router",              ROUTER},
+               {"search",              SEARCH},
                {"time",                TIME},
                {"timer",               TIMER},
                {"valid",               VALID},
@@ -870,7 +958,11 @@ conf_get_ra_iface(char *name)
        /* Inherit attributes set in global section. */
        iface->ra_options = conf->ra_options;
 
+       iface->rdns_lifetime = DEFAULT_RDNS_LIFETIME;
+
        SIMPLEQ_INIT(&iface->ra_prefix_list);
+       SIMPLEQ_INIT(&iface->ra_rdnss_list);
+       SIMPLEQ_INIT(&iface->ra_dnssl_list);
 
        SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
 
index 57ccb2c..1fc8cd4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: printconf.c,v 1.1 2018/07/10 16:39:54 florian Exp $   */
+/*     $OpenBSD: printconf.c,v 1.2 2018/07/15 09:28:21 florian Exp $   */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -72,6 +72,8 @@ print_config(struct rad_conf *conf)
 {
        struct ra_iface_conf    *iface;
        struct ra_prefix_conf   *prefix;
+       struct ra_rdnss_conf    *ra_rdnss;
+       struct ra_dnssl_conf    *ra_dnssl;
        char                     buf[INET6_ADDRSTRLEN], *bufp;
 
        print_ra_options("", &conf->ra_options);
@@ -97,6 +99,30 @@ print_config(struct rad_conf *conf)
                        printf("\t}\n");
                }
 
+               if (!SIMPLEQ_EMPTY(&iface->ra_rdnss_list) ||
+                   !SIMPLEQ_EMPTY(&iface->ra_dnssl_list)) {
+                       printf("\tdns {\n");
+                       printf("\t\tlifetime %u\n", iface->rdns_lifetime);
+                       if (!SIMPLEQ_EMPTY(&iface->ra_rdnss_list)) {
+                               printf("\t\tresolver {\n");
+                               SIMPLEQ_FOREACH(ra_rdnss,
+                                   &iface->ra_rdnss_list, entry) {
+                                       inet_ntop(AF_INET6, &ra_rdnss->rdnss,
+                                           buf, sizeof(buf));
+                                       printf("\t\t\t%s\n", buf);
+                               }
+                               printf("\t\t}\n");
+                       }
+                       if (!SIMPLEQ_EMPTY(&iface->ra_dnssl_list)) {
+                               printf("\t\tsearch {\n");
+                               SIMPLEQ_FOREACH(ra_dnssl,
+                                   &iface->ra_dnssl_list, entry)
+                                       printf("\t\t\t%s\n", ra_dnssl->search);
+                               printf("\t\t}\n");
+                       }
+                       printf("\t}\n");
+               }
+
                printf("}\n");
        }
 }
index c184c8c..36b68f2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rad.c,v 1.7 2018/07/13 09:16:15 florian Exp $ */
+/*     $OpenBSD: rad.c,v 1.8 2018/07/15 09:28:21 florian Exp $ */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -594,6 +594,8 @@ main_imsg_send_config(struct rad_conf *xconf)
 {
        struct ra_iface_conf    *ra_iface_conf;
        struct ra_prefix_conf   *ra_prefix_conf;
+       struct ra_rdnss_conf    *ra_rdnss_conf;
+       struct ra_dnssl_conf    *ra_dnssl_conf;
 
        /* Send fixed part of config to children. */
        if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
@@ -616,6 +618,22 @@ main_imsg_send_config(struct rad_conf *xconf)
                            ra_prefix_conf, sizeof(*ra_prefix_conf)) == -1)
                                return (-1);
                }
+               if (main_sendboth(IMSG_RECONF_RA_RDNS_LIFETIME,
+                   &ra_iface_conf->rdns_lifetime,
+                   sizeof(ra_iface_conf->rdns_lifetime)) == -1)
+                       return (-1);
+               SIMPLEQ_FOREACH(ra_rdnss_conf, &ra_iface_conf->ra_rdnss_list,
+                   entry) {
+                       if (main_sendboth(IMSG_RECONF_RA_RDNSS, ra_rdnss_conf,
+                           sizeof(*ra_rdnss_conf)) == -1)
+                               return (-1);
+               }
+               SIMPLEQ_FOREACH(ra_dnssl_conf, &ra_iface_conf->ra_dnssl_list,
+                   entry) {
+                       if (main_sendboth(IMSG_RECONF_RA_DNSSL, ra_dnssl_conf,
+                           sizeof(*ra_dnssl_conf)) == -1)
+                               return (-1);
+               }
        }
 
        /* Tell children the revised config is now complete. */
index b0c10e4..286d174 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: rad.conf.5,v 1.4 2018/07/15 09:27:02 florian Exp $
+.\"    $OpenBSD: rad.conf.5,v 1.5 2018/07/15 09:28:21 florian Exp $
 .\"
 .\" Copyright (c) 2018 Florian Obser <florian@openbsd.org>
 .\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
@@ -125,6 +125,26 @@ The valid lifetime (vltime) in seconds for addresses generated from this
 prefix.
 The default is 2592000.
 .El
+.Pp
+Recursive resolvers are configured inside an interface block:
+.Bd -unfilled -offset indent
+.Ic dns Brq dns options
+.Ed
+.Pp
+.Ic dns
+options are as follows:
+.Bl -tag -width Ds
+.It Ic lifetime Ar seconds
+The number of seconds the dns options are valid after receiving a router
+advertisement message.
+The default is 900 seconds.
+.It Ic resolver Pq Ar IP Ns | Ns { resolver list }
+IPv6 address or list of IPv6 addresses of recursive dns resolvers.
+.It Ic search Pq Ar domain Ns | Ns { domain list }
+Domain or list of domains for the
+.Xr resolv.conf 5
+search list.
+.El
 .Sh FILES
 .Bl -tag -width "/etc/rad.conf" -compact
 .It Pa /etc/rad.conf
index 22f296a..db80d7c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rad.h,v 1.10 2018/07/15 09:25:41 florian Exp $        */
+/*     $OpenBSD: rad.h,v 1.11 2018/07/15 09:28:21 florian Exp $        */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
 #define OPT_NOACTION   0x00000004
 
 
+#define        MAX_RTR_ADV_INTERVAL            600
+#define        MIN_RTR_ADV_INTERVAL            200
+#define        MAX_SEARCH 1025 /* same as MAXDNAME in arpa/nameser.h */
+#define        DEFAULT_RDNS_LIFETIME           600 * 1.5
+
 enum {
        PROC_MAIN,
        PROC_ENGINE,
@@ -54,6 +59,9 @@ enum imsg_type {
        IMSG_RECONF_RA_IFACE,
        IMSG_RECONF_RA_AUTOPREFIX,
        IMSG_RECONF_RA_PREFIX,
+       IMSG_RECONF_RA_RDNS_LIFETIME,
+       IMSG_RECONF_RA_RDNSS,
+       IMSG_RECONF_RA_DNSSL,
        IMSG_RECONF_END,
        IMSG_ICMP6SOCK,
        IMSG_ROUTESOCK,
@@ -90,13 +98,28 @@ struct ra_prefix_conf {
        int                              aflag;         /* autonom. addr flag */
 };
 
+/* RFC 8106 */
+struct ra_rdnss_conf {
+       SIMPLEQ_ENTRY(ra_rdnss_conf)    entry;
+       struct in6_addr                 rdnss;
+};
+struct ra_dnssl_conf {
+       SIMPLEQ_ENTRY(ra_dnssl_conf)    entry;
+       char                            search[MAX_SEARCH];
+};
+
 struct ra_iface_conf {
-       SIMPLEQ_ENTRY(ra_iface_conf)     entry;
-       struct ra_options_conf           ra_options;
-       struct ra_prefix_conf           *autoprefix;
+       SIMPLEQ_ENTRY(ra_iface_conf)             entry;
+       struct ra_options_conf                   ra_options;
+       struct ra_prefix_conf                   *autoprefix;
        SIMPLEQ_HEAD(ra_prefix_conf_head,
-           ra_prefix_conf)              ra_prefix_list;
-       char                             name[IF_NAMESIZE];
+           ra_prefix_conf)                      ra_prefix_list;
+       uint32_t                                 rdns_lifetime;
+       SIMPLEQ_HEAD(, ra_rdnss_conf)            ra_rdnss_list;
+       int                                      rdnss_count;
+       SIMPLEQ_HEAD(, ra_dnssl_conf)            ra_dnssl_list;
+       int                                      dnssl_len;
+       char                                     name[IF_NAMESIZE];
 };
 
 struct rad_conf {