diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-16 21:39:14 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-16 21:39:14 +0100 |
commit | ef5207f093216fe6cf6f1bc7a098bcab5f435a98 (patch) | |
tree | 320594dcbcdde3ec087cb5f146e96845c376d540 | |
parent | 1e8d79ba12d715d4375856418173c5375fbfce40 (diff) | |
download | busybox-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.h | 1 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 122 |
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 { | |||
133 | struct client6_data_t { | 133 | struct 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; |