diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-06-26 19:42:48 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-06-26 19:42:48 +0200 |
commit | 234b82ca19afb20276722334ecf1576f801cb588 (patch) | |
tree | bfeeaeed852df8febe5a22719469d28a1bda62d4 | |
parent | 4add757929a33203e6b5f829eb518654a73ad4e4 (diff) | |
download | busybox-w32-234b82ca19afb20276722334ecf1576f801cb588.tar.gz busybox-w32-234b82ca19afb20276722334ecf1576f801cb588.tar.bz2 busybox-w32-234b82ca19afb20276722334ecf1576f801cb588.zip |
udhcpc6: add support for timezones
Basedon patch by Bernd Holzmüller <bernd.holzmueller@tiggerswelt.net>
function old new delta
option_to_env 504 580 +76
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/udhcp/d6_common.h | 3 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 104 |
2 files changed, 59 insertions, 48 deletions
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h index fcec8c15a..ca5788390 100644 --- a/networking/udhcp/d6_common.h +++ b/networking/udhcp/d6_common.h | |||
@@ -89,6 +89,9 @@ struct d6_option { | |||
89 | 89 | ||
90 | #define D6_OPT_CLIENT_FQDN 39 | 90 | #define D6_OPT_CLIENT_FQDN 39 |
91 | 91 | ||
92 | #define D6_OPT_TZ_POSIX 41 | ||
93 | #define D6_OPT_TZ_NAME 42 | ||
94 | |||
92 | /*** Other shared functions ***/ | 95 | /*** Other shared functions ***/ |
93 | 96 | ||
94 | struct client6_data_t { | 97 | struct client6_data_t { |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 18a104c61..08a26fb57 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -93,7 +93,7 @@ static const char opt_req[] = { | |||
93 | 0, 6, | 93 | 0, 6, |
94 | (D6_OPT_DNS_SERVERS >> 8), (D6_OPT_DNS_SERVERS & 0xff), | 94 | (D6_OPT_DNS_SERVERS >> 8), (D6_OPT_DNS_SERVERS & 0xff), |
95 | (D6_OPT_DOMAIN_LIST >> 8), (D6_OPT_DOMAIN_LIST & 0xff), | 95 | (D6_OPT_DOMAIN_LIST >> 8), (D6_OPT_DOMAIN_LIST & 0xff), |
96 | (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff) | 96 | (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff), |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static const char opt_fqdn_req[] = { | 99 | static const char opt_fqdn_req[] = { |
@@ -136,12 +136,6 @@ static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code) | |||
136 | return xmemdup(opt, opt[3] + 4); | 136 | return xmemdup(opt, opt[3] + 4); |
137 | } | 137 | } |
138 | 138 | ||
139 | static void *d6_store_blob(void *dst, const void *src, unsigned len) | ||
140 | { | ||
141 | memcpy(dst, src, len); | ||
142 | return dst + len; | ||
143 | } | ||
144 | |||
145 | 139 | ||
146 | /*** Script execution code ***/ | 140 | /*** Script execution code ***/ |
147 | 141 | ||
@@ -154,10 +148,10 @@ static char** new_env(void) | |||
154 | /* put all the parameters into the environment */ | 148 | /* put all the parameters into the environment */ |
155 | static void option_to_env(uint8_t *option, uint8_t *option_end) | 149 | static void option_to_env(uint8_t *option, uint8_t *option_end) |
156 | { | 150 | { |
157 | char *dlist, *ptr; | 151 | char *dlist; |
158 | /* "length minus 4" */ | 152 | /* "length minus 4" */ |
159 | int len_m4 = option_end - option - 4; | 153 | int len_m4 = option_end - option - 4; |
160 | int olen, ooff; | 154 | int addrs, option_offset; |
161 | while (len_m4 >= 0) { | 155 | while (len_m4 >= 0) { |
162 | uint32_t v32; | 156 | uint32_t v32; |
163 | char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; | 157 | char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; |
@@ -165,6 +159,10 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
165 | if (option[0] != 0 || option[2] != 0) | 159 | if (option[0] != 0 || option[2] != 0) |
166 | break; | 160 | break; |
167 | 161 | ||
162 | /* Check if option-length exceeds size of option */ | ||
163 | if (option[3] > len_m4) | ||
164 | break; | ||
165 | |||
168 | switch (option[1]) { | 166 | switch (option[1]) { |
169 | //case D6_OPT_CLIENTID: | 167 | //case D6_OPT_CLIENTID: |
170 | //case D6_OPT_SERVERID: | 168 | //case D6_OPT_SERVERID: |
@@ -174,7 +172,7 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
174 | break; | 172 | break; |
175 | //case D6_OPT_IA_TA: | 173 | //case D6_OPT_IA_TA: |
176 | case D6_OPT_IAADDR: | 174 | case D6_OPT_IAADDR: |
177 | /* 0 1 2 3 | 175 | /* 0 1 2 3 |
178 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | 176 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
179 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 177 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
180 | * | OPTION_IAADDR | option-len | | 178 | * | OPTION_IAADDR | option-len | |
@@ -236,22 +234,25 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
236 | *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); | 234 | *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); |
237 | break; | 235 | break; |
238 | case D6_OPT_DNS_SERVERS: | 236 | case D6_OPT_DNS_SERVERS: |
239 | olen = ((option[2] << 8) | option[3]) / 16; | 237 | /* Make sure payload-size is a multiple of 16 */ |
240 | dlist = ptr = malloc (4 + olen * 40 - 1); | 238 | if ((option[3] & 0x0f) != 0) |
241 | 239 | break; | |
242 | memcpy (ptr, "dns=", 4); | ||
243 | ptr += 4; | ||
244 | ooff = 0; | ||
245 | |||
246 | while (olen--) { | ||
247 | sprint_nip6(ptr, option + 4 + ooff); | ||
248 | ptr += 39; | ||
249 | ooff += 16; | ||
250 | if (olen) | ||
251 | *ptr++ = ' '; | ||
252 | } | ||
253 | 240 | ||
254 | *new_env() = dlist; | 241 | /* Get the number of addresses on the option */ |
242 | addrs = option[3] >> 4; | ||
243 | |||
244 | /* Setup environment variable */ | ||
245 | *new_env() = dlist = xmalloc(4 + addrs * 40 - 1); | ||
246 | dlist = stpcpy(dlist, "dns="); | ||
247 | option_offset = 0; | ||
248 | |||
249 | while (addrs--) { | ||
250 | sprint_nip6(dlist, option + 4 + option_offset); | ||
251 | dlist += 39; | ||
252 | option_offset += 16; | ||
253 | if (addrs) | ||
254 | *dlist++ = ' '; | ||
255 | } | ||
255 | 256 | ||
256 | break; | 257 | break; |
257 | case D6_OPT_DOMAIN_LIST: | 258 | case D6_OPT_DOMAIN_LIST: |
@@ -261,24 +262,31 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
261 | *new_env() = dlist; | 262 | *new_env() = dlist; |
262 | break; | 263 | break; |
263 | case D6_OPT_CLIENT_FQDN: | 264 | case D6_OPT_CLIENT_FQDN: |
264 | // Work around broken ISC DHCPD6 | 265 | if (option[3] == 0) |
266 | break; | ||
267 | /* Work around broken ISC DHCPD6. | ||
268 | * ISC DHCPD6 does not implement RFC 4704 correctly: It says the first | ||
269 | * byte of option-payload should contain flags where the bits 7-3 are | ||
270 | * reserved for future use and MUST be zero. Instead ISC DHCPD6 just | ||
271 | * writes the entire FQDN as string to option-payload. We assume a | ||
272 | * broken server here if any of the reserved bits are set. | ||
273 | */ | ||
265 | if (option[4] & 0xf8) { | 274 | if (option[4] & 0xf8) { |
266 | olen = ((option[2] << 8) | option[3]); | 275 | *new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4); |
267 | dlist = xmalloc(olen); | ||
268 | //fixme: | ||
269 | //- explain | ||
270 | //- add len error check | ||
271 | //- merge two allocs into one | ||
272 | memcpy(dlist, option + 4, olen); | ||
273 | *new_env() = xasprintf("fqdn=%s", dlist); | ||
274 | free(dlist); | ||
275 | break; | 276 | break; |
276 | } | 277 | } |
277 | dlist = dname_dec(option + 5, ((option[2] << 8) | option[3]) - 1, "fqdn="); | 278 | dlist = dname_dec(option + 5, (/*(option[2] << 8) |*/ option[3]) - 1, "fqdn="); |
278 | if (!dlist) | 279 | if (!dlist) |
279 | break; | 280 | break; |
280 | *new_env() = dlist; | 281 | *new_env() = dlist; |
281 | break; | 282 | break; |
283 | /* RFC 4833 Timezones */ | ||
284 | case D6_OPT_TZ_POSIX: | ||
285 | *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4); | ||
286 | break; | ||
287 | case D6_OPT_TZ_NAME: | ||
288 | *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4); | ||
289 | break; | ||
282 | } | 290 | } |
283 | len_m4 -= 4 + option[3]; | 291 | len_m4 -= 4 + option[3]; |
284 | option += 4 + option[3]; | 292 | option += 4 + option[3]; |
@@ -346,7 +354,7 @@ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid | |||
346 | packet->d6_msg_type = type; | 354 | packet->d6_msg_type = type; |
347 | 355 | ||
348 | clientid = (void*)client_config.clientid; | 356 | clientid = (void*)client_config.clientid; |
349 | return d6_store_blob(packet->d6_options, clientid, clientid->len + 2+2); | 357 | return mempcpy(packet->d6_options, clientid, clientid->len + 2+2); |
350 | } | 358 | } |
351 | 359 | ||
352 | static uint8_t *add_d6_client_options(uint8_t *ptr) | 360 | static uint8_t *add_d6_client_options(uint8_t *ptr) |
@@ -483,11 +491,11 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip | |||
483 | iaaddr->len = 16+4+4; | 491 | iaaddr->len = 16+4+4; |
484 | memcpy(iaaddr->data, requested_ipv6, 16); | 492 | memcpy(iaaddr->data, requested_ipv6, 16); |
485 | } | 493 | } |
486 | opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len); | 494 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len); |
487 | 495 | ||
488 | /* Request additional options */ | 496 | /* Request additional options */ |
489 | opt_ptr = d6_store_blob(opt_ptr, &opt_req, sizeof(opt_req)); | 497 | opt_ptr = mempcpy(opt_ptr, &opt_req, sizeof(opt_req)); |
490 | opt_ptr = d6_store_blob(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); | 498 | opt_ptr = mempcpy(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); |
491 | 499 | ||
492 | /* Add options: | 500 | /* Add options: |
493 | * "param req" option according to -O, options specified with -x | 501 | * "param req" option according to -O, options specified with -x |
@@ -538,13 +546,13 @@ static NOINLINE int send_d6_select(uint32_t xid) | |||
538 | opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); | 546 | opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); |
539 | 547 | ||
540 | /* server id */ | 548 | /* server id */ |
541 | opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); | 549 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); |
542 | /* IA NA (contains requested IP) */ | 550 | /* IA NA (contains requested IP) */ |
543 | opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); | 551 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); |
544 | 552 | ||
545 | /* Request additional options */ | 553 | /* Request additional options */ |
546 | opt_ptr = d6_store_blob(opt_ptr, &opt_req, sizeof(opt_req)); | 554 | opt_ptr = mempcpy(opt_ptr, &opt_req, sizeof(opt_req)); |
547 | opt_ptr = d6_store_blob(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); | 555 | opt_ptr = mempcpy(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); |
548 | 556 | ||
549 | /* Add options: | 557 | /* Add options: |
550 | * "param req" option according to -O, options specified with -x | 558 | * "param req" option according to -O, options specified with -x |
@@ -611,9 +619,9 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st | |||
611 | opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); | 619 | opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); |
612 | 620 | ||
613 | /* server id */ | 621 | /* server id */ |
614 | opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); | 622 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); |
615 | /* IA NA (contains requested IP) */ | 623 | /* IA NA (contains requested IP) */ |
616 | opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); | 624 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); |
617 | 625 | ||
618 | /* Add options: | 626 | /* Add options: |
619 | * "param req" option according to -O, options specified with -x | 627 | * "param req" option according to -O, options specified with -x |
@@ -640,9 +648,9 @@ static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cu | |||
640 | /* Fill in: msg type, client id */ | 648 | /* Fill in: msg type, client id */ |
641 | opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); | 649 | opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); |
642 | /* server id */ | 650 | /* server id */ |
643 | opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); | 651 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); |
644 | /* IA NA (contains our current IP) */ | 652 | /* IA NA (contains our current IP) */ |
645 | opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); | 653 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); |
646 | 654 | ||
647 | bb_error_msg("sending %s", "release"); | 655 | bb_error_msg("sending %s", "release"); |
648 | return d6_send_kernel_packet( | 656 | return d6_send_kernel_packet( |