udhcpc6: improvements
Several small improvements to udhcpc6. - Remove usage text for the nonexistent -B option. - Fix a segfault when renewing an IA_PD lease without IA_NA (which means the client hasn't been assigned an ip, so we cannot locally bind to it). - Fix NAK management: check the option length, and print the status code and status message - Add a -m option to always send renew requests as multicast. These last two changes are useful to deal with hopelessly broken DHCPv6 servers such as the one from the Orange Livebox (one of the main French ISPs) which I'm currently having the displeasure to have to talk to, hence the patch. function old new delta static.send_d6_renew - 126 +126 .rodata 105598 105649 +51 udhcpc6_main 2607 2650 +43 packed_usage 34933 34953 +20 d6_send_kernel_packet_from_client_data_ifindex 266 282 +16 send_d6_renew 174 - -174 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 4/0 up/down: 256/-174) Total: 82 bytes Signed-off-by: Laurent Bercot <ska-dietlibc@skarnet.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
14f57f5357
commit
ef21820dc9
2 changed files with 72 additions and 32 deletions
|
@ -148,10 +148,11 @@ enum {
|
|||
OPT_o = 1 << 12,
|
||||
OPT_x = 1 << 13,
|
||||
OPT_f = 1 << 14,
|
||||
OPT_l = 1 << 15,
|
||||
OPT_d = 1 << 16,
|
||||
OPT_m = 1 << 15,
|
||||
OPT_l = 1 << 16,
|
||||
OPT_d = 1 << 17,
|
||||
/* The rest has variable bit positions, need to be clever */
|
||||
OPTBIT_d = 16,
|
||||
OPTBIT_d = 17,
|
||||
USE_FOR_MMU( OPTBIT_b,)
|
||||
///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
|
||||
IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
|
||||
|
@ -268,6 +269,23 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end)
|
|||
//case D6_OPT_SERVERID:
|
||||
case D6_OPT_IA_NA:
|
||||
case D6_OPT_IA_PD:
|
||||
/* 0 1 2 3
|
||||
* 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
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | OPTION_IA_PD | option-length |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | IAID (4 octets) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | T1 |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | T2 |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* . .
|
||||
* . IA_PD-options .
|
||||
* . .
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
/* recurse to handle "IA_PD-options" field */
|
||||
option_to_env(option + 16, option + 4 + option[3]);
|
||||
break;
|
||||
//case D6_OPT_IA_TA:
|
||||
|
@ -1131,12 +1149,11 @@ static void client_background(void)
|
|||
//usage:#endif
|
||||
//usage:#define udhcpc6_trivial_usage
|
||||
//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n"
|
||||
//usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..."
|
||||
//usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-mldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..."
|
||||
//usage:#define udhcpc6_full_usage "\n"
|
||||
//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
|
||||
//usage: "\n -p FILE Create pidfile"
|
||||
//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")"
|
||||
//usage: "\n -B Request broadcast replies"
|
||||
//usage: "\n -t N Send up to N discover packets"
|
||||
//usage: "\n -T SEC Pause between packets (default 3)"
|
||||
//usage: "\n -A SEC Wait if lease is not obtained (default 20)"
|
||||
|
@ -1154,6 +1171,7 @@ static void client_background(void)
|
|||
////usage: IF_FEATURE_UDHCPC_ARPING(
|
||||
////usage: "\n -a Use arping to validate offered address"
|
||||
////usage: )
|
||||
//usage: "\n -m Send multicast renew requests rather than unicast ones"
|
||||
//usage: "\n -l Send 'information request' instead of 'solicit'"
|
||||
//usage: "\n (used for servers which do not assign IPv6 addresses)"
|
||||
//usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
|
||||
|
@ -1211,7 +1229,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:*fld"
|
||||
"i:np:qRr:s:T:+t:+SA:+O:*ox:*fmld"
|
||||
USE_FOR_MMU("b")
|
||||
///IF_FEATURE_UDHCPC_ARPING("a")
|
||||
IF_FEATURE_UDHCP_PORT("P:")
|
||||
|
@ -1464,7 +1482,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
|
|||
if (opt & OPT_l)
|
||||
send_d6_info_request();
|
||||
else
|
||||
send_d6_renew(&srv6_buf, requested_ipv6);
|
||||
send_d6_renew(OPT_m ? NULL : &srv6_buf, requested_ipv6);
|
||||
timeout = discover_timeout;
|
||||
packet_num++;
|
||||
continue;
|
||||
|
@ -1617,8 +1635,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
|
|||
address_timeout = 0;
|
||||
prefix_timeout = 0;
|
||||
option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
|
||||
if (option && (option->data[0] | option->data[1]) != 0) {
|
||||
///FIXME:
|
||||
if (option) {
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | OPTION_STATUS_CODE | option-len |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
@ -1626,21 +1643,28 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
|
|||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
||||
// . status-message .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// so why do we think it's NAK if data[0] is zero but data[1] is not? That's wrong...
|
||||
// we should also check that option->len is ok (i.e. not 0), right?
|
||||
/* return to init state */
|
||||
bb_info_msg("received DHCP NAK (%u)", option->data[4]);
|
||||
d6_run_script(packet.d6_options,
|
||||
packet_end, "nak");
|
||||
if (client_data.state != REQUESTING)
|
||||
d6_run_script_no_option("deconfig");
|
||||
sleep(3); /* avoid excessive network traffic */
|
||||
client_data.state = INIT_SELECTING;
|
||||
client_data.first_secs = 0; /* make secs field count from 0 */
|
||||
requested_ipv6 = NULL;
|
||||
timeout = 0;
|
||||
packet_num = 0;
|
||||
continue;
|
||||
unsigned len, status;
|
||||
len = ((unsigned)option->len_hi << 8) + option->len;
|
||||
if (len < 2) {
|
||||
bb_simple_error_msg("invalid OPTION_STATUS_CODE, ignoring packet");
|
||||
continue;
|
||||
}
|
||||
status = ((unsigned)option->data[0] << 8) + option->data[1];
|
||||
if (status != 0) {
|
||||
//TODO: handle status == 5 (UseMulticast)?
|
||||
/* return to init state */
|
||||
bb_info_msg("received DHCP NAK: %u '%.*s'", status, len - 2, option->data + 2);
|
||||
d6_run_script(packet.d6_options, packet_end, "nak");
|
||||
if (client_data.state != REQUESTING)
|
||||
d6_run_script_no_option("deconfig");
|
||||
sleep(3); /* avoid excessive network traffic */
|
||||
client_data.state = INIT_SELECTING;
|
||||
client_data.first_secs = 0; /* make secs field count from 0 */
|
||||
requested_ipv6 = NULL;
|
||||
timeout = 0;
|
||||
packet_num = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
|
||||
if (!option) {
|
||||
|
@ -1661,7 +1685,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
|
|||
packet_num = 0;
|
||||
continue;
|
||||
}
|
||||
/* It's a D6_MSG_REPLY */
|
||||
/*
|
||||
* RFC 3315 18.1.8. Receipt of Reply Messages
|
||||
*
|
||||
|
@ -1790,6 +1813,21 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
|
|||
|
||||
free(client6_data.ia_pd);
|
||||
client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
|
||||
// 0 1 2 3
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | OPTION_IA_PD | option-length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IAID (4 octets) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | T1 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | T2 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . .
|
||||
// . IA_PD-options .
|
||||
// . .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
if (!client6_data.ia_pd) {
|
||||
bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet");
|
||||
continue;
|
||||
|
|
|
@ -153,13 +153,15 @@ int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex(
|
|||
}
|
||||
setsockopt_reuseaddr(fd);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = htons(source_port);
|
||||
sa.sin6_addr = *src_ipv6; /* struct copy */
|
||||
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
msg = "bind(%s)";
|
||||
goto ret_close;
|
||||
if (src_ipv6) {
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = htons(source_port);
|
||||
sa.sin6_addr = *src_ipv6; /* struct copy */
|
||||
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
msg = "bind(%s)";
|
||||
goto ret_close;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue