aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-06-26 19:42:48 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-06-26 19:42:48 +0200
commit234b82ca19afb20276722334ecf1576f801cb588 (patch)
treebfeeaeed852df8febe5a22719469d28a1bda62d4
parent4add757929a33203e6b5f829eb518654a73ad4e4 (diff)
downloadbusybox-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.h3
-rw-r--r--networking/udhcp/d6_dhcpc.c104
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
94struct client6_data_t { 97struct 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
99static const char opt_fqdn_req[] = { 99static 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
139static 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 */
155static void option_to_env(uint8_t *option, uint8_t *option_end) 149static 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
352static uint8_t *add_d6_client_options(uint8_t *ptr) 360static 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(