aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-01-16 21:39:14 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-01-16 21:39:14 +0100
commitef5207f093216fe6cf6f1bc7a098bcab5f435a98 (patch)
tree320594dcbcdde3ec087cb5f146e96845c376d540
parent1e8d79ba12d715d4375856418173c5375fbfce40 (diff)
downloadbusybox-w32-ef5207f093216fe6cf6f1bc7a098bcab5f435a98.tar.gz
busybox-w32-ef5207f093216fe6cf6f1bc7a098bcab5f435a98.tar.bz2
busybox-w32-ef5207f093216fe6cf6f1bc7a098bcab5f435a98.zip
udhcpc6: add support of prefix delegation
Based on patch by DannyAAM <danny@saru.moe> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/udhcp/d6_common.h1
-rw-r--r--networking/udhcp/d6_dhcpc.c122
2 files changed, 101 insertions, 22 deletions
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index 310550371..e9c0397ae 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -133,6 +133,7 @@ struct d6_option {
133struct client6_data_t { 133struct client6_data_t {
134 struct d6_option *server_id; 134 struct d6_option *server_id;
135 struct d6_option *ia_na; 135 struct d6_option *ia_na;
136 struct d6_option *ia_pd;
136 char **env_ptr; 137 char **env_ptr;
137 unsigned env_idx; 138 unsigned env_idx;
138 /* link-local IPv6 address */ 139 /* link-local IPv6 address */
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 57ad968cd..cfb2dcc5a 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -96,6 +96,7 @@ static const char udhcpc6_longopts[] ALIGN1 =
96 "quit\0" No_argument "q" 96 "quit\0" No_argument "q"
97 "release\0" No_argument "R" 97 "release\0" No_argument "R"
98 "request\0" Required_argument "r" 98 "request\0" Required_argument "r"
99 "requestprefix\0" No_argument "d"
99 "script\0" Required_argument "s" 100 "script\0" Required_argument "s"
100 "timeout\0" Required_argument "T" 101 "timeout\0" Required_argument "T"
101 "retries\0" Required_argument "t" 102 "retries\0" Required_argument "t"
@@ -128,8 +129,9 @@ enum {
128 OPT_o = 1 << 12, 129 OPT_o = 1 << 12,
129 OPT_x = 1 << 13, 130 OPT_x = 1 << 13,
130 OPT_f = 1 << 14, 131 OPT_f = 1 << 14,
132 OPT_d = 1 << 15,
131/* The rest has variable bit positions, need to be clever */ 133/* The rest has variable bit positions, need to be clever */
132 OPTBIT_f = 14, 134 OPTBIT_d = 15,
133 USE_FOR_MMU( OPTBIT_b,) 135 USE_FOR_MMU( OPTBIT_b,)
134 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 136 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
135 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 137 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -561,18 +563,33 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip
561 563
562 /* Create new IA_NA, optionally with included IAADDR with requested IP */ 564 /* Create new IA_NA, optionally with included IAADDR with requested IP */
563 free(client6_data.ia_na); 565 free(client6_data.ia_na);
564 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; 566 client6_data.ia_na = NULL;
565 client6_data.ia_na = xzalloc(len); 567 if (option_mask32 & OPT_r) {
566 client6_data.ia_na->code = D6_OPT_IA_NA; 568 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
567 client6_data.ia_na->len = len - 4; 569 client6_data.ia_na = xzalloc(len);
568 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ 570 client6_data.ia_na->code = D6_OPT_IA_NA;
569 if (requested_ipv6) { 571 client6_data.ia_na->len = len - 4;
570 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); 572 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
571 iaaddr->code = D6_OPT_IAADDR; 573 if (requested_ipv6) {
572 iaaddr->len = 16+4+4; 574 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
573 memcpy(iaaddr->data, requested_ipv6, 16); 575 iaaddr->code = D6_OPT_IAADDR;
576 iaaddr->len = 16+4+4;
577 memcpy(iaaddr->data, requested_ipv6, 16);
578 }
579 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
580 }
581
582 /* IA_PD */
583 free(client6_data.ia_pd);
584 client6_data.ia_pd = NULL;
585 if (option_mask32 & OPT_d) {
586 len = 2+2+4+4+4;
587 client6_data.ia_pd = xzalloc(len);
588 client6_data.ia_pd->code = D6_OPT_IA_PD;
589 client6_data.ia_pd->len = len - 4;
590 *(uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */
591 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
574 } 592 }
575 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
576 593
577 /* Add options: 594 /* Add options:
578 * "param req" option according to -O, options specified with -x 595 * "param req" option according to -O, options specified with -x
@@ -625,7 +642,11 @@ static NOINLINE int send_d6_select(uint32_t xid)
625 /* server id */ 642 /* server id */
626 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 643 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
627 /* IA NA (contains requested IP) */ 644 /* IA NA (contains requested IP) */
628 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 645 if (client6_data.ia_na)
646 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
647 /* IA PD */
648 if (client6_data.ia_pd)
649 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
629 650
630 /* Add options: 651 /* Add options:
631 * "param req" option according to -O, options specified with -x 652 * "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
694 /* server id */ 715 /* server id */
695 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 716 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
696 /* IA NA (contains requested IP) */ 717 /* IA NA (contains requested IP) */
697 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 718 if (client6_data.ia_na)
719 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
720 /* IA PD */
721 if (client6_data.ia_pd)
722 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
698 723
699 /* Add options: 724 /* Add options:
700 * "param req" option according to -O, options specified with -x 725 * "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
725 /* server id */ 750 /* server id */
726 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 751 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
727 /* IA NA (contains our current IP) */ 752 /* IA NA (contains our current IP) */
728 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 753 if (client6_data.ia_na)
754 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
755 /* IA PD */
756 if (client6_data.ia_pd)
757 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
729 758
730 bb_error_msg("sending %s", "release"); 759 bb_error_msg("sending %s", "release");
731 return d6_send_kernel_packet( 760 return d6_send_kernel_packet(
@@ -1028,7 +1057,8 @@ static void client_background(void)
1028////usage: ) 1057////usage: )
1029//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" 1058//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
1030//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" 1059//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
1031//usage: "\n -r,--request IP Request this IP address" 1060//usage: "\n -r,--request IP Request this IP address ('no' to not request any IP)"
1061//usage: "\n -d,--requestprefix Request prefix"
1032//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1062//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1033//usage: "\n Examples of string, numeric, and hex byte opts:" 1063//usage: "\n Examples of string, numeric, and hex byte opts:"
1034//usage: "\n -x hostname:bbox - option 12" 1064//usage: "\n -x hostname:bbox - option 12"
@@ -1062,7 +1092,8 @@ static void client_background(void)
1062////usage: ) 1092////usage: )
1063//usage: "\n -O OPT Request option OPT from server (cumulative)" 1093//usage: "\n -O OPT Request option OPT from server (cumulative)"
1064//usage: "\n -o Don't request any options (unless -O is given)" 1094//usage: "\n -o Don't request any options (unless -O is given)"
1065//usage: "\n -r IP Request this IP address" 1095//usage: "\n -r IP Request this IP address ('no' to not request any IP)"
1096//usage: "\n -d Request prefix"
1066//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1097//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1067//usage: "\n Examples of string, numeric, and hex byte opts:" 1098//usage: "\n Examples of string, numeric, and hex byte opts:"
1068//usage: "\n -x hostname:bbox - option 12" 1099//usage: "\n -x hostname:bbox - option 12"
@@ -1109,7 +1140,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1109 /* Parse command line */ 1140 /* Parse command line */
1110 opt = getopt32long(argv, "^" 1141 opt = getopt32long(argv, "^"
1111 /* O,x: list; -T,-t,-A take numeric param */ 1142 /* O,x: list; -T,-t,-A take numeric param */
1112 "i:np:qRr:s:T:+t:+SA:+O:*ox:*f" 1143 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd"
1113 USE_FOR_MMU("b") 1144 USE_FOR_MMU("b")
1114 ///IF_FEATURE_UDHCPC_ARPING("a") 1145 ///IF_FEATURE_UDHCPC_ARPING("a")
1115 IF_FEATURE_UDHCP_PORT("P:") 1146 IF_FEATURE_UDHCP_PORT("P:")
@@ -1125,10 +1156,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1125 IF_UDHCP_VERBOSE(, &dhcp_verbose) 1156 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1126 ); 1157 );
1127 requested_ipv6 = NULL; 1158 requested_ipv6 = NULL;
1159 option_mask32 |= OPT_r;
1128 if (opt & OPT_r) { 1160 if (opt & OPT_r) {
1129 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) 1161 if (strcmp(str_r, "no") == 0) {
1130 bb_error_msg_and_die("bad IPv6 address '%s'", str_r); 1162 option_mask32 -= OPT_r;
1131 requested_ipv6 = &ipv6_buf; 1163 } else {
1164 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1165 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1166 requested_ipv6 = &ipv6_buf;
1167 }
1132 } 1168 }
1133#if ENABLE_FEATURE_UDHCP_PORT 1169#if ENABLE_FEATURE_UDHCP_PORT
1134 if (opt & OPT_P) { 1170 if (opt & OPT_P) {
@@ -1466,6 +1502,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1466 if (packet.d6_msg_type == D6_MSG_REPLY) { 1502 if (packet.d6_msg_type == D6_MSG_REPLY) {
1467 uint32_t lease_seconds; 1503 uint32_t lease_seconds;
1468 struct d6_option *option, *iaaddr; 1504 struct d6_option *option, *iaaddr;
1505 int address_timeout = 0;
1506 int prefix_timeout = 0;
1469 type_is_ok: 1507 type_is_ok:
1470 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); 1508 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1471 if (option && (option->data[0] | option->data[1]) != 0) { 1509 if (option && (option->data[0] | option->data[1]) != 0) {
@@ -1589,6 +1627,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1589 * . . 1627 * . .
1590 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1628 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1591 */ 1629 */
1630 if (option_mask32 & OPT_r) {
1592 free(client6_data.ia_na); 1631 free(client6_data.ia_na);
1593 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); 1632 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1594 if (!client6_data.ia_na) { 1633 if (!client6_data.ia_na) {
@@ -1624,9 +1663,48 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1624 if (lease_seconds > 0x7fffffff / 1000) 1663 if (lease_seconds > 0x7fffffff / 1000)
1625 lease_seconds = 0x7fffffff / 1000; 1664 lease_seconds = 0x7fffffff / 1000;
1626 /* enter bound state */ 1665 /* enter bound state */
1627 timeout = lease_seconds / 2; 1666 address_timeout = lease_seconds / 2;
1628 bb_error_msg("lease obtained, lease time %u", 1667 bb_error_msg("lease obtained, lease time %u",
1629 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); 1668 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1669 }
1670 if (option_mask32 & OPT_d) {
1671 struct d6_option *iaprefix;
1672
1673 free(client6_data.ia_pd);
1674 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1675 if (!client6_data.ia_pd) {
1676 bb_error_msg("no %s option, ignoring packet", "IA_PD");
1677 continue;
1678 }
1679 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1680 bb_error_msg("IA_PD option is too short:%d bytes", client6_data.ia_pd->len);
1681 continue;
1682 }
1683 iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
1684 client6_data.ia_pd->data + client6_data.ia_pd->len,
1685 D6_OPT_IAPREFIX
1686 );
1687 if (!iaprefix) {
1688 bb_error_msg("no %s option, ignoring packet", "IAPREFIX");
1689 continue;
1690 }
1691 if (iaprefix->len < (4 + 4 + 1 + 16)) {
1692 bb_error_msg("IAPREFIX option is too short:%d bytes", iaprefix->len);
1693 continue;
1694 }
1695 move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1696 lease_seconds = ntohl(lease_seconds);
1697 /* paranoia: must not be too small and not prone to overflows */
1698 if (lease_seconds < 0x10)
1699 lease_seconds = 0x10;
1700 if (lease_seconds > 0x7fffffff / 1000)
1701 lease_seconds = 0x7fffffff / 1000;
1702 /* enter bound state */
1703 prefix_timeout = lease_seconds / 2;
1704 bb_error_msg("prefix obtained, lease time %u",
1705 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1706 }
1707 timeout = address_timeout > prefix_timeout ? prefix_timeout : address_timeout;
1630 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1708 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1631 1709
1632 state = BOUND; 1710 state = BOUND;