From 523cd46be873ce76b67bc2b3b1f26f6491815ca0 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Wed, 30 Apr 2014 17:39:15 +0200 Subject: [PATCH 01/16] Fix MAP parameter parsing --- src/script.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/script.c b/src/script.c index 44ce80e..6caaffd 100644 --- a/src/script.c +++ b/src/script.c @@ -246,12 +246,18 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len struct dhcpv6_s46_v4v6bind *bind = (struct dhcpv6_s46_v4v6bind*)odata; if (state != STATE_S46_LW && otype == DHCPV6_OPT_S46_RULE && - olen >= sizeof(struct dhcpv6_s46_rule) && olen >= - sizeof(struct dhcpv6_s46_rule) + rule->prefix6_len) { + olen >= sizeof(struct dhcpv6_s46_rule)) { char buf4[INET_ADDRSTRLEN]; char buf6[INET6_ADDRSTRLEN]; struct in6_addr in6 = IN6ADDR_ANY_INIT; - memcpy(&in6, rule->ipv6_prefix, rule->prefix6_len); + + size_t prefix6len = rule->prefix6_len; + prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; + + if (olen < sizeof(struct dhcpv6_s46_rule) + prefix6len) + continue; + + memcpy(&in6, rule->ipv6_prefix, prefix6len); inet_ntop(AF_INET, &rule->ipv4_prefix, buf4, sizeof(buf4)); inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6)); @@ -262,8 +268,8 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len fprintf(fp, "ealen=%d,prefix4len=%d,prefix6len=%d,ipv4prefix=%s,ipv6prefix=%s,", rule->ea_len, rule->prefix4_len, rule->prefix6_len, buf4, buf6); - s46_to_env_portparams(&rule->ipv6_prefix[rule->prefix6_len], - olen - sizeof(*rule) - rule->prefix6_len, fp); + s46_to_env_portparams(&rule->ipv6_prefix[prefix6len], + olen - sizeof(*rule) - prefix6len, fp); dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { if (state != STATE_S46_MAPT && otype == DHCPV6_OPT_S46_BR && @@ -271,21 +277,32 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len inet_ntop(AF_INET6, odata, buf6, sizeof(buf6)); fprintf(fp, "br=%s,", buf6); } else if (state == STATE_S46_MAPT && otype == DHCPV6_OPT_S46_DMR && - olen >= sizeof(struct dhcpv6_s46_dmr) && olen >= - sizeof(struct dhcpv6_s46_dmr) + dmr->dmr_prefix6_len) { + olen >= sizeof(struct dhcpv6_s46_dmr)) { memset(&in6, 0, sizeof(in6)); - memcpy(&in6, dmr->dmr_ipv6_prefix, dmr->dmr_prefix6_len); + size_t prefix6len = dmr->dmr_prefix6_len; + prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; + + if (olen < sizeof(struct dhcpv6_s46_dmr) + prefix6len) + continue; + + memcpy(&in6, dmr->dmr_ipv6_prefix, prefix6len); inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6)); fprintf(fp, "dmr=%s/%d,", buf6, dmr->dmr_prefix6_len); } } } else if (state == STATE_S46_LW && otype == DHCPV6_OPT_S46_V4V6BIND && - olen >= sizeof(struct dhcpv6_s46_v4v6bind) && olen >= - sizeof(struct dhcpv6_s46_v4v6bind) + bind->bindprefix6_len) { + olen >= sizeof(struct dhcpv6_s46_v4v6bind)) { char buf4[INET_ADDRSTRLEN]; char buf6[INET6_ADDRSTRLEN]; struct in6_addr in6 = IN6ADDR_ANY_INIT; - memcpy(&in6, bind->bind_ipv6_prefix, bind->bindprefix6_len); + + size_t prefix6len = bind->bindprefix6_len; + prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; + + if (olen < sizeof(struct dhcpv6_s46_v4v6bind) + prefix6len) + continue; + + memcpy(&in6, bind->bind_ipv6_prefix, prefix6len); inet_ntop(AF_INET, &bind->ipv4_address, buf4, sizeof(buf4)); inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6)); @@ -293,8 +310,8 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len fprintf(fp, "ipv4address=%s,prefix6len=%d,ipv6prefix=%s,", buf4, bind->bindprefix6_len, buf6); - s46_to_env_portparams(&bind->bind_ipv6_prefix[bind->bindprefix6_len], - olen - sizeof(*bind) - bind->bindprefix6_len, fp); + s46_to_env_portparams(&bind->bind_ipv6_prefix[prefix6len], + olen - sizeof(*bind) - prefix6len, fp); dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { if (otype == DHCPV6_OPT_S46_BR && olen == sizeof(struct in6_addr)) { -- 2.39.2 From 21ca19406b02b99eb7f1db1b83e9f0a59c664d32 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Wed, 30 Apr 2014 17:46:02 +0200 Subject: [PATCH 02/16] MAP: export type value in rules --- src/script.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/script.c b/src/script.c index 6caaffd..5ddd6c5 100644 --- a/src/script.c +++ b/src/script.c @@ -229,6 +229,8 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len { const char *name = (state == STATE_S46_MAPE) ? "MAPE" : (state == STATE_S46_MAPT) ? "MAPT" : "LW4O6"; + const char *type = (state == STATE_S46_MAPE) ? "map-e" : + (state == STATE_S46_MAPT) ? "map-t" : "lw4o6"; char *str; size_t strsize; @@ -265,8 +267,8 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len if (rule->flags & 1) fputs("fmr,", fp); - fprintf(fp, "ealen=%d,prefix4len=%d,prefix6len=%d,ipv4prefix=%s,ipv6prefix=%s,", - rule->ea_len, rule->prefix4_len, rule->prefix6_len, buf4, buf6); + fprintf(fp, "type=%s,ealen=%d,prefix4len=%d,prefix6len=%d,ipv4prefix=%s,ipv6prefix=%s,", + type, rule->ea_len, rule->prefix4_len, rule->prefix6_len, buf4, buf6); s46_to_env_portparams(&rule->ipv6_prefix[prefix6len], olen - sizeof(*rule) - prefix6len, fp); @@ -307,8 +309,8 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len inet_ntop(AF_INET, &bind->ipv4_address, buf4, sizeof(buf4)); inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6)); - fprintf(fp, "ipv4address=%s,prefix6len=%d,ipv6prefix=%s,", - buf4, bind->bindprefix6_len, buf6); + fprintf(fp, "type=%s,ipv4address=%s,prefix6len=%d,ipv6prefix=%s,", + type, buf4, bind->bindprefix6_len, buf6); s46_to_env_portparams(&bind->bind_ipv6_prefix[prefix6len], olen - sizeof(*bind) - prefix6len, fp); -- 2.39.2 From a0bbaf5bffc66b1693577a374a9a599e313aefe1 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Wed, 30 Apr 2014 17:49:32 +0200 Subject: [PATCH 03/16] Fix compiler warning --- src/script.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/script.c b/src/script.c index 5ddd6c5..13ac562 100644 --- a/src/script.c +++ b/src/script.c @@ -229,8 +229,6 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len { const char *name = (state == STATE_S46_MAPE) ? "MAPE" : (state == STATE_S46_MAPT) ? "MAPT" : "LW4O6"; - const char *type = (state == STATE_S46_MAPE) ? "map-e" : - (state == STATE_S46_MAPT) ? "map-t" : "lw4o6"; char *str; size_t strsize; @@ -240,6 +238,9 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len fputc('=', fp); #ifdef EXT_S46 + const char *type = (state == STATE_S46_MAPE) ? "map-e" : + (state == STATE_S46_MAPT) ? "map-t" : "lw4o6"; + uint8_t *odata; uint16_t otype, olen; dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { -- 2.39.2 From 19b89e91989e466a6657b07ee33961dbad99cc8e Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Thu, 8 May 2014 11:06:32 +0200 Subject: [PATCH 04/16] softwire: fix DMR parsing --- src/script.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/script.c b/src/script.c index 13ac562..9325085 100644 --- a/src/script.c +++ b/src/script.c @@ -281,6 +281,7 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len fprintf(fp, "br=%s,", buf6); } else if (state == STATE_S46_MAPT && otype == DHCPV6_OPT_S46_DMR && olen >= sizeof(struct dhcpv6_s46_dmr)) { + dmr = (struct dhcpv6_s46_dmr*)odata; memset(&in6, 0, sizeof(in6)); size_t prefix6len = dmr->dmr_prefix6_len; prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; -- 2.39.2 From fa291eaf4ea0d94e84e9fb617ff81abae04a2835 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Thu, 8 May 2014 11:12:43 +0200 Subject: [PATCH 05/16] Add MAPE / MAPT / LW4O6 to Readme --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 6ebba7d..f9abd49 100644 --- a/README +++ b/README @@ -80,3 +80,4 @@ Environment: * RA_DNS A space-separated list of recursive DNS servers from the RA * AFTR The DS-Lite AFTR domain name * AFTR_IP The DS-Lite AFTR resolved IPv6 address +* MAPE / MAPT / LW4O6 Softwire rules for MAPE, MAPT and LW4O6 -- 2.39.2 From 74b94c1442ec0897c1f90a314838594a5d42bb87 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 23 May 2014 08:15:49 +0200 Subject: [PATCH 06/16] Add support for DHCPv6 option passthru --- src/dhcpv6.c | 43 +++++++++++++++++++++++++++++++++---------- src/odhcp6c.h | 3 +++ src/script.c | 8 +++++++- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 7c6da00..4fbff84 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -922,10 +922,13 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_clear_state(STATE_S46_MAPT); odhcp6c_clear_state(STATE_S46_MAPE); odhcp6c_clear_state(STATE_S46_LW); + odhcp6c_clear_state(STATE_PASSTHRU); } // Parse and find all matching IAs dhcpv6_for_each_option(opt, end, otype, olen, odata) { + bool passthru = true; + if ((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]); @@ -963,12 +966,14 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, continue; dhcpv6_parse_ia(ia_hdr, odata + olen + sizeof(*ia_hdr)); + passthru = false; } else if (otype == DHCPV6_OPT_STATUS && olen >= 2) { uint8_t *mdata = (olen > 2) ? &odata[2] : NULL; uint16_t mlen = (olen > 2) ? olen - 2 : 0; uint16_t code = ((int)odata[0]) << 8 | ((int)odata[1]); dhcpv6_handle_status_code(orig, code, mdata, mlen, &ret); + passthru = false; } else if (otype == DHCPV6_OPT_DNS_SERVERS) { if (olen % 16 == 0) @@ -999,27 +1004,33 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_add_state(STATE_SIP_FQDN, odata, olen); } else if (otype == DHCPV6_OPT_INFO_REFRESH && olen >= 4) { refresh = ntohl(*((uint32_t*)odata)); - } else if (otype == DHCPV6_OPT_AUTH && olen == -4 + - sizeof(struct dhcpv6_auth_reconfigure)) { - struct dhcpv6_auth_reconfigure *r = (void*)&odata[-4]; - if (r->protocol == 3 && r->algorithm == 1 && - r->reconf_type == 1) - memcpy(reconf_key, r->key, sizeof(r->key)); + passthru = false; + } else if (otype == DHCPV6_OPT_AUTH) { + if (olen == -4 + sizeof(struct dhcpv6_auth_reconfigure)) { + struct dhcpv6_auth_reconfigure *r = (void*)&odata[-4]; + if (r->protocol == 3 && r->algorithm == 1 && + r->reconf_type == 1) + memcpy(reconf_key, r->key, sizeof(r->key)); + } + passthru = false; } else if (otype == DHCPV6_OPT_AFTR_NAME && olen > 3) { size_t cur_len; odhcp6c_get_state(STATE_AFTR_NAME, &cur_len); if (cur_len == 0) odhcp6c_add_state(STATE_AFTR_NAME, odata, olen); + passthru = false; } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) { uint32_t sol_max_rt = ntohl(*((uint32_t *)odata)); if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX) dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt; + passthru = false; } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) { uint32_t inf_max_rt = ntohl(*((uint32_t *)odata)); if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX) dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt; + passthru = false; #ifdef EXT_CER_ID } else if (otype == DHCPV6_OPT_CER_ID && olen == -4 + sizeof(struct dhcpv6_cer_id)) { @@ -1027,23 +1038,35 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, struct in6_addr any = IN6ADDR_ANY_INIT; if (memcmp(&cer_id->addr, &any, sizeof(any))) 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; } else if (otype == DHCPV6_OPT_S46_CONT_MAPE) { size_t mape_len; odhcp6c_get_state(STATE_S46_MAPE, &mape_len); if (mape_len == 0) odhcp6c_add_state(STATE_S46_MAPE, odata, olen); + passthru = false; } 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) { - odhcp6c_add_state(STATE_CUSTOM_OPTS, - &odata[-4], olen + 4); + } else if (otype == DHCPV6_OPT_CLIENTID || + otype == DHCPV6_OPT_SERVERID || + otype == DHCPV6_OPT_IA_TA || + otype == DHCPV6_OPT_PREF || + otype == DHCPV6_OPT_UNICAST || + otype == DHCPV6_OPT_FQDN) { + passthru = false; + } else { + odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-4], olen + 4); } + + if (passthru) + odhcp6c_add_state(STATE_PASSTHRU, &odata[-4], olen + 4); } if (orig != DHCPV6_MSG_INFO_REQ) { diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 8abb631..01fb072 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -37,12 +37,14 @@ enum dhcvp6_opt { DHCPV6_OPT_CLIENTID = 1, DHCPV6_OPT_SERVERID = 2, DHCPV6_OPT_IA_NA = 3, + DHCPV6_OPT_IA_TA = 4, DHCPV6_OPT_IA_ADDR = 5, DHCPV6_OPT_ORO = 6, DHCPV6_OPT_PREF = 7, DHCPV6_OPT_ELAPSED = 8, DHCPV6_OPT_RELAY_MSG = 9, DHCPV6_OPT_AUTH = 11, + DHCPV6_OPT_UNICAST = 12, DHCPV6_OPT_STATUS = 13, DHCPV6_OPT_RAPID_COMMIT = 14, DHCPV6_OPT_USER_CLASS = 15, @@ -268,6 +270,7 @@ enum odhcp6c_state { STATE_S46_MAPT, STATE_S46_MAPE, STATE_S46_LW, + STATE_PASSTHRU, _STATE_MAX }; diff --git a/src/script.c b/src/script.c index 9325085..389dc37 100644 --- a/src/script.c +++ b/src/script.c @@ -359,7 +359,7 @@ void script_call(const char *status) { size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len; size_t sip_ip_len, sip_fqdn_len, aftr_name_len, cer_len; - size_t s46_mapt_len, s46_mape_len, s46_lw_len; + size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len; odhcp6c_expire(); if (delayed_call) { @@ -380,6 +380,7 @@ void script_call(const char *status) uint8_t *s46_mapt = odhcp6c_get_state(STATE_S46_MAPT, &s46_mapt_len); uint8_t *s46_mape = odhcp6c_get_state(STATE_S46_MAPE, &s46_mape_len); uint8_t *s46_lw = odhcp6c_get_state(STATE_S46_LW, &s46_lw_len); + uint8_t *passthru = odhcp6c_get_state(STATE_PASSTHRU, &passthru_len); size_t prefix_len, address_len, ra_pref_len, ra_route_len, ra_dns_len; uint8_t *prefix = odhcp6c_get_state(STATE_IA_PD, &prefix_len); @@ -410,6 +411,11 @@ void script_call(const char *status) entry_to_env("RA_ROUTES", ra_route, ra_route_len, ENTRY_ROUTE); entry_to_env("RA_DNS", ra_dns, ra_dns_len, ENTRY_HOST); + char *buf = malloc(10 + passthru_len * 2); + strncpy(buf, "PASSTHRU=", 10); + script_hexlify(&buf[9], passthru, passthru_len); + putenv(buf); + argv[2] = (char*)status; execv(argv[0], argv); _exit(128); -- 2.39.2 From b38d8871977d3b97cc3c3e7f2ad203852166c661 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 23 May 2014 08:29:34 +0200 Subject: [PATCH 07/16] filter DNS-domain from passthru --- src/dhcpv6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 4fbff84..df6e120 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -980,6 +980,7 @@ 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); -- 2.39.2 From e3aa092cc84fc6eff6051c6ae306c085b50271ab Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 30 May 2014 16:49:05 +0200 Subject: [PATCH 08/16] Improve filter --- src/dhcpv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index df6e120..b09fa10 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -1060,7 +1060,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, otype == DHCPV6_OPT_IA_TA || otype == DHCPV6_OPT_PREF || otype == DHCPV6_OPT_UNICAST || - otype == DHCPV6_OPT_FQDN) { + otype == DHCPV6_OPT_RECONF_ACCEPT) { passthru = false; } else { odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-4], olen + 4); -- 2.39.2 From 26c5466e626735f27dd073b727b02612c5a807cd Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 30 May 2014 16:51:22 +0200 Subject: [PATCH 09/16] Filter FQDN as well --- src/dhcpv6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index b09fa10..0c98729 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -1060,6 +1060,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, otype == DHCPV6_OPT_IA_TA || otype == DHCPV6_OPT_PREF || otype == DHCPV6_OPT_UNICAST || + otype == DHCPV6_OPT_FQDN || otype == DHCPV6_OPT_RECONF_ACCEPT) { passthru = false; } else { -- 2.39.2 From 67b311ab81736b35858664219d345844ab08fcc7 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 21 Jul 2014 12:10:38 +0200 Subject: [PATCH 10/16] Send router solicitations with source link-layer address --- src/ra.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ra.c b/src/ra.c index 3e36f94..b700c9a 100644 --- a/src/ra.c +++ b/src/ra.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -132,9 +133,26 @@ int ra_init(const char *ifname, const struct in6_addr *ifid) static void ra_send_rs(int signal __attribute__((unused))) { - const struct icmp6_hdr rs = {ND_ROUTER_SOLICIT, 0, 0, {{0}}}; + struct { + struct icmp6_hdr hdr; + struct icmpv6_opt lladdr; + } rs = { + .hdr = {ND_ROUTER_SOLICIT, 0, 0, {{0}}}, + .lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {0}}, + }; const struct sockaddr_in6 dest = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, if_index}; - sendto(sock, &rs, sizeof(rs), MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)); + size_t len = sizeof(rs); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); + if (!ioctl(sock, SIOCGIFHWADDR, &ifr) + && memcmp(rs.lladdr.data, ifr.ifr_hwaddr.sa_data, 6)) + memcpy(rs.lladdr.data, ifr.ifr_hwaddr.sa_data, 6); + else + len = sizeof(struct icmp6_hdr); + + sendto(sock, &rs, len, MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)); if (++rs_attempt <= 3) alarm(4); -- 2.39.2 From b9c8be24207e4197c9b529c157d7ea04f3f4bdb8 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Wed, 13 Aug 2014 13:30:42 +0200 Subject: [PATCH 11/16] Remove BFD from master-branch (kept in BFD-branch) --- CMakeLists.txt | 7 +- src/bfd.c | 211 ------------------------------------------------- src/bfd.h | 18 ----- src/odhcp6c.c | 25 ------ 4 files changed, 1 insertion(+), 260 deletions(-) delete mode 100644 src/bfd.c delete mode 100644 src/bfd.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0abe08..9e508f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,12 +19,7 @@ if(${EXT_S46}) add_definitions(-DEXT_S46=${EXT_S46}) endif(${EXT_S46}) -if(${EXT_BFD_PING}) - add_definitions(-DEXT_BFD_PING) - set(BFD_SOURCE src/bfd.c) -endif(${EXT_BFD_PING}) - -add_executable(odhcp6c src/odhcp6c.c src/dhcpv6.c src/ra.c src/script.c src/md5.c ${BFD_SOURCE}) +add_executable(odhcp6c src/odhcp6c.c src/dhcpv6.c src/ra.c src/script.c src/md5.c) target_link_libraries(odhcp6c resolv) # Installation diff --git a/src/bfd.c b/src/bfd.c deleted file mode 100644 index 1822555..0000000 --- a/src/bfd.c +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "odhcp6c.h" - -static int sock = -1, rtnl = -1; -static int if_index = -1; -static int bfd_failed = 0, bfd_limit = 0, bfd_interval = 0; -static bool bfd_armed = false; - - -static void bfd_send(int signal __attribute__((unused))) -{ - struct { - struct ip6_hdr ip6; - struct icmp6_hdr icmp6; - } ping; - memset(&ping, 0, sizeof(ping)); - - ping.ip6.ip6_vfc = 6 << 4; - ping.ip6.ip6_plen = htons(8); - ping.ip6.ip6_nxt = IPPROTO_ICMPV6; - ping.ip6.ip6_hlim = 255; - - ping.icmp6.icmp6_type = ICMP6_ECHO_REQUEST; - ping.icmp6.icmp6_data32[0] = htonl(0xbfd0bfd); - - size_t pdlen, rtlen; - struct odhcp6c_entry *pd = odhcp6c_get_state(STATE_IA_PD, &pdlen), *cpd = NULL; - struct odhcp6c_entry *rt = odhcp6c_get_state(STATE_RA_ROUTE, &rtlen), *crt = NULL; - bool crt_found = false; - - alarm(bfd_interval); - - if (bfd_armed) { - if (++bfd_failed > bfd_limit) { - raise(SIGUSR2); - return; - } - } - - // Detect PD-Prefix - for (size_t i = 0; i < pdlen / sizeof(*pd); ++i) - if (!cpd || ((cpd->target.s6_addr[0] & 7) == 0xfc) > ((pd[i].target.s6_addr[0] & 7) == 0xfc) - || cpd->preferred < pd[i].preferred) - cpd = &pd[i]; - - // Detect default router - for (size_t i = 0; i < rtlen / sizeof(*rt); ++i) - if (IN6_IS_ADDR_UNSPECIFIED(&rt[i].target) && (!crt || crt->priority > rt[i].priority)) - crt = &rt[i]; - - struct sockaddr_ll dest = { - .sll_family = AF_PACKET, - .sll_protocol = htons(ETH_P_IPV6), - .sll_ifindex = if_index, - .sll_halen = ETH_ALEN, - }; - - if (crt) { - struct { - struct nlmsghdr hdr; - struct ndmsg ndm; - } req = { - .hdr = {sizeof(req), RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP, 1, 0}, - .ndm = {.ndm_family = AF_INET6, .ndm_ifindex = if_index} - }; - send(rtnl, &req, sizeof(req), 0); - - uint8_t buf[8192]; - struct nlmsghdr *nhm; - do { - ssize_t read = recv(rtnl, buf, sizeof(buf), 0); - nhm = (struct nlmsghdr*)buf; - if ((read < 0 && errno == EINTR) || !NLMSG_OK(nhm, (size_t)read)) - continue; - else if (read < 0) - break; - - for (; read > 0 && NLMSG_OK(nhm, (size_t)read); nhm = NLMSG_NEXT(nhm, read)) { - ssize_t attrlen = NLMSG_PAYLOAD(nhm, sizeof(struct ndmsg)); - if (nhm->nlmsg_type != RTM_NEWNEIGH || attrlen <= 0) { - nhm = NULL; - break; - } - - // Already have our MAC - if (crt_found) - continue; - - struct ndmsg *ndm = NLMSG_DATA(nhm); - for (struct rtattr *rta = (struct rtattr*)&ndm[1]; - attrlen > 0 && RTA_OK(rta, (size_t)attrlen); - rta = RTA_NEXT(rta, attrlen)) { - if (rta->rta_type == NDA_DST) { - crt_found = IN6_ARE_ADDR_EQUAL(RTA_DATA(rta), &crt->router); - } else if (rta->rta_type == NDA_LLADDR) { - memcpy(dest.sll_addr, RTA_DATA(rta), ETH_ALEN); - } - } - } - } while (nhm); - } - - if (!crt_found || !cpd) - return; - - ping.ip6.ip6_src = cpd->target; - ping.ip6.ip6_dst = cpd->target; - - struct sock_filter bpf[] = { - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct ip6_hdr, ip6_plen)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8 << 16 | IPPROTO_ICMPV6 << 8 | 254, 0, 13), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct ip6_hdr, ip6_dst)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ntohl(ping.ip6.ip6_dst.s6_addr32[0]), 0, 11), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct ip6_hdr, ip6_dst) + 4), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ntohl(ping.ip6.ip6_dst.s6_addr32[1]), 0, 9), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct ip6_hdr, ip6_dst) + 8), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ntohl(ping.ip6.ip6_dst.s6_addr32[2]), 0, 7), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct ip6_hdr, ip6_dst) + 12), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ntohl(ping.ip6.ip6_dst.s6_addr32[3]), 0, 5), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, sizeof(struct ip6_hdr) + - offsetof(struct icmp6_hdr, icmp6_type)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REQUEST << 24, 0, 3), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, sizeof(struct ip6_hdr) + - offsetof(struct icmp6_hdr, icmp6_data32)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ntohl(ping.icmp6.icmp6_data32[0]), 0, 1), - BPF_STMT(BPF_RET | BPF_K, 0xffffffff), - BPF_STMT(BPF_RET | BPF_K, 0), - }; - struct sock_fprog bpf_prog = {sizeof(bpf) / sizeof(*bpf), bpf}; - - - if (sock < 0) { - sock = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IPV6)); - bind(sock, (struct sockaddr*)&dest, sizeof(dest)); - - fcntl(sock, F_SETOWN, getpid()); - fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_ASYNC); - } - - setsockopt(sock, SOL_SOCKET, SO_DETACH_FILTER, &bpf_prog, sizeof(bpf_prog)); - if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog, sizeof(bpf_prog))) { - close(sock); - sock = -1; - return; - } - - uint8_t dummy[8]; - while (recv(sock, dummy, sizeof(dummy), MSG_DONTWAIT | MSG_TRUNC) > 0); - - sendto(sock, &ping, sizeof(ping), MSG_DONTWAIT, - (struct sockaddr*)&dest, sizeof(dest)); -} - - -void bfd_receive(void) -{ - uint8_t dummy[8]; - while (recv(sock, dummy, sizeof(dummy), MSG_DONTWAIT | MSG_TRUNC) > 0) { - bfd_failed = 0; - bfd_armed = true; - } -} - - -int bfd_start(const char *ifname, int limit, int interval) -{ - if_index = if_nametoindex(ifname); - bfd_armed = false; - bfd_failed = 0; - bfd_limit = limit; - bfd_interval = interval; - - if (limit < 1 || interval < 1) - return 0; - - rtnl = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE); - struct sockaddr_nl rtnl_kernel = { .nl_family = AF_NETLINK }; - connect(rtnl, (const struct sockaddr*)&rtnl_kernel, sizeof(rtnl_kernel)); - - signal(SIGALRM, bfd_send); - alarm(5); - return 0; -} - - -void bfd_stop(void) -{ - alarm(0); - close(sock); - close(rtnl); - - sock = -1; - rtnl = -1; -} diff --git a/src/bfd.h b/src/bfd.h deleted file mode 100644 index 0d3616a..0000000 --- a/src/bfd.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (C) 2012-2013 Steven Barth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#pragma once - -int bfd_start(const char *ifname, int limit, int interval); -void bfd_receive(void); -void bfd_stop(void); diff --git a/src/odhcp6c.c b/src/odhcp6c.c index f1286e5..2357a9a 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -32,9 +32,6 @@ #include "odhcp6c.h" #include "ra.h" -#ifdef EXT_BFD_PING -#include "bfd.h" -#endif static void sighandler(int signal); @@ -70,9 +67,6 @@ int main(_unused int argc, char* const argv[]) static struct in6_addr ifid = IN6ADDR_ANY_INIT; int sol_timeout = DHCPV6_SOL_MAX_RT; -#ifdef EXT_BFD_PING - int bfd_interval = 0, bfd_loss = 3; -#endif bool help = false, daemonize = false; int logopt = LOG_PID; @@ -141,12 +135,6 @@ int main(_unused int argc, char* const argv[]) ia_pd_mode = IA_MODE_FORCE; break; -#ifdef EXT_BFD_PING - case 'B': - bfd_interval = atoi(optarg); - break; -#endif - case 'c': l = script_unhexlify(&buf[4], sizeof(buf) - 4, optarg); if (l > 0) { @@ -350,10 +338,6 @@ int main(_unused int argc, char* const argv[]) script_call("bound"); bound = true; syslog(LOG_NOTICE, "entering stateful-mode on %s", ifname); -#ifdef EXT_BFD_PING - if (bfd_interval > 0) - bfd_start(ifname, bfd_loss, bfd_interval); -#endif while (!signal_usr2 && !signal_term) { // Renew Cycle @@ -396,9 +380,6 @@ int main(_unused int argc, char* const argv[]) if (res > 0) script_call("rebound"); else { -#ifdef EXT_BFD_PING - bfd_stop(); -#endif break; } } @@ -439,9 +420,6 @@ static int usage(void) " -P Request IPv6-Prefix (0 = auto)\n" " -F Force IPv6-Prefix\n" " -V Set vendor-class option (base-16 encoded)\n" -#ifdef EXT_BFD_PING - " -B Enable BFD ping check\n" -#endif " -u Set user-class option string\n" " -c Override client-ID (base-16 encoded)\n" " -i Use a custom interface identifier for RA handling\n" @@ -505,9 +483,6 @@ bool odhcp6c_signal_process(void) else if (ra_updated && !bound && allow_slaac_only > 0) script_delay_call("ra-updated", allow_slaac_only); -#ifdef EXT_BFD_PING - bfd_receive(); -#endif } return signal_usr1 || signal_usr2 || signal_term; -- 2.39.2 From fc0f3fd210223120a63e64cb707097b93568173a Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 22 Aug 2014 16:07:37 +0200 Subject: [PATCH 12/16] ia_na: use big-endian 1 as IAID --- src/dhcpv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 0c98729..e52fd6c 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -366,7 +366,7 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) struct dhcpv6_ia_hdr hdr_ia_na = { htons(DHCPV6_OPT_IA_NA), htons(sizeof(hdr_ia_na) - 4), - 1, 0, 0 + htonl(1), 0, 0 }; struct dhcpv6_ia_addr pa[ia_na_entries]; -- 2.39.2 From 6959336df6e667145c0670f4455ca59e81f89a34 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 22 Aug 2014 16:09:34 +0200 Subject: [PATCH 13/16] Also test for correct IA-ID for IA_NA --- src/dhcpv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index e52fd6c..aafd237 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -934,7 +934,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]); // 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; -- 2.39.2 From 0300fe7589a1701361735ac068e4b57bb1a1896f Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 25 Aug 2014 08:08:56 +0200 Subject: [PATCH 14/16] Enable softwire-support by default --- CMakeLists.txt | 4 ---- README | 6 +++--- src/dhcpv6.c | 4 ---- src/odhcp6c.h | 20 +++++++++----------- src/script.c | 8 ++------ 5 files changed, 14 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e508f1..f85334c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,10 +15,6 @@ if(${EXT_CER_ID}) add_definitions(-DEXT_CER_ID=${EXT_CER_ID}) endif(${EXT_CER_ID}) -if(${EXT_S46}) - add_definitions(-DEXT_S46=${EXT_S46}) -endif(${EXT_S46}) - add_executable(odhcp6c src/odhcp6c.c src/dhcpv6.c src/ra.c src/script.c src/md5.c) target_link_libraries(odhcp6c resolv) diff --git a/README b/README index f9abd49..91cefc0 100644 --- a/README +++ b/README @@ -28,9 +28,9 @@ especially routers. It compiles to only about 30 KB (-Os -s). g) Information-Refresh Options h) Configurable SOL_MAX_RT i) DS-Lite AFTR-Name Option - j) Prefix Class (experimental) - k) CER-ID (experimental) - l) Softwire address and port mapped clients (experimental) + j) Softwire address and port mapped clients (MAP, LW4over6) + k) Prefix Class (experimental) + l) CER-ID (experimental) 4. Support for requesting and parsing Router Advertisements a) parsing of prefixes, routes, MTU and RDNSS options diff --git a/src/dhcpv6.c b/src/dhcpv6.c index aafd237..b7fccac 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)); } @@ -1041,7 +1039,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 +1051,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 || diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 01fb072..59c4a42 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -73,17 +73,15 @@ enum dhcvp6_opt { /* draft-donley-dhc-cer-id-option-03 */ DHCPV6_OPT_CER_ID = EXT_CER_ID, #endif -#ifdef EXT_S46 - /* draft-ietf-softwire-map-dhcp-07 */ - DHCPV6_OPT_S46_RULE = EXT_S46, - DHCPV6_OPT_S46_BR = EXT_S46 + 1, - DHCPV6_OPT_S46_DMR = EXT_S46 + 2, - DHCPV6_OPT_S46_V4V6BIND = EXT_S46 + 3, - DHCPV6_OPT_S46_PORTPARAMS = EXT_S46 + 4, - DHCPV6_OPT_S46_CONT_MAPE = EXT_S46 + 5, - DHCPV6_OPT_S46_CONT_MAPT = EXT_S46 + 6, - DHCPV6_OPT_S46_CONT_LW = EXT_S46 + 7, -#endif + /* draft-ietf-softwire-map-dhcp-08 */ + DHCPV6_OPT_S46_RULE = 89, + DHCPV6_OPT_S46_BR = 90, + DHCPV6_OPT_S46_DMR = 91, + DHCPV6_OPT_S46_V4V6BIND = 92, + DHCPV6_OPT_S46_PORTPARAMS = 93, + DHCPV6_OPT_S46_CONT_MAPE = 94, + DHCPV6_OPT_S46_CONT_MAPT = 95, + DHCPV6_OPT_S46_CONT_LW = 96, }; enum dhcpv6_opt_npt { diff --git a/src/script.c b/src/script.c index 389dc37..d443ede 100644 --- a/src/script.c +++ b/src/script.c @@ -209,7 +209,7 @@ static void entry_to_env(const char *name, const void *data, size_t len, enum en putenv(buf); } -#ifdef EXT_S46 + static void s46_to_env_portparams(const uint8_t *data, size_t len, FILE *fp) { uint8_t *odata; @@ -223,7 +223,7 @@ static void s46_to_env_portparams(const uint8_t *data, size_t len, FILE *fp) } } } -#endif + static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len) { @@ -237,7 +237,6 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len fputs(name, fp); fputc('=', fp); -#ifdef EXT_S46 const char *type = (state == STATE_S46_MAPE) ? "map-e" : (state == STATE_S46_MAPT) ? "map-t" : "lw4o6"; @@ -327,9 +326,6 @@ static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len fputc(' ', fp); } -#else - if (data && len) {} -#endif fclose(fp); putenv(str); -- 2.39.2 From 3e52a1448eee0fbf7ff67c123265bedcbc9c26d0 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Sat, 27 Sep 2014 18:54:43 +0200 Subject: [PATCH 15/16] Send RS alternatingly with and without source MAC --- src/ra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ra.c b/src/ra.c index b700c9a..baaee9b 100644 --- a/src/ra.c +++ b/src/ra.c @@ -146,7 +146,7 @@ static void ra_send_rs(int signal __attribute__((unused))) struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); - if (!ioctl(sock, SIOCGIFHWADDR, &ifr) + if ((rs_attempt % 2 == 0) && !ioctl(sock, SIOCGIFHWADDR, &ifr) && memcmp(rs.lladdr.data, ifr.ifr_hwaddr.sa_data, 6)) memcpy(rs.lladdr.data, ifr.ifr_hwaddr.sa_data, 6); else -- 2.39.2 From d6fe99f6d03873e7a670c9b6f26fa03b219422f5 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 6 Oct 2014 10:29:43 +0200 Subject: [PATCH 16/16] Export DHCPv6 server address to env --- src/dhcpv6.c | 25 ++++++++++++++++--------- src/odhcp6c.c | 2 ++ src/odhcp6c.h | 3 ++- src/script.c | 4 +++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index b7fccac..30c9fb2 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -551,10 +551,12 @@ 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, + struct sockaddr_in6 addr; + struct msghdr msg = {&addr, sizeof(addr), &iov, 1, cmsg_buf, sizeof(cmsg_buf), 0}; struct in6_pktinfo *pktinfo = NULL; + // Check for pending signal if (odhcp6c_signal_process()) return -1; @@ -599,7 +601,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; @@ -729,7 +731,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; @@ -739,14 +741,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; @@ -854,18 +856,18 @@ 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; @@ -1090,6 +1092,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) { diff --git a/src/odhcp6c.c b/src/odhcp6c.c index 2357a9a..c76c813 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -266,6 +266,7 @@ int main(_unused int argc, char* const argv[]) while (!signal_term) { // Main logic odhcp6c_clear_state(STATE_SERVER_ID); + odhcp6c_clear_state(STATE_SERVER_ADDR); odhcp6c_clear_state(STATE_IA_NA); odhcp6c_clear_state(STATE_IA_PD); odhcp6c_clear_state(STATE_SNTP_IP); @@ -365,6 +366,7 @@ int main(_unused int argc, char* const argv[]) } odhcp6c_clear_state(STATE_SERVER_ID); // Remove binding + odhcp6c_clear_state(STATE_SERVER_ADDR); size_t ia_pd_len, ia_na_len; odhcp6c_get_state(STATE_IA_PD, &ia_pd_len); diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 59c4a42..a4343b1 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -123,7 +123,7 @@ enum dhcpv6_config { }; typedef int(reply_handler)(enum dhcpv6_msg orig, const int rc, - const void *opt, const void *end); + const void *opt, const void *end, const struct sockaddr_in6 *from); // retransmission strategy struct dhcpv6_retx { @@ -246,6 +246,7 @@ enum odhcp6c_state { STATE_CLIENT_ID, STATE_SERVER_ID, STATE_SERVER_CAND, + STATE_SERVER_ADDR, STATE_ORO, STATE_DNS, STATE_SEARCH, diff --git a/src/script.c b/src/script.c index d443ede..e389cc9 100644 --- a/src/script.c +++ b/src/script.c @@ -354,7 +354,7 @@ void script_delay_call(const char *status, int timeout) void script_call(const char *status) { size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len; - size_t sip_ip_len, sip_fqdn_len, aftr_name_len, cer_len; + size_t sip_ip_len, sip_fqdn_len, aftr_name_len, cer_len, addr_len; size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len; odhcp6c_expire(); @@ -363,6 +363,7 @@ void script_call(const char *status) dont_delay = true; } + struct in6_addr *addr = odhcp6c_get_state(STATE_SERVER_ADDR, &addr_len); struct in6_addr *dns = odhcp6c_get_state(STATE_DNS, &dns_len); uint8_t *search = odhcp6c_get_state(STATE_SEARCH, &search_len); uint8_t *custom = odhcp6c_get_state(STATE_CUSTOM_OPTS, &custom_len); @@ -387,6 +388,7 @@ void script_call(const char *status) // Don't set environment before forking, because env is leaky. if (fork() == 0) { + ipv6_to_env("SERVER", addr, addr_len / sizeof(*addr)); ipv6_to_env("RDNSS", dns, dns_len / sizeof(*dns)); ipv6_to_env("SNTP_IP", sntp, sntp_ip_len / sizeof(*sntp)); ipv6_to_env("NTP_IP", ntp, ntp_ip_len / sizeof(*ntp)); -- 2.39.2