udhcpc6: add support of prefix delegation
Based on patch by DannyAAM <danny@saru.moe> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		@@ -133,6 +133,7 @@ struct d6_option {
 | 
			
		||||
struct client6_data_t {
 | 
			
		||||
	struct d6_option *server_id;
 | 
			
		||||
	struct d6_option *ia_na;
 | 
			
		||||
	struct d6_option *ia_pd;
 | 
			
		||||
	char **env_ptr;
 | 
			
		||||
	unsigned env_idx;
 | 
			
		||||
	/* link-local IPv6 address */
 | 
			
		||||
 
 | 
			
		||||
@@ -96,6 +96,7 @@ static const char udhcpc6_longopts[] ALIGN1 =
 | 
			
		||||
	"quit\0"           No_argument       "q"
 | 
			
		||||
	"release\0"        No_argument       "R"
 | 
			
		||||
	"request\0"        Required_argument "r"
 | 
			
		||||
	"requestprefix\0"  No_argument       "d"
 | 
			
		||||
	"script\0"         Required_argument "s"
 | 
			
		||||
	"timeout\0"        Required_argument "T"
 | 
			
		||||
	"retries\0"        Required_argument "t"
 | 
			
		||||
@@ -128,8 +129,9 @@ enum {
 | 
			
		||||
	OPT_o = 1 << 12,
 | 
			
		||||
	OPT_x = 1 << 13,
 | 
			
		||||
	OPT_f = 1 << 14,
 | 
			
		||||
	OPT_d = 1 << 15,
 | 
			
		||||
/* The rest has variable bit positions, need to be clever */
 | 
			
		||||
	OPTBIT_f = 14,
 | 
			
		||||
	OPTBIT_d = 15,
 | 
			
		||||
	USE_FOR_MMU(             OPTBIT_b,)
 | 
			
		||||
	///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
 | 
			
		||||
	IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
 | 
			
		||||
@@ -561,18 +563,33 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip
 | 
			
		||||
 | 
			
		||||
	/* Create new IA_NA, optionally with included IAADDR with requested IP */
 | 
			
		||||
	free(client6_data.ia_na);
 | 
			
		||||
	len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
 | 
			
		||||
	client6_data.ia_na = xzalloc(len);
 | 
			
		||||
	client6_data.ia_na->code = D6_OPT_IA_NA;
 | 
			
		||||
	client6_data.ia_na->len = len - 4;
 | 
			
		||||
	*(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
 | 
			
		||||
	if (requested_ipv6) {
 | 
			
		||||
		struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
 | 
			
		||||
		iaaddr->code = D6_OPT_IAADDR;
 | 
			
		||||
		iaaddr->len = 16+4+4;
 | 
			
		||||
		memcpy(iaaddr->data, requested_ipv6, 16);
 | 
			
		||||
	client6_data.ia_na = NULL;
 | 
			
		||||
	if (option_mask32 & OPT_r) {
 | 
			
		||||
		len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
 | 
			
		||||
		client6_data.ia_na = xzalloc(len);
 | 
			
		||||
		client6_data.ia_na->code = D6_OPT_IA_NA;
 | 
			
		||||
		client6_data.ia_na->len = len - 4;
 | 
			
		||||
		*(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
 | 
			
		||||
		if (requested_ipv6) {
 | 
			
		||||
			struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
 | 
			
		||||
			iaaddr->code = D6_OPT_IAADDR;
 | 
			
		||||
			iaaddr->len = 16+4+4;
 | 
			
		||||
			memcpy(iaaddr->data, requested_ipv6, 16);
 | 
			
		||||
		}
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* IA_PD */
 | 
			
		||||
	free(client6_data.ia_pd);
 | 
			
		||||
	client6_data.ia_pd = NULL;
 | 
			
		||||
	if (option_mask32 & OPT_d) {
 | 
			
		||||
		len = 2+2+4+4+4;
 | 
			
		||||
		client6_data.ia_pd = xzalloc(len);
 | 
			
		||||
		client6_data.ia_pd->code = D6_OPT_IA_PD;
 | 
			
		||||
		client6_data.ia_pd->len = len - 4;
 | 
			
		||||
		*(uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
 | 
			
		||||
	}
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
 | 
			
		||||
 | 
			
		||||
	/* Add options:
 | 
			
		||||
	 * "param req" option according to -O, options specified with -x
 | 
			
		||||
@@ -625,7 +642,11 @@ static NOINLINE int send_d6_select(uint32_t xid)
 | 
			
		||||
	/* server id */
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
 | 
			
		||||
	/* IA NA (contains requested IP) */
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 | 
			
		||||
	if (client6_data.ia_na)
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 | 
			
		||||
	/* IA PD */
 | 
			
		||||
	if (client6_data.ia_pd)
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
 | 
			
		||||
 | 
			
		||||
	/* Add options:
 | 
			
		||||
	 * "param req" option according to -O, options specified with -x
 | 
			
		||||
@@ -694,7 +715,11 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
 | 
			
		||||
	/* server id */
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
 | 
			
		||||
	/* IA NA (contains requested IP) */
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 | 
			
		||||
	if (client6_data.ia_na)
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 | 
			
		||||
	/* IA PD */
 | 
			
		||||
	if (client6_data.ia_pd)
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
 | 
			
		||||
 | 
			
		||||
	/* Add options:
 | 
			
		||||
	 * "param req" option according to -O, options specified with -x
 | 
			
		||||
@@ -725,7 +750,11 @@ static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cu
 | 
			
		||||
	/* server id */
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
 | 
			
		||||
	/* IA NA (contains our current IP) */
 | 
			
		||||
	opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 | 
			
		||||
	if (client6_data.ia_na)
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 | 
			
		||||
	/* IA PD */
 | 
			
		||||
	if (client6_data.ia_pd)
 | 
			
		||||
		opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
 | 
			
		||||
 | 
			
		||||
	bb_error_msg("sending %s", "release");
 | 
			
		||||
	return d6_send_kernel_packet(
 | 
			
		||||
@@ -1028,7 +1057,8 @@ static void client_background(void)
 | 
			
		||||
////usage:	)
 | 
			
		||||
//usage:     "\n	-O,--request-option OPT	Request option OPT from server (cumulative)"
 | 
			
		||||
//usage:     "\n	-o,--no-default-options	Don't request any options (unless -O is given)"
 | 
			
		||||
//usage:     "\n	-r,--request IP		Request this IP address"
 | 
			
		||||
//usage:     "\n	-r,--request IP		Request this IP address ('no' to not request any IP)"
 | 
			
		||||
//usage:     "\n	-d,--requestprefix	Request prefix"
 | 
			
		||||
//usage:     "\n	-x OPT:VAL		Include option OPT in sent packets (cumulative)"
 | 
			
		||||
//usage:     "\n				Examples of string, numeric, and hex byte opts:"
 | 
			
		||||
//usage:     "\n				-x hostname:bbox - option 12"
 | 
			
		||||
@@ -1062,7 +1092,8 @@ static void client_background(void)
 | 
			
		||||
////usage:	)
 | 
			
		||||
//usage:     "\n	-O OPT		Request option OPT from server (cumulative)"
 | 
			
		||||
//usage:     "\n	-o		Don't request any options (unless -O is given)"
 | 
			
		||||
//usage:     "\n	-r IP		Request this IP address"
 | 
			
		||||
//usage:     "\n	-r IP		Request this IP address ('no' to not request any IP)"
 | 
			
		||||
//usage:     "\n	-d		Request prefix"
 | 
			
		||||
//usage:     "\n	-x OPT:VAL	Include option OPT in sent packets (cumulative)"
 | 
			
		||||
//usage:     "\n			Examples of string, numeric, and hex byte opts:"
 | 
			
		||||
//usage:     "\n			-x hostname:bbox - option 12"
 | 
			
		||||
@@ -1109,7 +1140,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
	/* Parse command line */
 | 
			
		||||
	opt = getopt32long(argv, "^"
 | 
			
		||||
		/* O,x: list; -T,-t,-A take numeric param */
 | 
			
		||||
		"i:np:qRr:s:T:+t:+SA:+O:*ox:*f"
 | 
			
		||||
		"i:np:qRr:s:T:+t:+SA:+O:*ox:*fd"
 | 
			
		||||
		USE_FOR_MMU("b")
 | 
			
		||||
		///IF_FEATURE_UDHCPC_ARPING("a")
 | 
			
		||||
		IF_FEATURE_UDHCP_PORT("P:")
 | 
			
		||||
@@ -1125,10 +1156,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
		IF_UDHCP_VERBOSE(, &dhcp_verbose)
 | 
			
		||||
	);
 | 
			
		||||
	requested_ipv6 = NULL;
 | 
			
		||||
	option_mask32 |= OPT_r;
 | 
			
		||||
	if (opt & OPT_r) {
 | 
			
		||||
		if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
 | 
			
		||||
			bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
 | 
			
		||||
		requested_ipv6 = &ipv6_buf;
 | 
			
		||||
		if (strcmp(str_r, "no") == 0) {
 | 
			
		||||
			option_mask32 -= OPT_r;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
 | 
			
		||||
				bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
 | 
			
		||||
			requested_ipv6 = &ipv6_buf;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#if ENABLE_FEATURE_UDHCP_PORT
 | 
			
		||||
	if (opt & OPT_P) {
 | 
			
		||||
@@ -1466,6 +1502,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
			if (packet.d6_msg_type == D6_MSG_REPLY) {
 | 
			
		||||
				uint32_t lease_seconds;
 | 
			
		||||
				struct d6_option *option, *iaaddr;
 | 
			
		||||
				int address_timeout = 0;
 | 
			
		||||
				int prefix_timeout = 0;
 | 
			
		||||
 type_is_ok:
 | 
			
		||||
				option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
 | 
			
		||||
				if (option && (option->data[0] | option->data[1]) != 0) {
 | 
			
		||||
@@ -1589,6 +1627,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
 * .                                                               .
 | 
			
		||||
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | 
			
		||||
 */
 | 
			
		||||
				if (option_mask32 & OPT_r) {
 | 
			
		||||
					free(client6_data.ia_na);
 | 
			
		||||
					client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
 | 
			
		||||
					if (!client6_data.ia_na) {
 | 
			
		||||
@@ -1624,9 +1663,48 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
					if (lease_seconds > 0x7fffffff / 1000)
 | 
			
		||||
						lease_seconds = 0x7fffffff / 1000;
 | 
			
		||||
					/* enter bound state */
 | 
			
		||||
					timeout = lease_seconds / 2;
 | 
			
		||||
					address_timeout = lease_seconds / 2;
 | 
			
		||||
					bb_error_msg("lease obtained, lease time %u",
 | 
			
		||||
						/*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
 | 
			
		||||
				}
 | 
			
		||||
				if (option_mask32 & OPT_d) {
 | 
			
		||||
					struct d6_option *iaprefix;
 | 
			
		||||
 | 
			
		||||
					free(client6_data.ia_pd);
 | 
			
		||||
					client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
 | 
			
		||||
					if (!client6_data.ia_pd) {
 | 
			
		||||
						bb_error_msg("no %s option, ignoring packet", "IA_PD");
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
					if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
 | 
			
		||||
						bb_error_msg("IA_PD option is too short:%d bytes", client6_data.ia_pd->len);
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
					iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
 | 
			
		||||
							client6_data.ia_pd->data + client6_data.ia_pd->len,
 | 
			
		||||
							D6_OPT_IAPREFIX
 | 
			
		||||
					);
 | 
			
		||||
					if (!iaprefix) {
 | 
			
		||||
						bb_error_msg("no %s option, ignoring packet", "IAPREFIX");
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
					if (iaprefix->len < (4 + 4 + 1 + 16)) {
 | 
			
		||||
						bb_error_msg("IAPREFIX option is too short:%d bytes", iaprefix->len);
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
					move_from_unaligned32(lease_seconds, iaprefix->data + 4);
 | 
			
		||||
					lease_seconds = ntohl(lease_seconds);
 | 
			
		||||
					/* paranoia: must not be too small and not prone to overflows */
 | 
			
		||||
					if (lease_seconds < 0x10)
 | 
			
		||||
						lease_seconds = 0x10;
 | 
			
		||||
					if (lease_seconds > 0x7fffffff / 1000)
 | 
			
		||||
						lease_seconds = 0x7fffffff / 1000;
 | 
			
		||||
					/* enter bound state */
 | 
			
		||||
					prefix_timeout = lease_seconds / 2;
 | 
			
		||||
					bb_error_msg("prefix obtained, lease time %u",
 | 
			
		||||
						/*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
 | 
			
		||||
				}
 | 
			
		||||
				timeout = address_timeout > prefix_timeout ? prefix_timeout : address_timeout;
 | 
			
		||||
				d6_run_script(&packet, state == REQUESTING ? "bound" : "renew");
 | 
			
		||||
 | 
			
		||||
				state = BOUND;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user