X-Git-Url: https://git.decadent.org.uk/gitweb/?p=odhcp6c.git;a=blobdiff_plain;f=src%2Fdhcpv6.c;h=6ae6f7a02fd8d9040fc8b676cd81a73d361d21c6;hp=e52fd6cd95fcf5dc4aa47febb023cb12e00b8eca;hb=e20ee553da0b17d2e2569650327fff568a4a222d;hpb=fc0f3fd210223120a63e64cb707097b93568173a diff --git a/src/dhcpv6.c b/src/dhcpv6.c index e52fd6c..6ae6f7a 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -179,11 +179,9 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout) #ifdef EXT_CER_ID htons(DHCPV6_OPT_CER_ID), #endif -#ifdef EXT_S46 htons(DHCPV6_OPT_S46_CONT_MAPE), htons(DHCPV6_OPT_S46_CONT_MAPT), htons(DHCPV6_OPT_S46_CONT_LW), -#endif }; odhcp6c_add_state(STATE_ORO, oro, sizeof(oro)); } @@ -330,6 +328,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); @@ -374,8 +377,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; @@ -466,7 +475,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); } @@ -488,8 +498,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) @@ -553,10 +563,13 @@ int dhcpv6_request(enum dhcpv6_msg type) round_start = odhcp6c_get_milli_time()) { uint8_t buf[1536], cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct iovec iov = {buf, sizeof(buf)}; - struct msghdr msg = {NULL, 0, &iov, 1, - cmsg_buf, sizeof(cmsg_buf), 0}; + struct sockaddr_in6 addr; + 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; + // Check for pending signal if (odhcp6c_signal_process()) return -1; @@ -601,7 +614,7 @@ int dhcpv6_request(enum dhcpv6_msg type) "%llums", (unsigned long long)elapsed); if (retx->handler_reply) - len = retx->handler_reply(type, rc, opt, opt_end); + len = retx->handler_reply(type, rc, opt, opt_end, &addr); if (len > 0 && round_end - round_start > 1000) round_end = 1000 + round_start; @@ -693,7 +706,7 @@ static bool dhcpv6_response_is_valid(const void *buf, ssize_t len, rcmsg = odata[0]; } else if ((otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA)) { ia_present = true; - if (olen < sizeof(struct dhcpv6_ia_hdr)) + if (olen < -4 + sizeof(struct dhcpv6_ia_hdr)) options_valid = false; } else if ((otype == DHCPV6_OPT_IA_ADDR) || (otype == DHCPV6_OPT_IA_PREFIX) || @@ -731,7 +744,7 @@ int dhcpv6_poll_reconfigure(void) static int dhcpv6_handle_reconfigure(_unused enum dhcpv6_msg orig, const int rc, - const void *opt, const void *end) + const void *opt, const void *end, _unused const struct sockaddr_in6 *from) { uint16_t otype, olen; uint8_t *odata, msg = DHCPV6_MSG_RENEW; @@ -741,14 +754,14 @@ static int dhcpv6_handle_reconfigure(_unused enum dhcpv6_msg orig, const int rc, odata[0] == DHCPV6_MSG_INFO_REQ)) msg = odata[0]; - dhcpv6_handle_reply(DHCPV6_MSG_UNKNOWN, rc, NULL, NULL); + dhcpv6_handle_reply(DHCPV6_MSG_UNKNOWN, rc, NULL, NULL, NULL); return msg; } // Collect all advertised servers static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, - const void *opt, const void *end) + const void *opt, const void *end, _unused const struct sockaddr_in6 *from) { uint16_t olen, otype; uint8_t *odata, pref = 0; @@ -761,7 +774,7 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, dhcpv6_for_each_option(opt, end, otype, olen, odata) { if (orig == DHCPV6_MSG_SOLICIT && (otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA) && - olen > sizeof(struct dhcpv6_ia_hdr)) { + olen > -4 + sizeof(struct dhcpv6_ia_hdr)) { struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]); dhcpv6_parse_ia(ia_hdr, odata + olen + sizeof(*ia_hdr)); } @@ -800,8 +813,8 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4]; uint8_t *oend = odata + olen, *d; dhcpv6_for_each_option(&h[1], oend, otype, olen, d) { - if (otype == DHCPV6_OPT_IA_PREFIX && (olen + 4) >= - (uint16_t)sizeof(struct dhcpv6_ia_prefix)) { + if (otype == DHCPV6_OPT_IA_PREFIX && + olen >= -4 + sizeof(struct dhcpv6_ia_prefix)) { struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&d[-4]; have_pd = p->prefix; } @@ -810,7 +823,8 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4]; uint8_t *oend = odata + olen, *d; dhcpv6_for_each_option(&h[1], oend, otype, olen, d) - if (otype == DHCPV6_OPT_IA_ADDR) + if (otype == DHCPV6_OPT_IA_ADDR && + olen >= -4 + sizeof(struct dhcpv6_ia_addr)) have_na = true; } } @@ -856,22 +870,22 @@ static int dhcpv6_commit_advert(void) static int dhcpv6_handle_rebind_reply(enum dhcpv6_msg orig, const int rc, - const void *opt, const void *end) + const void *opt, const void *end, const struct sockaddr_in6 *from) { - dhcpv6_handle_advert(orig, rc, opt, end); + dhcpv6_handle_advert(orig, rc, opt, end, from); if (dhcpv6_commit_advert() < 0) return -1; - return dhcpv6_handle_reply(orig, rc, opt, end); + return dhcpv6_handle_reply(orig, rc, opt, end, from); } static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, - const void *opt, const void *end) + const void *opt, const void *end, const struct sockaddr_in6 *from) { 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, }; @@ -930,11 +944,15 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, bool passthru = true; if ((otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA) - && olen > sizeof(struct dhcpv6_ia_hdr)) { + && 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 != 1 && otype == DHCPV6_OPT_IA_NA) + if (ia_hdr->iaid != htonl(1) && otype == DHCPV6_OPT_IA_NA) continue; uint16_t code = DHCPV6_Success; @@ -1041,7 +1059,6 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_add_state(STATE_CER, &cer_id->addr, sizeof(any)); passthru = false; #endif -#ifdef EXT_S46 } else if (otype == DHCPV6_OPT_S46_CONT_MAPT) { odhcp6c_add_state(STATE_S46_MAPT, odata, olen); passthru = false; @@ -1054,7 +1071,6 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, } else if (otype == DHCPV6_OPT_S46_CONT_LW) { odhcp6c_add_state(STATE_S46_LW, odata, olen); passthru = false; -#endif } else if (otype == DHCPV6_OPT_CLIENTID || otype == DHCPV6_OPT_SERVERID || otype == DHCPV6_OPT_IA_TA || @@ -1094,6 +1110,11 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, default : break; } + + if (orig == DHCPV6_MSG_REBIND || orig == DHCPV6_MSG_REQUEST) { + odhcp6c_clear_state(STATE_SERVER_ADDR); + odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16); + } } } else if (ret > 0) { @@ -1196,7 +1217,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++; } @@ -1231,7 +1252,7 @@ static int dhcpv6_parse_ia(void *opt, void *end) 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++; } } @@ -1350,23 +1371,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; } }