1 /* vi: set sw=4 ts=4: */
2 /*
3 * DHCPv6 client.
4 *
5 * Copyright (C) 2011-2017 Denys Vlasenko.
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9 //config:config UDHCPC6
10 //config: bool "udhcpc6 (21 kb)"
11 //config: default y
12 //config: depends on FEATURE_IPV6
13 //config: help
14 //config: udhcpc6 is a DHCPv6 client
15 //config:
16 //config:config FEATURE_UDHCPC6_RFC3646
17 //config: bool "Support RFC 3646 (DNS server and search list)"
18 //config: default y
19 //config: depends on UDHCPC6
20 //config: help
21 //config: List of DNS servers and domain search list can be requested with
22 //config: "-O dns" and "-O search". If server gives these values,
23 //config: they will be set in environment variables "dns" and "search".
24 //config:
25 //config:config FEATURE_UDHCPC6_RFC4704
26 //config: bool "Support RFC 4704 (Client FQDN)"
27 //config: default y
28 //config: depends on UDHCPC6
29 //config: help
30 //config: You can request FQDN to be given by server using "-O fqdn".
31 //config:
32 //config:config FEATURE_UDHCPC6_RFC4833
33 //config: bool "Support RFC 4833 (Timezones)"
34 //config: default y
35 //config: depends on UDHCPC6
36 //config: help
37 //config: You can request POSIX timezone with "-O tz" and timezone name
38 //config: with "-O timezone".
39 //config:
40 //config:config FEATURE_UDHCPC6_RFC5970
41 //config: bool "Support RFC 5970 (Network Boot)"
42 //config: default y
43 //config: depends on UDHCPC6
44 //config: help
45 //config: You can request bootfile-url with "-O bootfile_url" and
46 //config: bootfile-params with "-O bootfile_params".
47
48 //applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP))
49
50 //kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o
51 //kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC3646) += domain_codec.o
52 //kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC4704) += domain_codec.o
53
54 #include <syslog.h>
55 /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
56 #define WANT_PIDFILE 1
57 #include "common.h"
58 #include "dhcpd.h"
59 #include "dhcpc.h"
60 #include "d6_common.h"
61
62 #include <netinet/if_ether.h>
63 #include <netpacket/packet.h>
64 #include <linux/filter.h>
65
66 /* "struct client_data_t client_data" is in bb_common_bufsiz1 */
67
68 static const struct dhcp_optflag d6_optflags[] = {
69 #if ENABLE_FEATURE_UDHCPC6_RFC3646
70 { OPTION_6RD | OPTION_LIST | OPTION_REQ, D6_OPT_DNS_SERVERS },
71 { OPTION_DNS_STRING | OPTION_LIST | OPTION_REQ, D6_OPT_DOMAIN_LIST },
72 #endif
73 #if ENABLE_FEATURE_UDHCPC6_RFC4704
74 { OPTION_DNS_STRING, D6_OPT_CLIENT_FQDN },
75 #endif
76 #if ENABLE_FEATURE_UDHCPC6_RFC4833
77 { OPTION_STRING, D6_OPT_TZ_POSIX },
78 { OPTION_STRING, D6_OPT_TZ_NAME },
79 #endif
80 #if ENABLE_FEATURE_UDHCPC6_RFC5970
81 { OPTION_STRING, D6_OPT_BOOT_URL },
82 { OPTION_STRING, D6_OPT_BOOT_PARAM },
83 #endif
84 { OPTION_STRING, 0xd1 }, /* DHCP_PXE_CONF_FILE */
85 { OPTION_STRING, 0xd2 }, /* DHCP_PXE_PATH_PREFIX */
86 { 0, 0 }
87 };
88 /* Must match d6_optflags[] order */
89 static const char d6_option_strings[] ALIGN1 =
90 #if ENABLE_FEATURE_UDHCPC6_RFC3646
91 "dns" "\0" /* D6_OPT_DNS_SERVERS */
92 "search" "\0" /* D6_OPT_DOMAIN_LIST */
93 #endif
94 #if ENABLE_FEATURE_UDHCPC6_RFC4704
95 "fqdn" "\0" /* D6_OPT_CLIENT_FQDN */
96 #endif
97 #if ENABLE_FEATURE_UDHCPC6_RFC4833
98 "tz" "\0" /* D6_OPT_TZ_POSIX */
99 "timezone" "\0" /* D6_OPT_TZ_NAME */
100 #endif
101 #if ENABLE_FEATURE_UDHCPC6_RFC5970
102 "bootfile_url" "\0" /* D6_OPT_BOOT_URL */
103 "bootfile_param" "\0" /* D6_OPT_BOOT_PARAM */
104 #endif
105 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
106 "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */
107 "\0";
108
109 #if ENABLE_LONG_OPTS
110 static const char udhcpc6_longopts[] ALIGN1 =
111 "interface\0" Required_argument "i"
112 "now\0" No_argument "n"
113 "pidfile\0" Required_argument "p"
114 "quit\0" No_argument "q"
115 "release\0" No_argument "R"
116 "request\0" Required_argument "r"
117 "requestprefix\0" No_argument "d"
118 "script\0" Required_argument "s"
119 "timeout\0" Required_argument "T"
120 "retries\0" Required_argument "t"
121 "tryagain\0" Required_argument "A"
122 "syslog\0" No_argument "S"
123 "request-option\0" Required_argument "O"
124 "no-default-options\0" No_argument "o"
125 "foreground\0" No_argument "f"
126 "stateless\0" No_argument "l"
127 USE_FOR_MMU(
128 "background\0" No_argument "b"
129 )
130 /// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a")
131 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
132 ;
133 #endif
134 /* Must match getopt32 option string order */
135 enum {
136 OPT_i = 1 << 0,
137 OPT_n = 1 << 1,
138 OPT_p = 1 << 2,
139 OPT_q = 1 << 3,
140 OPT_R = 1 << 4,
141 OPT_r = 1 << 5,
142 OPT_s = 1 << 6,
143 OPT_T = 1 << 7,
144 OPT_t = 1 << 8,
145 OPT_S = 1 << 9,
146 OPT_A = 1 << 10,
147 OPT_O = 1 << 11,
148 OPT_o = 1 << 12,
149 OPT_x = 1 << 13,
150 OPT_f = 1 << 14,
151 OPT_l = 1 << 15,
152 OPT_d = 1 << 16,
153 /* The rest has variable bit positions, need to be clever */
154 OPTBIT_d = 16,
155 USE_FOR_MMU( OPTBIT_b,)
156 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
157 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
158 USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,)
159 ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
160 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,)
161 };
162
163 #if ENABLE_FEATURE_UDHCPC6_RFC4704
164 static const char opt_fqdn_req[] = {
165 (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff),
166 0, 2, /* optlen */
167 0, /* flags: */
168 /* S=0: server SHOULD NOT perform AAAA RR updates */
169 /* O=0: client MUST set this bit to 0 */
170 /* N=0: server SHOULD perform updates (PTR RR only in our case, since S=0) */
171 0 /* empty DNS-encoded name */
172 };
173 #endif
174
175 /*** Utility functions ***/
176
d6_find_option(uint8_t * option,uint8_t * option_end,unsigned code)177 static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code)
178 {
179 /* "length minus 4" */
180 int len_m4 = option_end - option - 4;
181 while (len_m4 >= 0) {
182 /* Next option's len is too big? */
183 if (option[3] > len_m4)
184 return NULL; /* yes. bogus packet! */
185 /* So far we treat any opts with code >255
186 * or len >255 as bogus, and stop at once.
187 * This simplifies big-endian handling.
188 */
189 if (option[0] != 0 || option[2] != 0)
190 return NULL;
191 /* Option seems to be valid */
192 /* Does its code match? */
193 if (option[1] == code)
194 return option; /* yes! */
195 len_m4 -= option[3] + 4;
196 option += option[3] + 4;
197 }
198 return NULL;
199 }
200
d6_copy_option(uint8_t * option,uint8_t * option_end,unsigned code)201 static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code)
202 {
203 uint8_t *opt = d6_find_option(option, option_end, code);
204 if (!opt)
205 return opt;
206 return xmemdup(opt, opt[3] + 4);
207 }
208
209 /*** Script execution code ***/
210
new_env(void)211 static char** new_env(void)
212 {
213 client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx);
214 return &client6_data.env_ptr[client6_data.env_idx++];
215 }
216
string_option_to_env(const uint8_t * option,const uint8_t * option_end)217 static char *string_option_to_env(const uint8_t *option,
218 const uint8_t *option_end)
219 {
220 const char *ptr, *name = NULL;
221 unsigned val_len;
222 int i;
223
224 ptr = d6_option_strings;
225 i = 0;
226 while (*ptr) {
227 if (d6_optflags[i].code == option[1]) {
228 name = ptr;
229 goto found;
230 }
231 ptr += strlen(ptr) + 1;
232 i++;
233 }
234 bb_error_msg("can't find option name for 0x%x, skipping", option[1]);
235 return NULL;
236
237 found:
238 val_len = (option[2] << 8) | option[3];
239 if (val_len + &option[D6_OPT_DATA] > option_end) {
240 bb_simple_error_msg("option data exceeds option length");
241 return NULL;
242 }
243 return xasprintf("%s=%.*s", name, val_len, (char*)option + 4);
244 }
245
246 /* put all the parameters into the environment */
option_to_env(const uint8_t * option,const uint8_t * option_end)247 static void option_to_env(const uint8_t *option, const uint8_t *option_end)
248 {
249 #if ENABLE_FEATURE_UDHCPC6_RFC3646
250 int addrs, option_offset;
251 #endif
252 /* "length minus 4" */
253 int len_m4 = option_end - option - 4;
254
255 while (len_m4 >= 0) {
256 uint32_t v32;
257 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
258
259 if (option[0] != 0 || option[2] != 0)
260 break;
261
262 /* Check if option-length exceeds size of option */
263 if (option[3] > len_m4)
264 break;
265
266 switch (option[1]) {
267 //case D6_OPT_CLIENTID:
268 //case D6_OPT_SERVERID:
269 case D6_OPT_IA_NA:
270 case D6_OPT_IA_PD:
271 option_to_env(option + 16, option + 4 + option[3]);
272 break;
273 //case D6_OPT_IA_TA:
274 case D6_OPT_IAADDR:
275 /* 0 1 2 3
276 * 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
277 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278 * | OPTION_IAADDR | option-len |
279 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
280 * | |
281 * | IPv6 address |
282 * | |
283 * | |
284 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
285 * | preferred-lifetime |
286 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287 * | valid-lifetime |
288 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
289 */
290 /* Make sure payload contains an address */
291 if (option[3] < 24)
292 break;
293
294 sprint_nip6(ipv6str, option + 4);
295 *new_env() = xasprintf("ipv6=%s", ipv6str);
296
297 move_from_unaligned32(v32, option + 4 + 16 + 4);
298 *new_env() = xasprintf("lease=%u", (unsigned)v32);
299 break;
300
301 //case D6_OPT_ORO:
302 //case D6_OPT_PREFERENCE:
303 //case D6_OPT_ELAPSED_TIME:
304 //case D6_OPT_RELAY_MSG:
305 //case D6_OPT_AUTH:
306 //case D6_OPT_UNICAST:
307 //case D6_OPT_STATUS_CODE:
308 //case D6_OPT_RAPID_COMMIT:
309 //case D6_OPT_USER_CLASS:
310 //case D6_OPT_VENDOR_CLASS:
311 //case D6_OPT_VENDOR_OPTS:
312 //case D6_OPT_INTERFACE_ID:
313 //case D6_OPT_RECONF_MSG:
314 //case D6_OPT_RECONF_ACCEPT:
315
316 case D6_OPT_IAPREFIX:
317 /* 0 1 2 3
318 * 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
319 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320 * | OPTION_IAPREFIX | option-length |
321 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
322 * | preferred-lifetime |
323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 * | valid-lifetime |
325 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 * | prefix-length | |
327 * +-+-+-+-+-+-+-+-+ IPv6 prefix |
328 * | (16 octets) |
329 * | |
330 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 * | |
332 * +-+-+-+-+-+-+-+-+
333 */
334 move_from_unaligned32(v32, option + 4 + 4);
335 *new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
336
337 sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
338 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
339 break;
340 #if ENABLE_FEATURE_UDHCPC6_RFC3646
341 case D6_OPT_DNS_SERVERS: {
342 char *dlist;
343
344 /* Make sure payload-size is a multiple of 16 */
345 if ((option[3] & 0x0f) != 0)
346 break;
347
348 /* Get the number of addresses on the option */
349 addrs = option[3] >> 4;
350
351 /* Setup environment variable */
352 *new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
353 dlist = stpcpy(dlist, "dns=");
354 option_offset = 0;
355
356 while (addrs--) {
357 sprint_nip6(dlist, option + 4 + option_offset);
358 dlist += 39;
359 option_offset += 16;
360 if (addrs)
361 *dlist++ = ' ';
362 }
363
364 break;
365 }
366 case D6_OPT_DOMAIN_LIST: {
367 char *dlist;
368
369 dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
370 if (!dlist)
371 break;
372 *new_env() = dlist;
373 break;
374 }
375 #endif
376 #if ENABLE_FEATURE_UDHCPC6_RFC4704
377 case D6_OPT_CLIENT_FQDN: {
378 char *dlist;
379
380 if (option[3] == 0)
381 break;
382 /* Work around broken ISC DHCPD6.
383 * ISC DHCPD6 does not implement RFC 4704 correctly: It says the first
384 * byte of option-payload should contain flags where the bits 7-3 are
385 * reserved for future use and MUST be zero. Instead ISC DHCPD6 just
386 * writes the entire FQDN as string to option-payload. We assume a
387 * broken server here if any of the reserved bits are set.
388 */
389 if (option[4] & 0xf8) {
390 *new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4);
391 break;
392 }
393 dlist = dname_dec(option + 5, (/*(option[2] << 8) |*/ option[3]) - 1, "fqdn=");
394 if (!dlist)
395 break;
396 *new_env() = dlist;
397 break;
398 }
399 #endif
400 #if ENABLE_FEATURE_UDHCPC6_RFC4833
401 /* RFC 4833 Timezones */
402 case D6_OPT_TZ_POSIX:
403 *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4);
404 break;
405 case D6_OPT_TZ_NAME:
406 *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
407 break;
408 #endif
409 case D6_OPT_BOOT_URL:
410 case D6_OPT_BOOT_PARAM:
411 case 0xd1: /* DHCP_PXE_CONF_FILE */
412 case 0xd2: /* DHCP_PXE_PATH_PREFIX */
413 {
414 char *tmp = string_option_to_env(option, option_end);
415 if (tmp)
416 *new_env() = tmp;
417 break;
418 }
419 }
420 len_m4 -= 4 + option[3];
421 option += 4 + option[3];
422 }
423 }
424
fill_envp(const uint8_t * option,const uint8_t * option_end)425 static char **fill_envp(const uint8_t *option, const uint8_t *option_end)
426 {
427 char **envp, **curr;
428
429 client6_data.env_ptr = NULL;
430 client6_data.env_idx = 0;
431
432 *new_env() = xasprintf("interface=%s", client_data.interface);
433
434 if (option)
435 option_to_env(option, option_end);
436
437 envp = curr = client6_data.env_ptr;
438 while (*curr)
439 putenv(*curr++);
440
441 return envp;
442 }
443
444 /* Call a script with env vars */
d6_run_script(const uint8_t * option,const uint8_t * option_end,const char * name)445 static void d6_run_script(const uint8_t *option, const uint8_t *option_end,
446 const char *name)
447 {
448 char **envp, **curr;
449 char *argv[3];
450
451 envp = fill_envp(option, option_end);
452
453 /* call script */
454 log1("executing %s %s", client_data.script, name);
455 argv[0] = (char*) client_data.script;
456 argv[1] = (char*) name;
457 argv[2] = NULL;
458 spawn_and_wait(argv);
459
460 for (curr = envp; *curr; curr++) {
461 log2(" %s", *curr);
462 bb_unsetenv_and_free(*curr);
463 }
464 free(envp);
465 }
466
467 /* Call a script with no env var */
d6_run_script_no_option(const char * name)468 static void d6_run_script_no_option(const char *name)
469 {
470 d6_run_script(NULL, NULL, name);
471 }
472
473 /*** Sending/receiving packets ***/
474
random_xid(void)475 static ALWAYS_INLINE uint32_t random_xid(void)
476 {
477 uint32_t t = rand() & htonl(0x00ffffff);
478 return t;
479 }
480
481 /* Initialize the packet with the proper defaults */
init_d6_packet(struct d6_packet * packet,char type)482 static uint8_t *init_d6_packet(struct d6_packet *packet, char type)
483 {
484 uint8_t *ptr;
485 unsigned secs;
486
487 memset(packet, 0, sizeof(*packet));
488
489 packet->d6_xid32 = client_data.xid;
490 packet->d6_msg_type = type; /* union, overwrites lowest byte of d6_xid32 */
491
492 /* ELAPSED_TIME option is required to be present by the RFC,
493 * and some servers do check for its presense. [which?]
494 */
495 ptr = packet->d6_options; /* NB: it is 32-bit aligned */
496 *((uint32_t*)ptr) = htonl((D6_OPT_ELAPSED_TIME << 16) + 2);
497 ptr += 4;
498 client_data.last_secs = monotonic_sec();
499 if (client_data.first_secs == 0)
500 client_data.first_secs = client_data.last_secs;
501 secs = client_data.last_secs - client_data.first_secs;
502 *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff;
503 ptr += 2;
504
505 return ptr;
506 }
507
add_d6_client_options(uint8_t * ptr)508 static uint8_t *add_d6_client_options(uint8_t *ptr)
509 {
510 struct option_set *curr;
511 uint8_t *start = ptr;
512 unsigned option;
513 uint16_t len;
514
515 ptr += 4;
516 for (option = 1; option < 256; option++) {
517 if (client_data.opt_mask[option >> 3] & (1 << (option & 7))) {
518 ptr[0] = (option >> 8);
519 ptr[1] = option;
520 ptr += 2;
521 }
522 }
523
524 if ((ptr - start - 4) != 0) {
525 start[0] = (D6_OPT_ORO >> 8);
526 start[1] = D6_OPT_ORO;
527 start[2] = ((ptr - start - 4) >> 8);
528 start[3] = (ptr - start - 4);
529 } else
530 ptr = start;
531
532 #if ENABLE_FEATURE_UDHCPC6_RFC4704
533 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
534 #endif
535 /* Add -x options if any */
536 curr = client_data.options;
537 while (curr) {
538 len = (curr->data[D6_OPT_LEN] << 8) | curr->data[D6_OPT_LEN + 1];
539 ptr = mempcpy(ptr, curr->data, D6_OPT_DATA + len);
540 curr = curr->next;
541 }
542
543 return ptr;
544 }
545
d6_mcast_from_client_data_ifindex(struct d6_packet * packet,uint8_t * end)546 static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *end)
547 {
548 /* FF02::1:2 is "All_DHCP_Relay_Agents_and_Servers" address */
549 static const uint8_t FF02__1_2[16] = {
550 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
552 };
553 /* IPv6 requires different multicast contents in Ethernet Frame (RFC 2464) */
554 static const uint8_t MAC_DHCP6MCAST_ADDR[6] ALIGN2 = {
555 0x33, 0x33, 0x00, 0x01, 0x00, 0x02,
556 };
557
558 return d6_send_raw_packet_from_client_data_ifindex(
559 packet, (end - (uint8_t*) packet),
560 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
561 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_DHCP6MCAST_ADDR
562 );
563 }
564
565 /* RFC 3315 18.1.5. Creation and Transmission of Information-request Messages
566 *
567 * The client uses an Information-request message to obtain
568 * configuration information without having addresses assigned to it.
569 *
570 * The client sets the "msg-type" field to INFORMATION-REQUEST. The
571 * client generates a transaction ID and inserts this value in the
572 * "transaction-id" field.
573 *
574 * The client SHOULD include a Client Identifier option to identify
575 * itself to the server. If the client does not include a Client
576 * Identifier option, the server will not be able to return any client-
577 * specific options to the client, or the server may choose not to
578 * respond to the message at all. The client MUST include a Client
579 * Identifier option if the Information-Request message will be
580 * authenticated.
581 *
582 * The client MUST include an Option Request option (see section 22.7)
583 * to indicate the options the client is interested in receiving. The
584 * client MAY include options with data values as hints to the server
585 * about parameter values the client would like to have returned.
586 */
587 /* NOINLINE: limit stack usage in caller */
send_d6_info_request(void)588 static NOINLINE int send_d6_info_request(void)
589 {
590 struct d6_packet packet;
591 uint8_t *opt_ptr;
592
593 /* Fill in: msg type, xid, ELAPSED_TIME */
594 opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST);
595
596 /* Add options: client-id,
597 * "param req" option according to -O, options specified with -x
598 */
599 opt_ptr = add_d6_client_options(opt_ptr);
600
601 bb_error_msg("sending %s", "info request");
602 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
603 }
604
605 /* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
606 *
607 * RFC 3315 17.1.1. Creation of Solicit Messages
608 *
609 * The client MUST include a Client Identifier option to identify itself
610 * to the server. The client includes IA options for any IAs to which
611 * it wants the server to assign addresses. The client MAY include
612 * addresses in the IAs as a hint to the server about addresses for
613 * which the client has a preference. ...
614 *
615 * The client uses IA_NA options to request the assignment of non-
616 * temporary addresses and uses IA_TA options to request the assignment
617 * of temporary addresses. Either IA_NA or IA_TA options, or a
618 * combination of both, can be included in DHCP messages.
619 *
620 * The client SHOULD include an Option Request option (see section 22.7)
621 * to indicate the options the client is interested in receiving. The
622 * client MAY additionally include instances of those options that are
623 * identified in the Option Request option, with data values as hints to
624 * the server about parameter values the client would like to have
625 * returned.
626 *
627 * The client includes a Reconfigure Accept option (see section 22.20)
628 * if the client is willing to accept Reconfigure messages from the
629 * server.
630 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
631 | OPTION_CLIENTID | option-len |
632 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
633 . .
634 . DUID .
635 . (variable length) .
636 . .
637 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
638
639
640 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
641 | OPTION_IA_NA | option-len |
642 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
643 | IAID (4 octets) |
644 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
645 | T1 |
646 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
647 | T2 |
648 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
649 | |
650 . IA_NA-options .
651 . .
652 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
653
654
655 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
656 | OPTION_IAADDR | option-len |
657 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
658 | |
659 | IPv6 address |
660 | |
661 | |
662 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
663 | preferred-lifetime |
664 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
665 | valid-lifetime |
666 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
667 . .
668 . IAaddr-options .
669 . .
670 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
671
672
673 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
674 | OPTION_ORO | option-len |
675 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676 | requested-option-code-1 | requested-option-code-2 |
677 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
678 | ... |
679 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
680
681
682 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
683 | OPTION_RECONF_ACCEPT | 0 |
684 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
685 */
686 /* NOINLINE: limit stack usage in caller */
send_d6_discover(struct in6_addr * requested_ipv6)687 static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6)
688 {
689 struct d6_packet packet;
690 uint8_t *opt_ptr;
691 unsigned len;
692
693 /* Fill in: msg type, xid, ELAPSED_TIME */
694 opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT);
695
696 /* Create new IA_NA, optionally with included IAADDR with requested IP */
697 free(client6_data.ia_na);
698 client6_data.ia_na = NULL;
699 if (option_mask32 & OPT_r) {
700 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
701 client6_data.ia_na = xzalloc(len);
702 client6_data.ia_na->code = D6_OPT_IA_NA;
703 client6_data.ia_na->len = len - 4;
704 *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
705 if (requested_ipv6) {
706 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
707 iaaddr->code = D6_OPT_IAADDR;
708 iaaddr->len = 16+4+4;
709 memcpy(iaaddr->data, requested_ipv6, 16);
710 }
711 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
712 }
713
714 /* IA_PD */
715 free(client6_data.ia_pd);
716 client6_data.ia_pd = NULL;
717 if (option_mask32 & OPT_d) {
718 len = 2+2+4+4+4;
719 client6_data.ia_pd = xzalloc(len);
720 client6_data.ia_pd->code = D6_OPT_IA_PD;
721 client6_data.ia_pd->len = len - 4;
722 *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */
723 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
724 }
725
726 /* Add options: client-id,
727 * "param req" option according to -O, options specified with -x
728 */
729 opt_ptr = add_d6_client_options(opt_ptr);
730
731 bb_info_msg("sending %s", "discover");
732 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
733 }
734
735 /* Multicast a DHCPv6 request message
736 *
737 * RFC 3315 18.1.1. Creation and Transmission of Request Messages
738 *
739 * The client uses a Request message to populate IAs with addresses and
740 * obtain other configuration information. The client includes one or
741 * more IA options in the Request message. The server then returns
742 * addresses and other information about the IAs to the client in IA
743 * options in a Reply message.
744 *
745 * The client generates a transaction ID and inserts this value in the
746 * "transaction-id" field.
747 *
748 * The client places the identifier of the destination server in a
749 * Server Identifier option.
750 *
751 * The client MUST include a Client Identifier option to identify itself
752 * to the server. The client adds any other appropriate options,
753 * including one or more IA options (if the client is requesting that
754 * the server assign it some network addresses).
755 *
756 * The client MUST include an Option Request option (see section 22.7)
757 * to indicate the options the client is interested in receiving. The
758 * client MAY include options with data values as hints to the server
759 * about parameter values the client would like to have returned.
760 *
761 * The client includes a Reconfigure Accept option (see section 22.20)
762 * indicating whether or not the client is willing to accept Reconfigure
763 * messages from the server.
764 */
765 /* NOINLINE: limit stack usage in caller */
send_d6_select(void)766 static NOINLINE int send_d6_select(void)
767 {
768 struct d6_packet packet;
769 uint8_t *opt_ptr;
770
771 /* Fill in: msg type, xid, ELAPSED_TIME */
772 opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST);
773
774 /* server id */
775 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
776 /* IA NA (contains requested IP) */
777 if (client6_data.ia_na)
778 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
779 /* IA PD */
780 if (client6_data.ia_pd)
781 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
782
783 /* Add options: client-id,
784 * "param req" option according to -O, options specified with -x
785 */
786 opt_ptr = add_d6_client_options(opt_ptr);
787
788 bb_info_msg("sending %s", "select");
789 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
790 }
791
792 /* Unicast or broadcast a DHCP renew message
793 *
794 * RFC 3315 18.1.3. Creation and Transmission of Renew Messages
795 *
796 * To extend the valid and preferred lifetimes for the addresses
797 * associated with an IA, the client sends a Renew message to the server
798 * from which the client obtained the addresses in the IA containing an
799 * IA option for the IA. The client includes IA Address options in the
800 * IA option for the addresses associated with the IA. The server
801 * determines new lifetimes for the addresses in the IA according to the
802 * administrative configuration of the server. The server may also add
803 * new addresses to the IA. The server may remove addresses from the IA
804 * by setting the preferred and valid lifetimes of those addresses to
805 * zero.
806 *
807 * The server controls the time at which the client contacts the server
808 * to extend the lifetimes on assigned addresses through the T1 and T2
809 * parameters assigned to an IA.
810 *
811 * At time T1 for an IA, the client initiates a Renew/Reply message
812 * exchange to extend the lifetimes on any addresses in the IA. The
813 * client includes an IA option with all addresses currently assigned to
814 * the IA in its Renew message.
815 *
816 * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no
817 * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind
818 * message, respectively, at the client's discretion.
819 *
820 * The client sets the "msg-type" field to RENEW. The client generates
821 * a transaction ID and inserts this value in the "transaction-id"
822 * field.
823 *
824 * The client places the identifier of the destination server in a
825 * Server Identifier option.
826 *
827 * The client MUST include a Client Identifier option to identify itself
828 * to the server. The client adds any appropriate options, including
829 * one or more IA options. The client MUST include the list of
830 * addresses the client currently has associated with the IAs in the
831 * Renew message.
832 *
833 * The client MUST include an Option Request option (see section 22.7)
834 * to indicate the options the client is interested in receiving. The
835 * client MAY include options with data values as hints to the server
836 * about parameter values the client would like to have returned.
837 */
838 /* NOINLINE: limit stack usage in caller */
send_d6_renew(struct in6_addr * server_ipv6,struct in6_addr * our_cur_ipv6)839 static NOINLINE int send_d6_renew(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
840 {
841 struct d6_packet packet;
842 uint8_t *opt_ptr;
843
844 /* Fill in: msg type, xid, ELAPSED_TIME */
845 opt_ptr = init_d6_packet(&packet, DHCPREQUEST);
846
847 /* server id */
848 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
849 /* IA NA (contains requested IP) */
850 if (client6_data.ia_na)
851 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
852 /* IA PD */
853 if (client6_data.ia_pd)
854 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
855
856 /* Add options: client-id,
857 * "param req" option according to -O, options specified with -x
858 */
859 opt_ptr = add_d6_client_options(opt_ptr);
860
861 bb_info_msg("sending %s", "renew");
862 if (server_ipv6)
863 return d6_send_kernel_packet_from_client_data_ifindex(
864 &packet, (opt_ptr - (uint8_t*) &packet),
865 our_cur_ipv6, CLIENT_PORT6,
866 server_ipv6, SERVER_PORT6
867 );
868 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
869 }
870
871 /* Unicast a DHCP release message */
872 static
873 ALWAYS_INLINE /* one caller, help compiler to use this fact */
send_d6_release(struct in6_addr * server_ipv6,struct in6_addr * our_cur_ipv6)874 int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
875 {
876 struct d6_packet packet;
877 uint8_t *opt_ptr;
878 struct option_set *ci;
879
880 /* Fill in: msg type, xid, ELAPSED_TIME */
881 opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE);
882 /* server id */
883 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
884 /* IA NA (contains our current IP) */
885 if (client6_data.ia_na)
886 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
887 /* IA PD */
888 if (client6_data.ia_pd)
889 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
890 /* Client-id */
891 ///vda
892 ci = udhcp_find_option(client_data.options, D6_OPT_CLIENTID, /*dhcpv6:*/ 1);
893 if (ci)
894 opt_ptr = mempcpy(opt_ptr, ci->data, D6_OPT_DATA + 2+2 + 6);
895
896 bb_info_msg("sending %s", "release");
897 return d6_send_kernel_packet_from_client_data_ifindex(
898 &packet, (opt_ptr - (uint8_t*) &packet),
899 our_cur_ipv6, CLIENT_PORT6,
900 server_ipv6, SERVER_PORT6
901 );
902 }
903
904 /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
905 /* NOINLINE: limit stack usage in caller */
d6_recv_raw_packet(struct in6_addr * peer_ipv6,struct d6_packet * d6_pkt,int fd)906 static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_packet *d6_pkt, int fd)
907 {
908 int bytes;
909 struct ip6_udp_d6_packet packet;
910
911 bytes = safe_read(fd, &packet, sizeof(packet));
912 if (bytes < 0) {
913 log1s("packet read error, ignoring");
914 /* NB: possible down interface, etc. Caller should pause. */
915 return bytes; /* returns -1 */
916 }
917
918 if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) {
919 log1s("packet is too short, ignoring");
920 return -2;
921 }
922
923 if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) {
924 /* packet is bigger than sizeof(packet), we did partial read */
925 log1s("oversized packet, ignoring");
926 return -2;
927 }
928
929 /* ignore any extra garbage bytes */
930 bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen);
931
932 /* make sure its the right packet for us, and that it passes sanity checks */
933 if (packet.ip6.ip6_nxt != IPPROTO_UDP
934 || (packet.ip6.ip6_vfc >> 4) != 6
935 || packet.udp.dest != htons(CLIENT_PORT6)
936 /* || bytes > (int) sizeof(packet) - can't happen */
937 || packet.udp.len != packet.ip6.ip6_plen
938 ) {
939 log1s("unrelated/bogus packet, ignoring");
940 return -2;
941 }
942
943 //How to do this for ipv6?
944 // /* verify UDP checksum. IP header has to be modified for this */
945 // memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
946 // /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
947 // packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
948 // check = packet.udp.check;
949 // packet.udp.check = 0;
950 // if (check && check != inet_cksum(&packet, bytes)) {
951 // log1("packet with bad UDP checksum received, ignoring");
952 // return -2;
953 // }
954
955 if (peer_ipv6)
956 *peer_ipv6 = packet.ip6.ip6_src; /* struct copy */
957
958 log2("received %s", "a packet");
959 /* log2 because more informative msg for valid packets is printed later at log1 level */
960 d6_dump_packet(&packet.data);
961
962 bytes -= sizeof(packet.ip6) + sizeof(packet.udp);
963 memcpy(d6_pkt, &packet.data, bytes);
964 return bytes;
965 }
966
967 /*** Main ***/
968
969 /* Values for client_data.listen_mode */
970 #define LISTEN_NONE 0
971 #define LISTEN_KERNEL 1
972 #define LISTEN_RAW 2
973
974 /* Values for client_data.state */
975 /* initial state: (re)start DHCP negotiation */
976 #define INIT_SELECTING 0
977 /* discover was sent, DHCPOFFER reply received */
978 #define REQUESTING 1
979 /* select/renew was sent, DHCPACK reply received */
980 #define BOUND 2
981 /* half of lease passed, want to renew it by sending unicast renew requests */
982 #define RENEWING 3
983 /* renew requests were not answered, lease is almost over, send broadcast renew */
984 #define REBINDING 4
985 /* manually requested renew (SIGUSR1) */
986 #define RENEW_REQUESTED 5
987 /* release, possibly manually requested (SIGUSR2) */
988 #define RELEASED 6
989
d6_raw_socket(int ifindex)990 static int d6_raw_socket(int ifindex)
991 {
992 int fd;
993 struct sockaddr_ll sock;
994
995 /*
996 * Comment:
997 *
998 * I've selected not to see LL header, so BPF doesn't see it, too.
999 * The filter may also pass non-IP and non-ARP packets, but we do
1000 * a more complete check when receiving the message in userspace.
1001 *
1002 * and filter shamelessly stolen from:
1003 *
1004 * http://www.flamewarmaster.de/software/dhcpclient/
1005 *
1006 * There are a few other interesting ideas on that page (look under
1007 * "Motivation"). Use of netlink events is most interesting. Think
1008 * of various network servers listening for events and reconfiguring.
1009 * That would obsolete sending HUP signals and/or make use of restarts.
1010 *
1011 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
1012 * License: GPL v2.
1013 *
1014 * TODO: make conditional?
1015 */
1016 #if 0
1017 static const struct sock_filter filter_instr[] = {
1018 /* load 9th byte (protocol) */
1019 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1020 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
1021 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1022 /* L1: load halfword from offset 6 (flags and frag offset) */
1023 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1024 /* jump to L4 if any bits in frag offset field are set, else to L2 */
1025 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1026 /* L2: skip IP header (load index reg with header len) */
1027 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1028 /* load udp destination port from halfword[header_len + 2] */
1029 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1030 /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */
1031 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1032 /* L3: accept packet */
1033 BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
1034 /* L4: discard packet */
1035 BPF_STMT(BPF_RET|BPF_K, 0),
1036 };
1037 static const struct sock_fprog filter_prog = {
1038 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1039 /* casting const away: */
1040 .filter = (struct sock_filter *) filter_instr,
1041 };
1042 #endif
1043
1044 log2("opening raw socket on ifindex %d", ifindex);
1045
1046 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
1047
1048 memset(&sock, 0, sizeof(sock)); /* let's be deterministic */
1049 sock.sll_family = AF_PACKET;
1050 sock.sll_protocol = htons(ETH_P_IPV6);
1051 sock.sll_ifindex = ifindex;
1052 /*sock.sll_hatype = ARPHRD_???;*/
1053 /*sock.sll_pkttype = PACKET_???;*/
1054 /*sock.sll_halen = ???;*/
1055 /*sock.sll_addr[8] = ???;*/
1056 xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
1057
1058 #if 0
1059 if (CLIENT_PORT6 == 546) {
1060 /* Use only if standard port is in use */
1061 /* Ignoring error (kernel may lack support for this) */
1062 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1063 sizeof(filter_prog)) >= 0)
1064 log1("attached filter to raw socket fd %d", fd); // log?
1065 }
1066 #endif
1067 return fd;
1068 }
1069
change_listen_mode(int new_mode)1070 static void change_listen_mode(int new_mode)
1071 {
1072 log1("entering listen mode: %s",
1073 new_mode != LISTEN_NONE
1074 ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
1075 : "none"
1076 );
1077
1078 client_data.listen_mode = new_mode;
1079 if (client_data.sockfd >= 0) {
1080 close(client_data.sockfd);
1081 client_data.sockfd = -1;
1082 }
1083 if (new_mode == LISTEN_KERNEL)
1084 client_data.sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_data.interface);
1085 else if (new_mode != LISTEN_NONE)
1086 client_data.sockfd = d6_raw_socket(client_data.ifindex);
1087 /* else LISTEN_NONE: client_data.sockfd stays closed */
1088 }
1089
perform_d6_release(struct in6_addr * server_ipv6,struct in6_addr * our_cur_ipv6)1090 static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
1091 {
1092 change_listen_mode(LISTEN_NONE);
1093
1094 /* send release packet */
1095 if (client_data.state == BOUND
1096 || client_data.state == RENEWING
1097 || client_data.state == REBINDING
1098 || client_data.state == RENEW_REQUESTED
1099 ) {
1100 bb_simple_info_msg("unicasting a release");
1101 client_data.xid = random_xid(); //TODO: can omit?
1102 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */
1103 }
1104 bb_simple_info_msg("entering released state");
1105 /*
1106 * We can be here on: SIGUSR2,
1107 * or on exit (SIGTERM) and -R "release on quit" is specified.
1108 * Users requested to be notified in all cases, even if not in one
1109 * of the states above.
1110 */
1111 d6_run_script_no_option("deconfig");
1112 client_data.state = RELEASED;
1113 }
1114
1115 #if BB_MMU
client_background(void)1116 static void client_background(void)
1117 {
1118 bb_daemonize(0);
1119 logmode &= ~LOGMODE_STDIO;
1120 /* rewrite pidfile, as our pid is different now */
1121 write_pidfile(client_data.pidfile);
1122 }
1123 #endif
1124
1125 //usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
1126 //usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
1127 //usage:#else
1128 //usage:# define IF_UDHCP_VERBOSE(...)
1129 //usage:#endif
1130 //usage:#define udhcpc6_trivial_usage
1131 //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n"
1132 //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..."
1133 //usage:#define udhcpc6_full_usage "\n"
1134 //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
1135 //usage: "\n -p FILE Create pidfile"
1136 //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1137 //usage: "\n -B Request broadcast replies"
1138 //usage: "\n -t N Send up to N discover packets"
1139 //usage: "\n -T SEC Pause between packets (default 3)"
1140 //usage: "\n -A SEC Wait if lease is not obtained (default 20)"
1141 //usage: USE_FOR_MMU(
1142 //usage: "\n -b Background if lease is not obtained"
1143 //usage: )
1144 //usage: "\n -n Exit if lease is not obtained"
1145 //usage: "\n -q Exit after obtaining lease"
1146 //usage: "\n -R Release IP on exit"
1147 //usage: "\n -f Run in foreground"
1148 //usage: "\n -S Log to syslog too"
1149 //usage: IF_FEATURE_UDHCP_PORT(
1150 //usage: "\n -P PORT Use PORT (default 546)"
1151 //usage: )
1152 ////usage: IF_FEATURE_UDHCPC_ARPING(
1153 ////usage: "\n -a Use arping to validate offered address"
1154 ////usage: )
1155 //usage: "\n -l Send 'information request' instead of 'solicit'"
1156 //usage: "\n (used for servers which do not assign IPv6 addresses)"
1157 //usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
1158 //usage: "\n -d Request prefix"
1159 //usage: "\n -o Don't request any options (unless -O is given)"
1160 //usage: "\n -O OPT Request option OPT from server (cumulative)"
1161 //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1162 //usage: "\n Examples of string, numeric, and hex byte opts:"
1163 //usage: "\n -x hostname:bbox - option 12"
1164 //usage: "\n -x lease:3600 - option 51 (lease time)"
1165 //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1166 //usage: "\n -x 14:'\"dumpfile\"' - option 14 (shell-quoted)"
1167 //usage: IF_UDHCP_VERBOSE(
1168 //usage: "\n -v Verbose"
1169 //usage: )
1170 //usage: "\nSignals:"
1171 //usage: "\n USR1 Renew lease"
1172 //usage: "\n USR2 Release lease"
1173
1174 int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
udhcpc6_main(int argc UNUSED_PARAM,char ** argv)1175 int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1176 {
1177 const char *str_r;
1178 IF_FEATURE_UDHCP_PORT(char *str_P;)
1179 uint8_t *clientid_mac_ptr;
1180 llist_t *list_O = NULL;
1181 llist_t *list_x = NULL;
1182 int tryagain_timeout = 20;
1183 int discover_timeout = 3;
1184 int discover_retries = 3;
1185 struct in6_addr srv6_buf;
1186 struct in6_addr ipv6_buf;
1187 struct in6_addr *requested_ipv6;
1188 int packet_num;
1189 int timeout; /* must be signed */
1190 int lease_remaining; /* must be signed */
1191 unsigned opt;
1192 int retval;
1193
1194 setup_common_bufsiz();
1195 /* We want random_xid to be random */
1196 srand(monotonic_us());
1197
1198 /* Default options */
1199 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
1200 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;)
1201 client_data.interface = CONFIG_UDHCPC_DEFAULT_INTERFACE;
1202 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1203 client_data.sockfd = -1;
1204
1205 /* Make sure fd 0,1,2 are open */
1206 /* Set up the signal pipe on fds 3,4 - must be before openlog() */
1207 udhcp_sp_setup();
1208
1209 /* Parse command line */
1210 opt = getopt32long(argv, "^"
1211 /* O,x: list; -T,-t,-A take numeric param */
1212 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld"
1213 USE_FOR_MMU("b")
1214 ///IF_FEATURE_UDHCPC_ARPING("a")
1215 IF_FEATURE_UDHCP_PORT("P:")
1216 "v"
1217 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */
1218 , udhcpc6_longopts
1219 , &client_data.interface, &client_data.pidfile, &str_r /* i,p */
1220 , &client_data.script /* s */
1221 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1222 , &list_O
1223 , &list_x
1224 IF_FEATURE_UDHCP_PORT(, &str_P)
1225 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1226 );
1227 requested_ipv6 = NULL;
1228 option_mask32 |= OPT_r;
1229 if (opt & OPT_l) {
1230 /* for -l, do not require IPv6 assignment from server */
1231 option_mask32 &= ~OPT_r;
1232 } else if (opt & OPT_r) {
1233 /* explicit "-r ARG" given */
1234 if (strcmp(str_r, "no") == 0) {
1235 option_mask32 &= ~OPT_r;
1236 } else {
1237 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1238 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1239 requested_ipv6 = &ipv6_buf;
1240 }
1241 }
1242
1243 #if ENABLE_FEATURE_UDHCP_PORT
1244 if (opt & OPT_P) {
1245 CLIENT_PORT6 = xatou16(str_P);
1246 SERVER_PORT6 = CLIENT_PORT6 + 1;
1247 }
1248 #endif
1249 while (list_O) {
1250 char *optstr = llist_pop(&list_O);
1251 unsigned n = bb_strtou(optstr, NULL, 0);
1252 if (errno || n > 254) {
1253 n = udhcp_option_idx(optstr, d6_option_strings);
1254 n = d6_optflags[n].code;
1255 }
1256 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1257 }
1258 if (!(opt & OPT_o)) {
1259 unsigned i, n;
1260 for (i = 0; (n = d6_optflags[i].code) != 0; i++) {
1261 if (d6_optflags[i].flags & OPTION_REQ) {
1262 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1263 }
1264 }
1265 }
1266 while (list_x) {
1267 char *optstr = xstrdup(llist_pop(&list_x));
1268 udhcp_str2optset(optstr, &client_data.options,
1269 d6_optflags, d6_option_strings,
1270 /*dhcpv6:*/ 1
1271 );
1272 free(optstr);
1273 }
1274
1275 clientid_mac_ptr = NULL;
1276 if (!udhcp_find_option(client_data.options, D6_OPT_CLIENTID, /*dhcpv6:*/ 1)) {
1277 /* not set, set the default client ID */
1278 clientid_mac_ptr = udhcp_insert_new_option(
1279 &client_data.options, D6_OPT_CLIENTID,
1280 2+2 + 6, /*dhcp6:*/ 1);
1281 clientid_mac_ptr += 2+2; /* skip option code, len */
1282 clientid_mac_ptr[1] = 3; /* DUID-LL */
1283 clientid_mac_ptr[3] = 1; /* type: ethernet */
1284 clientid_mac_ptr += 2+2; /* skip DUID-LL, ethernet */
1285 }
1286
1287 if (d6_read_interface(client_data.interface,
1288 &client_data.ifindex,
1289 &client6_data.ll_ip6,
1290 client_data.client_mac)
1291 ) {
1292 return 1;
1293 }
1294
1295 #if !BB_MMU
1296 /* on NOMMU reexec (i.e., background) early */
1297 if (!(opt & OPT_f)) {
1298 bb_daemonize_or_rexec(0 /* flags */, argv);
1299 logmode = LOGMODE_NONE;
1300 }
1301 #endif
1302 if (opt & OPT_S) {
1303 openlog(applet_name, LOG_PID, LOG_DAEMON);
1304 logmode |= LOGMODE_SYSLOG;
1305 }
1306
1307 /* Create pidfile */
1308 write_pidfile(client_data.pidfile);
1309 /* Goes to stdout (unless NOMMU) and possibly syslog */
1310 bb_simple_info_msg("started, v"BB_VER);
1311
1312 client_data.state = INIT_SELECTING;
1313 d6_run_script_no_option("deconfig");
1314 packet_num = 0;
1315 timeout = 0;
1316 lease_remaining = 0;
1317
1318 /* Main event loop. select() waits on signal pipe and possibly
1319 * on sockfd.
1320 * "continue" statements in code below jump to the top of the loop.
1321 */
1322 for (;;) {
1323 struct pollfd pfds[2];
1324 struct d6_packet packet;
1325 uint8_t *packet_end;
1326
1327 //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode);
1328
1329 /* Was opening raw or udp socket here
1330 * if (client_data.listen_mode != LISTEN_NONE && client_data.sockfd < 0),
1331 * but on fast network renew responses return faster
1332 * than we open sockets. Thus this code is moved
1333 * to change_listen_mode(). Thus we open listen socket
1334 * BEFORE we send renew request (see "case BOUND:"). */
1335
1336 udhcp_sp_fd_set(pfds, client_data.sockfd);
1337
1338 retval = 0;
1339 /* If we already timed out, fall through with retval = 0, else... */
1340 if (timeout > 0) {
1341 unsigned diff;
1342
1343 if (timeout > INT_MAX/1000)
1344 timeout = INT_MAX/1000;
1345 log1("waiting %u seconds", timeout);
1346 diff = (unsigned)monotonic_sec();
1347 retval = poll(pfds, 2, timeout * 1000);
1348 diff = (unsigned)monotonic_sec() - diff;
1349 lease_remaining -= diff;
1350 if (lease_remaining < 0)
1351 lease_remaining = 0;
1352 timeout -= diff;
1353 if (timeout < 0)
1354 timeout = 0;
1355
1356 if (retval < 0) {
1357 /* EINTR? A signal was caught, don't panic */
1358 if (errno == EINTR) {
1359 continue;
1360 }
1361 /* Else: an error occured, panic! */
1362 bb_simple_perror_msg_and_die("poll");
1363 }
1364 }
1365
1366 /* If timeout dropped to zero, time to become active:
1367 * resend discover/renew/whatever
1368 */
1369 if (retval == 0) {
1370 /* When running on a bridge, the ifindex may have changed
1371 * (e.g. if member interfaces were added/removed
1372 * or if the status of the bridge changed).
1373 * Refresh ifindex and client_mac:
1374 */
1375 if (d6_read_interface(client_data.interface,
1376 &client_data.ifindex,
1377 &client6_data.ll_ip6,
1378 client_data.client_mac)
1379 ) {
1380 goto ret0; /* iface is gone? */
1381 }
1382
1383 if (clientid_mac_ptr)
1384 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1385
1386 switch (client_data.state) {
1387 case INIT_SELECTING:
1388 if (!discover_retries || packet_num < discover_retries) {
1389 if (packet_num == 0) {
1390 change_listen_mode(LISTEN_RAW);
1391 client_data.xid = random_xid();
1392 }
1393 /* multicast */
1394 if (opt & OPT_l)
1395 send_d6_info_request();
1396 else
1397 send_d6_discover(requested_ipv6);
1398 timeout = discover_timeout;
1399 packet_num++;
1400 continue;
1401 }
1402 leasefail:
1403 change_listen_mode(LISTEN_NONE);
1404 d6_run_script_no_option("leasefail");
1405 #if BB_MMU /* -b is not supported on NOMMU */
1406 if (opt & OPT_b) { /* background if no lease */
1407 bb_simple_info_msg("no lease, forking to background");
1408 client_background();
1409 /* do not background again! */
1410 opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f);
1411 /* ^^^ also disables -n (-b takes priority over -n):
1412 * ifup's default udhcpc options are -R -n,
1413 * and users want to be able to add -b
1414 * (in a config file) to make it background
1415 * _and not exit_.
1416 */
1417 } else
1418 #endif
1419 if (opt & OPT_n) { /* abort if no lease */
1420 bb_simple_info_msg("no lease, failing");
1421 retval = 1;
1422 goto ret;
1423 }
1424 /* Wait before trying again */
1425 timeout = tryagain_timeout;
1426 packet_num = 0;
1427 continue;
1428 case REQUESTING:
1429 if (!discover_retries || packet_num < discover_retries) {
1430 /* send multicast select packet */
1431 send_d6_select();
1432 timeout = discover_timeout;
1433 packet_num++;
1434 continue;
1435 }
1436 /* Timed out, go back to init state.
1437 * "discover...select...discover..." loops
1438 * were seen in the wild. Treat them similarly
1439 * to "no response to discover" case */
1440 client_data.state = INIT_SELECTING;
1441 goto leasefail;
1442 case BOUND:
1443 /* 1/2 lease passed, enter renewing state */
1444 client_data.state = RENEWING;
1445 client_data.first_secs = 0; /* make secs field count from 0 */
1446 got_SIGUSR1:
1447 log1s("entering renew state");
1448 change_listen_mode(LISTEN_KERNEL);
1449 /* fall right through */
1450 case RENEW_REQUESTED: /* in manual (SIGUSR1) renew */
1451 case RENEWING:
1452 if (packet_num == 0) {
1453 /* Send an unicast renew request */
1454 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1455 * a new UDP socket for sending inside send_renew.
1456 * I hazard to guess existing listening socket
1457 * is somehow conflicting with it, but why is it
1458 * not deterministic then?! Strange.
1459 * Anyway, it does recover by eventually failing through
1460 * into INIT_SELECTING state.
1461 */
1462 if (opt & OPT_l)
1463 send_d6_info_request();
1464 else
1465 send_d6_renew(&srv6_buf, requested_ipv6);
1466 timeout = discover_timeout;
1467 packet_num++;
1468 continue;
1469 } /* else: we had sent one packet, but got no reply */
1470 log1s("no response to renew");
1471 if (lease_remaining > 30) {
1472 /* Some lease time remains, try to renew later */
1473 change_listen_mode(LISTEN_NONE);
1474 goto BOUND_for_half_lease;
1475 }
1476 /* Enter rebinding state */
1477 client_data.state = REBINDING;
1478 log1s("entering rebinding state");
1479 /* Switch to bcast receive */
1480 change_listen_mode(LISTEN_RAW);
1481 packet_num = 0;
1482 /* fall right through */
1483 case REBINDING:
1484 /* Lease is *really* about to run out,
1485 * try to find DHCP server using broadcast */
1486 if (lease_remaining > 0 && packet_num < 3) {
1487 if (opt & OPT_l)
1488 send_d6_info_request();
1489 else /* send a broadcast renew request */
1490 send_d6_renew(/*server_ipv6:*/ NULL, requested_ipv6);
1491 timeout = discover_timeout;
1492 packet_num++;
1493 continue;
1494 }
1495 /* Timed out, enter init state */
1496 change_listen_mode(LISTEN_NONE);
1497 bb_simple_info_msg("lease lost, entering init state");
1498 d6_run_script_no_option("deconfig");
1499 client_data.state = INIT_SELECTING;
1500 client_data.first_secs = 0; /* make secs field count from 0 */
1501 timeout = 0;
1502 packet_num = 0;
1503 continue;
1504 /* case RELEASED: */
1505 }
1506 /* RELEASED state (when we got SIGUSR2) ends up here.
1507 * (wait for SIGUSR1 to re-init, or for TERM, etc)
1508 */
1509 timeout = INT_MAX;
1510 continue; /* back to main loop */
1511 } /* if poll timed out */
1512
1513 /* poll() didn't timeout, something happened */
1514
1515 /* Is it a signal? */
1516 switch (udhcp_sp_read()) {
1517 case SIGUSR1:
1518 if (client_data.state <= REQUESTING)
1519 /* Initial negotiations in progress, do not disturb */
1520 break;
1521 if (client_data.state == REBINDING)
1522 /* Do not go back from rebind to renew state */
1523 break;
1524
1525 if (lease_remaining > 30) /* if renew fails, do not go back to BOUND */
1526 lease_remaining = 30;
1527 client_data.first_secs = 0; /* make secs field count from 0 */
1528 packet_num = 0;
1529
1530 switch (client_data.state) {
1531 case BOUND:
1532 case RENEWING:
1533 /* Try to renew/rebind */
1534 change_listen_mode(LISTEN_KERNEL);
1535 client_data.state = RENEW_REQUESTED;
1536 goto got_SIGUSR1;
1537
1538 case RENEW_REQUESTED:
1539 /* Two SIGUSR1 received, start things over */
1540 change_listen_mode(LISTEN_NONE);
1541 d6_run_script_no_option("deconfig");
1542
1543 default:
1544 /* case RELEASED: */
1545 /* Wake from SIGUSR2-induced deconfigured state */
1546 change_listen_mode(LISTEN_NONE);
1547 }
1548 client_data.state = INIT_SELECTING;
1549 /* Kill any timeouts, user wants this to hurry along */
1550 timeout = 0;
1551 continue;
1552 case SIGUSR2:
1553 perform_d6_release(&srv6_buf, requested_ipv6);
1554 /* ^^^ switches to LISTEN_NONE */
1555 timeout = INT_MAX;
1556 continue;
1557 case SIGTERM:
1558 bb_info_msg("received %s", "SIGTERM");
1559 goto ret0;
1560 }
1561
1562 /* Is it a packet? */
1563 if (!pfds[1].revents)
1564 continue; /* no */
1565
1566 {
1567 int len;
1568
1569 /* A packet is ready, read it */
1570 if (client_data.listen_mode == LISTEN_KERNEL)
1571 len = d6_recv_kernel_packet(&srv6_buf, &packet, client_data.sockfd);
1572 else
1573 len = d6_recv_raw_packet(&srv6_buf, &packet, client_data.sockfd);
1574 if (len == -1) {
1575 /* Error is severe, reopen socket */
1576 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
1577 sleep(discover_timeout); /* 3 seconds by default */
1578 change_listen_mode(client_data.listen_mode); /* just close and reopen */
1579 }
1580 if (len < 0)
1581 continue;
1582 packet_end = (uint8_t*)&packet + len;
1583 }
1584
1585 if ((packet.d6_xid32 & htonl(0x00ffffff)) != client_data.xid) {
1586 log1("xid %x (our is %x)%s",
1587 (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)client_data.xid,
1588 ", ignoring packet"
1589 );
1590 continue;
1591 }
1592
1593 switch (client_data.state) {
1594 case INIT_SELECTING:
1595 if (packet.d6_msg_type == D6_MSG_ADVERTISE)
1596 goto type_is_ok;
1597 /* DHCPv6 has "Rapid Commit", when instead of Advertise,
1598 * server sends Reply right away.
1599 * Fall through to check for this case.
1600 */
1601 case REQUESTING:
1602 case RENEWING:
1603 case RENEW_REQUESTED:
1604 case REBINDING:
1605 if (packet.d6_msg_type == D6_MSG_REPLY) {
1606 unsigned start;
1607 uint32_t lease_seconds;
1608 struct d6_option *option;
1609 unsigned address_timeout;
1610 unsigned prefix_timeout;
1611 type_is_ok:
1612 change_listen_mode(LISTEN_NONE);
1613
1614 address_timeout = 0;
1615 prefix_timeout = 0;
1616 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1617 if (option && (option->data[0] | option->data[1]) != 0) {
1618 /* return to init state */
1619 bb_info_msg("received DHCP NAK (%u)", option->data[4]);
1620 d6_run_script(packet.d6_options,
1621 packet_end, "nak");
1622 if (client_data.state != REQUESTING)
1623 d6_run_script_no_option("deconfig");
1624 sleep(3); /* avoid excessive network traffic */
1625 client_data.state = INIT_SELECTING;
1626 client_data.first_secs = 0; /* make secs field count from 0 */
1627 requested_ipv6 = NULL;
1628 timeout = 0;
1629 packet_num = 0;
1630 continue;
1631 }
1632 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1633 if (!option) {
1634 bb_simple_info_msg("no server ID, ignoring packet");
1635 continue;
1636 /* still selecting - this server looks bad */
1637 }
1638 //Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1639 //server_id variable is used solely for creation of proper server_id option
1640 //in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1641 free(client6_data.server_id);
1642 client6_data.server_id = option;
1643 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1644 /* enter requesting state */
1645 change_listen_mode(LISTEN_RAW);
1646 client_data.state = REQUESTING;
1647 timeout = 0;
1648 packet_num = 0;
1649 continue;
1650 }
1651 /* It's a D6_MSG_REPLY */
1652 /*
1653 * RFC 3315 18.1.8. Receipt of Reply Messages
1654 *
1655 * Upon the receipt of a valid Reply message in response to a Solicit
1656 * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or
1657 * Information-request message, the client extracts the configuration
1658 * information contained in the Reply. The client MAY choose to report
1659 * any status code or message from the status code option in the Reply
1660 * message.
1661 *
1662 * The client SHOULD perform duplicate address detection [17] on each of
1663 * the addresses in any IAs it receives in the Reply message before
1664 * using that address for traffic. If any of the addresses are found to
1665 * be in use on the link, the client sends a Decline message to the
1666 * server as described in section 18.1.7.
1667 *
1668 * If the Reply was received in response to a Solicit (with a Rapid
1669 * Commit option), Request, Renew or Rebind message, the client updates
1670 * the information it has recorded about IAs from the IA options
1671 * contained in the Reply message:
1672 *
1673 * - Record T1 and T2 times.
1674 *
1675 * - Add any new addresses in the IA option to the IA as recorded by
1676 * the client.
1677 *
1678 * - Update lifetimes for any addresses in the IA option that the
1679 * client already has recorded in the IA.
1680 *
1681 * - Discard any addresses from the IA, as recorded by the client, that
1682 * have a valid lifetime of 0 in the IA Address option.
1683 *
1684 * - Leave unchanged any information about addresses the client has
1685 * recorded in the IA but that were not included in the IA from the
1686 * server.
1687 *
1688 * Management of the specific configuration information is detailed in
1689 * the definition of each option in section 22.
1690 *
1691 * If the client receives a Reply message with a Status Code containing
1692 * UnspecFail, the server is indicating that it was unable to process
1693 * the message due to an unspecified failure condition. If the client
1694 * retransmits the original message to the same server to retry the
1695 * desired operation, the client MUST limit the rate at which it
1696 * retransmits the message and limit the duration of the time during
1697 * which it retransmits the message.
1698 *
1699 * When the client receives a Reply message with a Status Code option
1700 * with the value UseMulticast, the client records the receipt of the
1701 * message and sends subsequent messages to the server through the
1702 * interface on which the message was received using multicast. The
1703 * client resends the original message using multicast.
1704 *
1705 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1706 * | OPTION_IA_NA | option-len |
1707 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1708 * | IAID (4 octets) |
1709 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1710 * | T1 |
1711 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1712 * | T2 |
1713 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1714 * | |
1715 * . IA_NA-options .
1716 * . .
1717 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1718 *
1719 *
1720 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1721 * | OPTION_IAADDR | option-len |
1722 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1723 * | |
1724 * | IPv6 address |
1725 * | |
1726 * | |
1727 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1728 * | preferred-lifetime |
1729 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1730 * | valid-lifetime |
1731 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1732 * . .
1733 * . IAaddr-options .
1734 * . .
1735 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1736 */
1737 if (option_mask32 & OPT_r) {
1738 struct d6_option *iaaddr;
1739
1740 free(client6_data.ia_na);
1741 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1742 if (!client6_data.ia_na) {
1743 bb_info_msg("no %s option%s", "IA_NA", ", ignoring packet");
1744 continue;
1745 }
1746 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1747 bb_info_msg("%s option is too short:%d bytes",
1748 "IA_NA", client6_data.ia_na->len);
1749 continue;
1750 }
1751 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
1752 client6_data.ia_na->data + client6_data.ia_na->len,
1753 D6_OPT_IAADDR
1754 );
1755 if (!iaaddr) {
1756 bb_info_msg("no %s option%s", "IAADDR", ", ignoring packet");
1757 continue;
1758 }
1759 if (iaaddr->len < (16 + 4 + 4)) {
1760 bb_info_msg("%s option is too short:%d bytes",
1761 "IAADDR", iaaddr->len);
1762 continue;
1763 }
1764 /* Note: the address is sufficiently aligned for cast:
1765 * we _copied_ IA-NA, and copy is always well-aligned.
1766 */
1767 requested_ipv6 = (struct in6_addr*) iaaddr->data;
1768 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1769 lease_seconds = ntohl(lease_seconds);
1770 /// TODO: check for 0 lease time?
1771 bb_info_msg("%s obtained, lease time %u",
1772 "IPv6", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1773 address_timeout = lease_seconds;
1774 }
1775 if (option_mask32 & OPT_d) {
1776 struct d6_option *iaprefix;
1777
1778 free(client6_data.ia_pd);
1779 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1780 if (!client6_data.ia_pd) {
1781 bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet");
1782 continue;
1783 }
1784 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1785 bb_info_msg("%s option is too short:%d bytes",
1786 "IA_PD", client6_data.ia_pd->len);
1787 continue;
1788 }
1789 iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
1790 client6_data.ia_pd->data + client6_data.ia_pd->len,
1791 D6_OPT_IAPREFIX
1792 );
1793 if (!iaprefix) {
1794 bb_info_msg("no %s option%s", "IAPREFIX", ", ignoring packet");
1795 continue;
1796 }
1797 if (iaprefix->len < (4 + 4 + 1 + 16)) {
1798 bb_info_msg("%s option is too short:%d bytes",
1799 "IAPREFIX", iaprefix->len);
1800 continue;
1801 }
1802 move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1803 lease_seconds = ntohl(lease_seconds);
1804 bb_info_msg("%s obtained, lease time %u",
1805 "prefix", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1806 prefix_timeout = lease_seconds;
1807 }
1808 if (!address_timeout)
1809 address_timeout = prefix_timeout;
1810 if (!prefix_timeout)
1811 prefix_timeout = address_timeout;
1812 lease_remaining = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout);
1813 if (lease_remaining < 0) /* signed overflow? */
1814 lease_remaining = INT_MAX;
1815 if (opt & OPT_l) {
1816 /* TODO: request OPTION_INFORMATION_REFRESH_TIME (32)
1817 * and use its value instead of the default 1 day.
1818 */
1819 lease_remaining = 24 * 60 * 60;
1820 }
1821 /* paranoia: must not be too small */
1822 if (lease_remaining < 30)
1823 lease_remaining = 30;
1824
1825 /* enter bound state */
1826 start = monotonic_sec();
1827 d6_run_script(packet.d6_options, packet_end,
1828 (client_data.state == REQUESTING ? "bound" : "renew"));
1829 lease_remaining -= (unsigned)monotonic_sec() - start;
1830 if (lease_remaining < 0)
1831 lease_remaining = 0;
1832 if (opt & OPT_q) { /* quit after lease */
1833 goto ret0;
1834 }
1835 /* future renew failures should not exit (JM) */
1836 opt &= ~OPT_n;
1837 #if BB_MMU /* NOMMU case backgrounded earlier */
1838 if (!(opt & OPT_f)) {
1839 client_background();
1840 /* do not background again! */
1841 opt = ((opt & ~OPT_b) | OPT_f);
1842 }
1843 #endif
1844
1845 BOUND_for_half_lease:
1846 timeout = (unsigned)lease_remaining / 2;
1847 client_data.state = BOUND;
1848 packet_num = 0;
1849 continue; /* back to main loop */
1850 }
1851 continue;
1852 /* case BOUND: - ignore all packets */
1853 /* case RELEASED: - ignore all packets */
1854 }
1855 /* back to main loop */
1856 } /* for (;;) - main loop ends */
1857
1858 ret0:
1859 if (opt & OPT_R) /* release on quit */
1860 perform_d6_release(&srv6_buf, requested_ipv6);
1861 retval = 0;
1862 ret:
1863 /*if (client_data.pidfile) - remove_pidfile has its own check */
1864 remove_pidfile(client_data.pidfile);
1865 return retval;
1866 }
1867