treewide: rework logic to retrieve IPv6 interface addresses
authorHans Dedecker <dedeckeh@gmail.com>
Thu, 29 Jun 2017 13:35:21 +0000 (15:35 +0200)
committerHans Dedecker <dedeckeh@gmail.com>
Mon, 3 Jul 2017 09:32:53 +0000 (11:32 +0200)
Retrieve IPv6 interface addresses when the interface gets created; this
allows to get rid of the IPv6 address dump logic in ndp.c.
Add IPv4 address support in odhcp_ipaddr struct.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
src/config.c
src/dhcpv6-ia.c
src/dhcpv6.c
src/dhcpv6.h
src/ndp.c
src/odhcpd.c
src/odhcpd.h
src/router.c

index 1276b6f8ef6adf00d24e26c9e910ee57d5d6e313..e6f23828d4538bf5725728e8d225858b768e1e9b 100644 (file)
@@ -388,6 +388,8 @@ err:
 int config_parse_interface(void *data, size_t len, const char *name, bool overwrite)
 {
        struct blob_attr *tb[IFACE_ATTR_MAX], *c;
+       bool get_addrs = false;
+
        blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, data, len);
 
        if (tb[IFACE_ATTR_INTERFACE])
@@ -409,7 +411,7 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
                set_interface_defaults(iface);
 
                list_add(&iface->head, &interfaces);
-               overwrite = true;
+               get_addrs = overwrite = true;
        }
 
        const char *ifname = NULL;
@@ -439,6 +441,14 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
        if ((iface->ifindex = if_nametoindex(iface->ifname)) <= 0)
                goto err;
 
+       if (get_addrs) {
+               ssize_t len = odhcpd_get_interface_addresses(iface->ifindex,
+                                               true, &iface->ia_addr);
+
+               if (len > 0)
+                       iface->ia_addr_len = len;
+       }
+
        iface->inuse = true;
 
        if ((c = tb[IFACE_ATTR_DYNAMICDHCP]))
@@ -823,7 +833,6 @@ void odhcpd_reload(void)
                        close_interface(i);
        }
 
-       ndp_handle_addr6_dump();
        uci_unload(uci, dhcp);
        uci_free_context(uci);
 }
index c2221d81baf1fe56dbe4ee2cf62f7d8e178e2a6f..502373fd9904c8c6e4b362c7332c6c3cbc45152b 100644 (file)
@@ -248,7 +248,7 @@ void dhcpv6_enum_ia_addrs(struct interface *iface, struct dhcpv6_assignment *c,
                if (!valid_addr(&addrs[i], now))
                        continue;
 
-               addr = addrs[i].addr;
+               addr = addrs[i].addr.in6;
                pref = addrs[i].preferred;
                valid = addrs[i].valid;
                if (prefix == 128) {
@@ -444,7 +444,7 @@ static void apply_lease(struct interface *iface, struct dhcpv6_assignment *a, bo
        size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
 
        for (size_t i = 0; i < addrlen; ++i) {
-               struct in6_addr prefix = addrs[i].addr;
+               struct in6_addr prefix = addrs[i].addr.in6;
                prefix.s6_addr32[1] |= htonl(a->assigned);
                prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0;
                odhcpd_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length,
@@ -661,11 +661,12 @@ void dhcpv6_ia_preupdate(struct interface *iface)
                        apply_lease(iface, c, false);
 }
 
-void dhcpv6_ia_postupdate(struct interface *iface, time_t now)
+void dhcpv6_ia_postupdate(struct interface *iface)
 {
        if (iface->dhcpv6 != RELAYD_SERVER)
                return;
 
+       time_t now = odhcpd_time();
        int minprefix = -1;
        for (size_t i = 0; i < iface->ia_addr_len; ++i) {
                if (iface->ia_addr[i].preferred > (uint32_t)now &&
@@ -802,7 +803,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                                .preferred = htonl(prefix_pref),
                                                .valid = htonl(prefix_valid),
                                                .prefix = (a->managed_size) ? addrs[i].prefix : a->length,
-                                               .addr = addrs[i].addr
+                                               .addr = addrs[i].addr.in6,
                                        };
                                        p.addr.s6_addr32[1] |= htonl(a->assigned);
                                        p.addr.s6_addr32[2] = p.addr.s6_addr32[3] = 0;
@@ -820,7 +821,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                        struct dhcpv6_ia_addr n = {
                                                .type = htons(DHCPV6_OPT_IA_ADDR),
                                                .len = htons(sizeof(n) - 4),
-                                               .addr = addrs[i].addr,
+                                               .addr = addrs[i].addr.in6,
                                                .preferred = htonl(prefix_pref),
                                                .valid = htonl(prefix_valid)
                                        };
@@ -879,7 +880,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                                if (!valid_addr(&addrs[i], now))
                                                        continue;
 
-                                               struct in6_addr addr = addrs[i].addr;
+                                               struct in6_addr addr = addrs[i].addr.in6;
                                                if (ia->type == htons(DHCPV6_OPT_IA_PD)) {
                                                        addr.s6_addr32[1] |= htonl(a->assigned);
                                                        addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
index 3128968b8629d2bc593038f509b072d617826b33..4ecb54ab35c441de190b55792dfe8e9272c65bea 100644 (file)
@@ -90,9 +90,6 @@ int setup_dhcpv6_interface(struct interface *iface, bool enable)
                if (iface->dhcpv6 == RELAYD_SERVER)
                        setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &server, sizeof(server));
 
-               if (iface->dhcpv6 != RELAYD_RELAY || !iface->master)
-                       ndp_rqs_addr6_dump();
-
                iface->dhcpv6_event.uloop.fd = sock;
                iface->dhcpv6_event.handle_dgram = handle_dhcpv6;
                odhcpd_register(&iface->dhcpv6_event);
@@ -336,7 +333,7 @@ static void handle_client_request(void *addr, void *data, size_t len,
 
                        if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)) {
                                struct odhcpd_ipaddr *addrs;
-                               ssize_t len = odhcpd_get_interface_addresses(0, &addrs);
+                               ssize_t len = odhcpd_get_interface_addresses(0, true, &addrs);
 
                                for (ssize_t i = 0; i < len; ++i)
                                        if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)
@@ -483,6 +480,26 @@ static void relay_server_response(uint8_t *data, size_t len)
        odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface);
 }
 
+static struct odhcpd_ipaddr *relay_link_address(struct interface *iface)
+{
+       struct odhcpd_ipaddr *addr = NULL;
+       time_t now = odhcpd_time();
+
+       for (size_t i = 0; i < iface->ia_addr_len; i++) {
+               if (iface->ia_addr[i].valid <= (uint32_t)now)
+                       continue;
+
+               if (iface->ia_addr[i].preferred > (uint32_t)now) {
+                       addr = &iface->ia_addr[i];
+                       break;
+               }
+
+               if (!addr || (iface->ia_addr[i].valid > addr->valid))
+                       addr = &iface->ia_addr[i];
+       }
+
+       return addr;
+}
 
 // Relay client request (regular DHCPv6-relay)
 static void relay_client_request(struct sockaddr_in6 *source,
@@ -522,18 +539,19 @@ static void relay_client_request(struct sockaddr_in6 *source,
        memcpy(&hdr.interface_id_data, &ifindex, sizeof(ifindex));
 
        // Detect public IP of slave interface to use as link-address
-       struct odhcpd_ipaddr *ip = NULL;
-       if (odhcpd_get_interface_addresses(iface->ifindex, &ip) < 1) {
+       struct odhcpd_ipaddr *ip = relay_link_address(iface);
+       if (!ip) {
                // No suitable address! Is the slave not configured yet?
                // Detect public IP of master interface and use it instead
                // This is WRONG and probably violates the RFC. However
                // otherwise we have a hen and egg problem because the
                // slave-interface cannot be auto-configured.
-               if (odhcpd_get_interface_addresses(master->ifindex, &ip) < 1)
+               ip = relay_link_address(master);
+               if (!ip)
                        return; // Could not obtain a suitable address
        }
-       memcpy(&hdr.link_address, &ip[0].addr, sizeof(hdr.link_address));
-       free(ip);
+
+       memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
 
        struct sockaddr_in6 dhcpv6_servers = {AF_INET6,
                        htons(DHCPV6_SERVER_PORT), 0, ALL_DHCPV6_SERVERS, 0};
index b38ae829616f8bfff9547ce56ceb6c82e64bd4a6..e58cb69ad9144058f0a41157954cdc4755bfffef 100644 (file)
@@ -190,4 +190,4 @@ void dhcpv6_enum_ia_addrs(struct interface *iface, struct dhcpv6_assignment *c,
                                dhcpv6_binding_cb_handler_t func, void *arg);
 void dhcpv6_write_statefile(void);
 void dhcpv6_ia_preupdate(struct interface *iface);
-void dhcpv6_ia_postupdate(struct interface *iface, time_t now);
+void dhcpv6_ia_postupdate(struct interface *iface);
index 8488fc57ca8278c7c0f91f06bbb9c0ebe67653a2..94b7e96a491e665b5e0727e4e96d538c35ec6018 100644 (file)
--- a/src/ndp.c
+++ b/src/ndp.c
@@ -48,7 +48,6 @@ static void handle_rtnl_event(struct odhcpd_event *ev);
 static int cb_rtnl_valid(struct nl_msg *msg, void *arg);
 static void catch_rtnl_err(struct odhcpd_event *e, int error);
 
-static int addr6_dump_rqs = 0;
 static int ping_socket = -1;
 static struct event_socket rtnl_event = {
        .ev = {
@@ -150,11 +149,11 @@ static void dump_neigh_table(const bool proxy)
        nlmsg_free(msg);
 }
 
-static void dump_addr6_table(void)
+static void dump_addr_table(bool v6)
 {
        struct nl_msg *msg;
        struct ifaddrmsg ifa = {
-               .ifa_family = AF_INET6,
+               .ifa_family = v6 ? AF_INET6 : AF_INET,
        };
 
        msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP);
@@ -168,20 +167,6 @@ static void dump_addr6_table(void)
        nlmsg_free(msg);
 }
 
-void ndp_handle_addr6_dump(void)
-{
-       if (!addr6_dump_rqs)
-               return;
-
-       dump_addr6_table();
-       addr6_dump_rqs = 0;
-}
-
-inline void ndp_rqs_addr6_dump(void)
-{
-       addr6_dump_rqs++;
-}
-
 int setup_ndp_interface(struct interface *iface, bool enable)
 {
        int ret = 0, procfd;
@@ -253,8 +238,6 @@ int setup_ndp_interface(struct interface *iface, bool enable)
                        dump_neigh_table(false);
                else
                        dump_neigh = false;
-
-               ndp_rqs_addr6_dump();
        }
 
        if (dump_neigh)
@@ -340,38 +323,18 @@ static void setup_route(struct in6_addr *addr, struct interface *iface, bool add
                odhcpd_setup_route(addr, 128, iface, NULL, 1024, add);
 }
 
-// compare prefixes
-static int prefixcmp(const void *va, const void *vb)
-{
-       const struct odhcpd_ipaddr *a = va, *b = vb;
-       uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr) ? 1 : a->preferred;
-       uint32_t b_pref = IN6_IS_ADDR_ULA(&b->addr) ? 1 : b->preferred;
-       return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0;
-}
-
 // Check address update
-static void check_addr_updates(struct interface *iface)
+static void check_addr6_updates(struct interface *iface)
 {
        struct odhcpd_ipaddr *addr = NULL;
-       time_t now = odhcpd_time();
-       ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, &addr);
+       ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, true, &addr);
 
        if (len < 0)
                return;
 
-       qsort(addr, len, sizeof(*addr), prefixcmp);
-
-       for (int i = 0; i < len; ++i) {
-               if (addr[i].preferred < UINT32_MAX - now)
-                       addr[i].preferred += now;
-
-               if (addr[i].valid < UINT32_MAX - now)
-                       addr[i].valid += now;
-       }
-
        bool change = len != (ssize_t)iface->ia_addr_len;
        for (ssize_t i = 0; !change && i < len; ++i)
-               if (!IN6_ARE_ADDR_EQUAL(&addr[i].addr, &iface->ia_addr[i].addr) ||
+               if (!IN6_ARE_ADDR_EQUAL(&addr[i].addr.in6, &iface->ia_addr[i].addr.in6) ||
                                (addr[i].preferred > 0) != (iface->ia_addr[i].preferred > 0) ||
                                addr[i].valid < iface->ia_addr[i].valid ||
                                addr[i].preferred < iface->ia_addr[i].preferred)
@@ -385,7 +348,7 @@ static void check_addr_updates(struct interface *iface)
        iface->ia_addr_len = len;
 
        if (change)
-               dhcpv6_ia_postupdate(iface, now);
+               dhcpv6_ia_postupdate(iface);
 
        if (change) {
                syslog(LOG_INFO, "Raising SIGUSR1 due to address change on %s", iface->ifname);
@@ -477,7 +440,7 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
                syslog(LOG_DEBUG, "Netlink %s %s%%%s", true ? "newaddr" : "deladdr",
                        ipbuf, iface->ifname);
 
-               check_addr_updates(iface);
+               check_addr6_updates(iface);
 
                if (iface->ndp != RELAYD_RELAY)
                        break;
@@ -562,7 +525,7 @@ static void catch_rtnl_err(struct odhcpd_event *e, int error)
        if (nl_socket_set_buffer_size(ev_sock->sock, ev_sock->sock_bufsize, 0))
                goto err;
 
-       dump_addr6_table();
+       dump_addr_table(true);
        return;
 
 err:
index ee628a5715994a0b5812aa890f4e12e7aca4f416..6f38d5c1c06117aa182ea9862234ba76cff6e24e 100644 (file)
@@ -222,6 +222,7 @@ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
 
 struct addr_info {
        int ifindex;
+       int af;
        struct odhcpd_ipaddr **addrs;
        int pending;
        ssize_t ret;
@@ -240,6 +241,7 @@ static int cb_valid_handler(struct nl_msg *msg, void *arg)
 
        ifa = NLMSG_DATA(hdr);
        if (ifa->ifa_scope != RT_SCOPE_UNIVERSE ||
+                       (ctxt->af != ifa->ifa_family) ||
                        (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex))
                return NL_SKIP;
 
@@ -293,12 +295,21 @@ static int cb_error_handler(_unused struct sockaddr_nl *nla, struct nlmsgerr *er
        return NL_STOP;
 }
 
+// compare prefixes
+static int prefixcmp(const void *va, const void *vb)
+{
+       const struct odhcpd_ipaddr *a = va, *b = vb;
+       uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred;
+       uint32_t b_pref = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred;
+       return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0;
+}
+
 // Detect an IPV6-address currently assigned to the given interface
-ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr **addrs)
+ssize_t odhcpd_get_interface_addresses(int ifindex, bool v6, struct odhcpd_ipaddr **addrs)
 {
        struct nl_msg *msg;
        struct ifaddrmsg ifa = {
-               .ifa_family = AF_INET6,
+               .ifa_family = v6? AF_INET6: AF_INET,
                .ifa_prefixlen = 0,
                .ifa_flags = 0,
                .ifa_scope = 0,
@@ -306,6 +317,7 @@ ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr **addrs
        struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
        struct addr_info ctxt = {
                .ifindex = ifindex,
+               .af = v6? AF_INET6: AF_INET,
                .addrs = addrs,
                .ret = 0,
                .pending = 1,
@@ -334,6 +346,23 @@ ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr **addrs
                nl_recvmsgs(rtnl_socket, cb);
 
        nlmsg_free(msg);
+
+       if (ctxt.ret <= 0)
+               goto out;
+
+       time_t now = odhcpd_time();
+       struct odhcpd_ipaddr *addr = *addrs;
+
+       qsort(addr, ctxt.ret, sizeof(*addr), prefixcmp);
+
+       for (ssize_t i = 0; i < ctxt.ret; ++i) {
+               if (addr[i].preferred < UINT32_MAX - now)
+                       addr[i].preferred += now;
+
+               if (addr[i].valid < UINT32_MAX - now)
+                       addr[i].valid += now;
+       }
+
 out:
        nl_cb_put(cb);
 
@@ -383,12 +412,12 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr
                                iface->ia_addr[i].preferred < (uint32_t)now)
                        continue;
 
-               if (IN6_IS_ADDR_ULA(&iface->ia_addr[i].addr)) {
-                       if (!IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr)) {
+               if (IN6_IS_ADDR_ULA(&iface->ia_addr[i].addr.in6)) {
+                       if (!IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr.in6)) {
                                m = i;
                                continue;
                        }
-               } else if (IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr))
+               } else if (IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr.in6))
                        continue;
 
                if (iface->ia_addr[i].preferred > iface->ia_addr[m].preferred)
@@ -396,7 +425,7 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr
        }
 
        if (m >= 0) {
-               *addr = iface->ia_addr[m].addr;
+               *addr = iface->ia_addr[m].addr.in6;
                return 0;
        }
 
index 8a196eac6c81948dae407c5ef1648299fe6f053e..28eb88e00a5c7972ae43317b9ca3a3e4b70b7f0b 100644 (file)
@@ -68,10 +68,16 @@ struct odhcpd_event {
        void (*recv_msgs)(struct odhcpd_event *e);
 };
 
+union if_addr {
+       struct in_addr in;
+       struct in6_addr in6;
+};
 
 struct odhcpd_ipaddr {
-       struct in6_addr addr;
+       union if_addr addr;
        uint8_t prefix;
+
+       /* ipv6 only */
        uint8_t dprefix;
        uint32_t preferred;
        uint32_t valid;
@@ -203,7 +209,7 @@ struct nl_sock *odhcpd_create_nl_socket(int protocol);
 ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
                struct iovec *iov, size_t iov_len,
                const struct interface *iface);
-ssize_t odhcpd_get_interface_addresses(int ifindex,
+ssize_t odhcpd_get_interface_addresses(int ifindex, bool v6,
                struct odhcpd_ipaddr **addrs);
 int odhcpd_get_interface_dns_addr(const struct interface *iface,
                struct in6_addr *addr);
@@ -229,9 +235,6 @@ void odhcpd_bmemcpy(void *av, const void *bv, size_t bits);
 
 int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite);
 
-void ndp_handle_addr6_dump(void);
-void ndp_rqs_addr6_dump(void);
-
 #ifdef WITH_UBUS
 int init_ubus(void);
 const char* ubus_get_ifname(const char *name);
index 0463d6875eef211b66e51f6168889fbbb0e473b6..19702a2d08f3af29e23a74e508dcb2e777fcebeb 100644 (file)
@@ -119,7 +119,6 @@ int setup_router_interface(struct interface *iface, bool enable)
                } else if (iface->ra == RELAYD_SERVER && !iface->master) {
                        iface->timer_rs.cb = trigger_router_advert;
                        uloop_timeout_set(&iface->timer_rs, 1000);
-                       ndp_rqs_addr6_dump();
                }
 
                if (iface->ra == RELAYD_RELAY || (iface->ra == RELAYD_SERVER && !iface->master))
@@ -182,7 +181,9 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
 
        char line[512], ifname[16];
        bool found_default = false;
-       struct odhcpd_ipaddr p = {IN6ADDR_ANY_INIT, 0, 0, 0, 0};
+       struct odhcpd_ipaddr p = { .addr.in6 = IN6ADDR_ANY_INIT, .prefix = 0,
+                                       .dprefix = 0, .preferred = 0, .valid = 0};
+
        while (fgets(line, sizeof(line), fp_route)) {
                uint32_t rflags;
                if (sscanf(line, "00000000000000000000000000000000 00 "
@@ -191,15 +192,15 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
                        found_default = true;
                } else if (sscanf(line, "%8" SCNx32 "%8" SCNx32 "%*8" SCNx32 "%*8" SCNx32 " %hhx %*s "
                                "%*s 00000000000000000000000000000000 %*s %*s %*s %" SCNx32 " lo",
-                               &p.addr.s6_addr32[0], &p.addr.s6_addr32[1], &p.prefix, &rflags) &&
+                               &p.addr.in6.s6_addr32[0], &p.addr.in6.s6_addr32[1], &p.prefix, &rflags) &&
                                p.prefix > 0 && (rflags & RTF_NONEXTHOP) && (rflags & RTF_REJECT)) {
                        // Find source prefixes by scanning through unreachable-routes
-                       p.addr.s6_addr32[0] = htonl(p.addr.s6_addr32[0]);
-                       p.addr.s6_addr32[1] = htonl(p.addr.s6_addr32[1]);
+                       p.addr.in6.s6_addr32[0] = htonl(p.addr.in6.s6_addr32[0]);
+                       p.addr.in6.s6_addr32[1] = htonl(p.addr.in6.s6_addr32[1]);
 
                        for (ssize_t i = 0; i < len; ++i) {
                                if (n[i].prefix <= 64 && n[i].prefix >= p.prefix &&
-                                               !odhcpd_bmemcmp(&p.addr, &n[i].addr, p.prefix)) {
+                                               !odhcpd_bmemcmp(&p.addr.in6, &n[i].addr.in6, p.prefix)) {
                                        n[i].dprefix = p.prefix;
                                        break;
                                }
@@ -353,7 +354,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                if (addr->prefix > 96 || addr->valid <= (uint32_t)now) {
                        char namebuf[INET6_ADDRSTRLEN];
 
-                       inet_ntop(AF_INET6, addr, namebuf, sizeof(namebuf));
+                       inet_ntop(AF_INET6, &addr->addr.in6, namebuf, sizeof(namebuf));
                        syslog(LOG_INFO, "Address %s (prefix %d, valid %u) not suitable as RA prefix on %s",
                                        namebuf, addr->prefix, addr->valid, iface->ifname);
                        continue;
@@ -363,7 +364,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                for (size_t i = 0; i < pfxs_cnt; ++i) {
                        if (addr->prefix == pfxs[i].nd_opt_pi_prefix_len &&
                                        !odhcpd_bmemcmp(&pfxs[i].nd_opt_pi_prefix,
-                                       &addr->addr, addr->prefix))
+                                       &addr->addr.in6, addr->prefix))
                                p = &pfxs[i];
                }
 
@@ -396,10 +397,10 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                if (minvalid > valid)
                        minvalid = valid;
 
-               if (!IN6_IS_ADDR_ULA(&addr->addr) || iface->default_router)
+               if (!IN6_IS_ADDR_ULA(&addr->addr.in6) || iface->default_router)
                        valid_prefix = true;
 
-               odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr,
+               odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr.in6,
                                (iface->ra_advrouter) ? 128 : addr->prefix);
                p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
                p->nd_opt_pi_len = 4;
@@ -498,10 +499,10 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                                (addr->dprefix == 64 && addr->prefix == 64)) {
                        continue; // Address not suitable
                } else if (addr->dprefix > 32) {
-                       addr->addr.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1));
+                       addr->addr.in6.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1));
                } else if (addr->dprefix <= 32) {
-                       addr->addr.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix)) - 1));
-                       addr->addr.s6_addr32[1] = 0;
+                       addr->addr.in6.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix)) - 1));
+                       addr->addr.in6.s6_addr32[1] = 0;
                }
 
                tmp = realloc(routes, sizeof(*routes) * (routes_cnt + 1));
@@ -522,8 +523,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                else if (iface->route_preference > 0)
                        routes[routes_cnt].flags |= ND_RA_PREF_HIGH;
                routes[routes_cnt].lifetime = htonl(TIME_LEFT(addr->valid, now));
-               routes[routes_cnt].addr[0] = addr->addr.s6_addr32[0];
-               routes[routes_cnt].addr[1] = addr->addr.s6_addr32[1];
+               routes[routes_cnt].addr[0] = addr->addr.in6.s6_addr32[0];
+               routes[routes_cnt].addr[1] = addr->addr.in6.s6_addr32[1];
                routes[routes_cnt].addr[2] = 0;
                routes[routes_cnt].addr[3] = 0;