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