From b5c20853fcbc081ad950ef2083a4f5c31d6ecb54 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Wed, 31 Jul 2013 19:05:55 +0200 Subject: [PATCH] Include IAs in Request to be more compatible with some servers --- src/dhcpv6.c | 33 ++++++++++++++++++++++++++++++--- src/odhcp6c.c | 23 ++++++++++++++++++++++- src/odhcp6c.h | 5 +++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 64c0cb4..9742c39 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -559,12 +559,12 @@ static int dhcpv6_handle_reconfigure(_unused enum dhcpv6_msg orig, // Collect all advertised servers -static int dhcpv6_handle_advert(_unused enum dhcpv6_msg orig, +static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const void *opt, const void *end) { uint16_t olen, otype; uint8_t *odata; - struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}}; + struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}, NULL, NULL, 0, 0}; dhcpv6_for_each_option(opt, end, otype, olen, odata) { if (otype == DHCPV6_OPT_SERVERID && olen <= 130) { @@ -598,10 +598,25 @@ static int dhcpv6_handle_advert(_unused enum dhcpv6_msg orig, cand.preference -= 2000; } } + + if (orig == DHCPV6_MSG_SOLICIT && + (otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA) && + olen > sizeof(struct dhcpv6_ia_hdr)) { + struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]); + dhcpv6_parse_ia(&ia_hdr[1], odata + olen); + } } - if (cand.duid_len > 0) + if (cand.duid_len > 0) { + cand.ia_na = odhcp6c_move_state(STATE_IA_NA, &cand.ia_na_len); + cand.ia_pd = odhcp6c_move_state(STATE_IA_PD, &cand.ia_pd_len); odhcp6c_add_state(STATE_SERVER_CAND, &cand, sizeof(cand)); + } + + if (orig == DHCPV6_MSG_SOLICIT) { + odhcp6c_clear_state(STATE_IA_NA); + odhcp6c_clear_state(STATE_IA_PD); + } return -1; } @@ -634,8 +649,14 @@ static int dhcpv6_commit_advert(void) odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr)); odhcp6c_add_state(STATE_SERVER_ID, c->duid, c->duid_len); accept_reconfig = c->wants_reconfigure; + odhcp6c_add_state(STATE_IA_NA, c->ia_na, c->ia_na_len); + odhcp6c_add_state(STATE_IA_PD, c->ia_pd, c->ia_pd_len); } + for (size_t i = 0; i < cand_len / sizeof(*c); ++i) { + free(cand[i].ia_na); + free(cand[i].ia_pd); + } odhcp6c_clear_state(STATE_SERVER_CAND); if (!c) @@ -691,6 +712,12 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, t1 = t2 = t3 = UINT32_MAX; } + if (orig == DHCPV6_MSG_REQUEST) { + // Delete NA and PD we have in the state from the Advert + odhcp6c_clear_state(STATE_IA_NA); + odhcp6c_clear_state(STATE_IA_PD); + } + if (opt) { odhcp6c_clear_state(STATE_DNS); odhcp6c_clear_state(STATE_SEARCH); diff --git a/src/odhcp6c.c b/src/odhcp6c.c index df89eb9..f732d9e 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -192,7 +192,7 @@ int main(_unused int argc, char* const argv[]) while (do_signal != SIGTERM) { // Main logic odhcp6c_clear_state(STATE_SERVER_ID); - odhcp6c_clear_state(STATE_SERVER_CAND); + odhcp6c_clear_state(STATE_IA_NA); odhcp6c_clear_state(STATE_IA_PD); odhcp6c_clear_state(STATE_SNTP_IP); odhcp6c_clear_state(STATE_SNTP_FQDN); @@ -201,6 +201,15 @@ int main(_unused int argc, char* const argv[]) dhcpv6_set_ia_na_mode(ia_na_mode); bound = false; + // Server candidates need deep-delete + size_t cand_len; + struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len); + for (size_t i = 0; i < cand_len / sizeof(*cand); ++i) { + free(cand[i].ia_na); + free(cand[i].ia_pd); + } + odhcp6c_clear_state(STATE_SERVER_CAND); + syslog(LOG_NOTICE, "(re)starting transaction on %s", ifname); do_signal = 0; @@ -405,6 +414,18 @@ size_t odhcp6c_remove_state(enum odhcp6c_state state, size_t offset, size_t len) } +void* odhcp6c_move_state(enum odhcp6c_state state, size_t *len) +{ + *len = state_len[state]; + void *data = state_data[state]; + + state_len[state] = 0; + state_data[state] = NULL; + + return data; +} + + void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len) { *len = state_len[state]; diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 2e7107c..ac0932f 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -158,6 +158,10 @@ struct dhcpv6_server_cand { int16_t preference; uint8_t duid_len; uint8_t duid[130]; + void *ia_na; + void *ia_pd; + size_t ia_na_len; + size_t ia_pd_len; }; @@ -236,6 +240,7 @@ void odhcp6c_random(void *buf, size_t len); void odhcp6c_clear_state(enum odhcp6c_state state); void odhcp6c_add_state(enum odhcp6c_state state, const void *data, size_t len); size_t odhcp6c_remove_state(enum odhcp6c_state state, size_t offset, size_t len); +void* odhcp6c_move_state(enum odhcp6c_state state, size_t *len); void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len); // Entry manipulation -- 2.30.2