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:
parent
1e8d79ba12
commit
ef5207f093
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user