Improve handling of DNS search domains
[project/odhcp6c.git] / src / dhcpv6.c
index ca41db6b48e88dd90d05b73eb270f4d585fc5c55..eeb669b4bfdff61fd40539fd204cf4031c2f0899 100644 (file)
@@ -173,9 +173,6 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout)
                        htons(DHCPV6_OPT_PD_EXCLUDE),
                        htons(DHCPV6_OPT_SOL_MAX_RT),
                        htons(DHCPV6_OPT_INF_MAX_RT),
-#ifdef EXT_PREFIX_CLASS
-                       htons(DHCPV6_OPT_PREFIX_CLASS),
-#endif
 #ifdef EXT_CER_ID
                        htons(DHCPV6_OPT_CER_ID),
 #endif
@@ -328,6 +325,11 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
                                        .addr = e[j].target
                                };
 
+                               if (type == DHCPV6_MSG_REQUEST) {
+                                       p.preferred = htonl(e[j].preferred);
+                                       p.valid = htonl(e[j].valid);
+                               }
+
                                memcpy(ia_pd + ia_pd_len, &p, sizeof(p));
                                ia_pd_len += sizeof(p);
 
@@ -372,8 +374,14 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
                pa[i].type = htons(DHCPV6_OPT_IA_ADDR);
                pa[i].len = htons(sizeof(pa[i]) - 4U);
                pa[i].addr = e[i].target;
-               pa[i].preferred = 0;
-               pa[i].valid = 0;
+
+               if (type == DHCPV6_MSG_REQUEST) {
+                       pa[i].preferred = htonl(e[i].preferred);
+                       pa[i].valid = htonl(e[i].valid);
+               } else {
+                       pa[i].preferred = 0;
+                       pa[i].valid = 0;
+               }
        }
 
        ia_na = pa;
@@ -464,7 +472,8 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
 
        struct sockaddr_in6 srv = {AF_INET6, htons(DHCPV6_SERVER_PORT),
                0, ALL_DHCPV6_RELAYS, ifindex};
-       struct msghdr msg = {&srv, sizeof(srv), iov, cnt, NULL, 0, 0};
+       struct msghdr msg = {.msg_name = &srv, .msg_namelen = sizeof(srv),
+                       .msg_iov = iov, .msg_iovlen = cnt};
 
        sendmsg(sock, &msg, 0);
 }
@@ -486,8 +495,8 @@ int dhcpv6_request(enum dhcpv6_msg type)
 
        if (retx->delay) {
                struct timespec ts = {0, 0};
-               ts.tv_nsec = dhcpv6_rand_delay(10 * DHCPV6_REQ_DELAY);
-               nanosleep(&ts, NULL);
+               ts.tv_nsec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2) * 1000000;
+               while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
        }
 
        if (type == DHCPV6_MSG_UNKNOWN)
@@ -552,8 +561,9 @@ int dhcpv6_request(enum dhcpv6_msg type)
                        uint8_t buf[1536], cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
                        struct iovec iov = {buf, sizeof(buf)};
                        struct sockaddr_in6 addr;
-                       struct msghdr msg = {&addr, sizeof(addr), &iov, 1,
-                                       cmsg_buf, sizeof(cmsg_buf), 0};
+                       struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr),
+                                       .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf,
+                                       .msg_controllen = sizeof(cmsg_buf)};
                        struct in6_pktinfo *pktinfo = NULL;
 
 
@@ -872,7 +882,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
 {
        uint8_t *odata;
        uint16_t otype, olen;
-       uint32_t refresh = UINT32_MAX;
+       uint32_t refresh = 86400;
        int ret = 1;
        bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
 
@@ -934,6 +944,10 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
                                && olen > -4 + sizeof(struct dhcpv6_ia_hdr)) {
                        struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]);
 
+                       if ((na_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_NA) ||
+                           (pd_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_PD))
+                               continue;
+
                        // Test ID
                        if (ia_hdr->iaid != htonl(1) && otype == DHCPV6_OPT_IA_NA)
                                continue;
@@ -981,7 +995,6 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
                                odhcp6c_add_state(STATE_DNS, odata, olen);
                } else if (otype == DHCPV6_OPT_DNS_DOMAIN) {
                        odhcp6c_add_state(STATE_SEARCH, odata, olen);
-                       passthru = false;
                } else if (otype == DHCPV6_OPT_SNTP_SERVERS) {
                        if (olen % 16 == 0)
                                odhcp6c_add_state(STATE_SNTP_IP, odata, olen);
@@ -1128,8 +1141,8 @@ static int dhcpv6_parse_ia(void *opt, void *end)
 
        // Update address IA
        dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
-               struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0,
-                               IN6ADDR_ANY_INIT, 0, 0, 0, 0, 0, 0};
+               struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0, 0,
+                               IN6ADDR_ANY_INIT, 0, 0, 0, 0, 0};
 
                entry.iaid = ia_hdr->iaid;
 
@@ -1154,14 +1167,6 @@ static int dhcpv6_parse_ia(void *opt, void *end)
                        uint16_t stype, slen;
                        uint8_t *sdata;
 
-#ifdef EXT_PREFIX_CLASS
-                       // Find prefix class, if any
-                       dhcpv6_for_each_option(&prefix[1], odata + olen,
-                                       stype, slen, sdata)
-                               if (stype == DHCPV6_OPT_PREFIX_CLASS && slen == 2)
-                                       entry.class = sdata[0] << 8 | sdata[1];
-#endif
-
                        // Parse PD-exclude
                        bool ok = true;
                        dhcpv6_for_each_option(odata + sizeof(*prefix) - 4U,
@@ -1200,7 +1205,7 @@ static int dhcpv6_parse_ia(void *opt, void *end)
                        }
 
                        if (ok) {
-                               odhcp6c_update_entry(STATE_IA_PD, &entry);
+                               odhcp6c_update_entry(STATE_IA_PD, &entry, 0, false);
                                parsed_ia++;
                        }
 
@@ -1225,17 +1230,7 @@ static int dhcpv6_parse_ia(void *opt, void *end)
                        entry.length = 128;
                        entry.target = addr->addr;
 
-#ifdef EXT_PREFIX_CLASS
-                       uint16_t stype, slen;
-                       uint8_t *sdata;
-                       // Find prefix class, if any
-                       dhcpv6_for_each_option(&addr[1], odata + olen,
-                                       stype, slen, sdata)
-                               if (stype == DHCPV6_OPT_PREFIX_CLASS && slen == 2)
-                                       entry.class = sdata[0] << 8 | sdata[1];
-#endif
-
-                       odhcp6c_update_entry(STATE_IA_NA, &entry);
+                       odhcp6c_update_entry(STATE_IA_NA, &entry, 0, false);
                        parsed_ia++;
                }
        }
@@ -1354,23 +1349,8 @@ static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
                }
                break;
 
-       case DHCPV6_NoAddrsAvail:
-       case DHCPV6_NoPrefixAvail:
-               switch (orig) {
-               case DHCPV6_MSG_REQUEST:
-                       if (*ret != 0)
-                               *ret = 0;
-                       break;
-               default:
-                       break;
-               }
-               break;
-
-       case DHCPV6_NotOnLink:
-               // TODO handle not onlink in case of confirm
-               break;
-
        default:
+               *ret = 0;
                break;
        }
 }