diff options
author | Denys Vlasenko | 2021-06-02 13:50:26 +0200 |
---|---|---|
committer | Denys Vlasenko | 2021-06-02 14:07:26 +0200 |
commit | 265fcddd08f22c99a2a419a1537c18f4d6d43e9f (patch) | |
tree | e1cfb7a18bb0887b95700a7417f88ff90883bfa3 | |
parent | 9659a8db1dd28bdf8659fdae5d097b6f48bd2736 (diff) | |
download | busybox-265fcddd08f22c99a2a419a1537c18f4d6d43e9f.zip busybox-265fcddd08f22c99a2a419a1537c18f4d6d43e9f.tar.gz |
udhcpc: include client-id option in DECLINEs, even if it's a custom -x 61:HEX option
client_data.vendorclass, .hostname and .fqdn probably need the same treatment:
just insert them into the list of -x opts, get rid of
if (client_data.vendorclass)
udhcp_add_binary_option(packet, client_data.vendorclass);
if (client_data.hostname)
udhcp_add_binary_option(packet, client_data.hostname);
if (client_data.fqdn)
udhcp_add_binary_option(packet, client_data.fqdn);
function old new delta
udhcp_insert_new_option - 166 +166
perform_release 171 207 +36
perform_d6_release 227 259 +32
udhcpc6_main 2558 2580 +22
init_d6_packet 103 84 -19
udhcpc_main 2585 2564 -21
attach_option 397 253 -144
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/3 up/down: 256/-184) Total: 72 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/udhcp/common.c | 63 | ||||
-rw-r--r-- | networking/udhcp/common.h | 11 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 58 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 56 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.h | 4 |
5 files changed, 115 insertions, 77 deletions
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index f2d6907..684d76b 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -420,6 +420,43 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg) return 1; } +void* FAST_FUNC udhcp_insert_new_option( + struct option_set **opt_list, + unsigned code, + const void *buffer, + unsigned length, + bool dhcpv6) +{ + IF_NOT_UDHCPC6(bool dhcpv6 = 0;) + struct option_set *new, **curr; + + log2("attaching option %02x to list", code); + new = xmalloc(sizeof(*new)); + if (!dhcpv6) { + new->data = xmalloc(length + OPT_DATA); + new->data[OPT_CODE] = code; + new->data[OPT_LEN] = length; + memcpy(new->data + OPT_DATA, buffer, length); + } else { + new->data = xmalloc(length + D6_OPT_DATA); + new->data[D6_OPT_CODE] = code >> 8; + new->data[D6_OPT_CODE + 1] = code & 0xff; + new->data[D6_OPT_LEN] = length >> 8; + new->data[D6_OPT_LEN + 1] = length & 0xff; + memcpy(new->data + D6_OPT_DATA, buffer, length); + } + + curr = opt_list; +//FIXME: DHCP6 codes > 255!! + while (*curr && (*curr)->data[OPT_CODE] < code) + curr = &(*curr)->next; + + new->next = *curr; + *curr = new; + + return new->data; +} + /* udhcp_str2optset: * Parse string option representation to binary form and add it to opt_list. * Called to parse "udhcpc -x OPTNAME:OPTVAL" @@ -459,32 +496,8 @@ static NOINLINE void attach_option( existing = udhcp_find_option(*opt_list, optflag->code); if (!existing) { - struct option_set *new, **curr; - /* make a new option */ - log2("attaching option %02x to list", optflag->code); - new = xmalloc(sizeof(*new)); - if (!dhcpv6) { - new->data = xmalloc(length + OPT_DATA); - new->data[OPT_CODE] = optflag->code; - new->data[OPT_LEN] = length; - memcpy(new->data + OPT_DATA, buffer, length); - } else { - new->data = xmalloc(length + D6_OPT_DATA); - new->data[D6_OPT_CODE] = optflag->code >> 8; - new->data[D6_OPT_CODE + 1] = optflag->code & 0xff; - new->data[D6_OPT_LEN] = length >> 8; - new->data[D6_OPT_LEN + 1] = length & 0xff; - memcpy(new->data + D6_OPT_DATA, buffer, - length); - } - - curr = opt_list; - while (*curr && (*curr)->data[OPT_CODE] < optflag->code) - curr = &(*curr)->next; - - new->next = *curr; - *curr = new; + udhcp_insert_new_option(opt_list, optflag->code, buffer, length, dhcpv6); goto ret; } diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index cc0abd2..e5af628 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -319,6 +319,17 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; /* 2nd param is "uint32_t*" */ int FAST_FUNC udhcp_str2nip(const char *str, void *arg); + +#if !ENABLE_UDHCPC6 +#define udhcp_insert_new_option(opt_list, code, buffer, length, dhcpv6) \ + udhcp_insert_new_option(opt_list, code, buffer, length) +#endif +void* FAST_FUNC udhcp_insert_new_option(struct option_set **opt_list, + unsigned code, + const void *buffer, + unsigned length, + bool dhcpv6); + /* 2nd param is "struct option_set**" */ #if !ENABLE_UDHCPC6 #define udhcp_str2optset(str, arg, optflags, option_strings, dhcpv6) \ diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 5bca4a8..c4bedb2 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -482,7 +482,6 @@ static ALWAYS_INLINE uint32_t random_xid(void) static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) { uint8_t *ptr; - struct d6_option *clientid; unsigned secs; memset(packet, 0, sizeof(*packet)); @@ -503,9 +502,7 @@ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff; ptr += 2; - /* add CLIENTID option */ - clientid = (void*)client_data.clientid; - return mempcpy(ptr, clientid, clientid->len + 2+2); + return ptr; } static uint8_t *add_d6_client_options(uint8_t *ptr) @@ -593,10 +590,10 @@ static NOINLINE int send_d6_info_request(uint32_t xid) struct d6_packet packet; uint8_t *opt_ptr; - /* Fill in: msg type, client id */ + /* Fill in: msg type */ opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid); - /* Add options: + /* Add options: client-id, * "param req" option according to -O, options specified with -x */ opt_ptr = add_d6_client_options(opt_ptr); @@ -693,7 +690,7 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip uint8_t *opt_ptr; unsigned len; - /* Fill in: msg type, client id */ + /* Fill in: msg type */ opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); /* Create new IA_NA, optionally with included IAADDR with requested IP */ @@ -726,7 +723,7 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); } - /* Add options: + /* Add options: client-id, * "param req" option according to -O, options specified with -x */ opt_ptr = add_d6_client_options(opt_ptr); @@ -771,7 +768,7 @@ static NOINLINE int send_d6_select(uint32_t xid) struct d6_packet packet; uint8_t *opt_ptr; - /* Fill in: msg type, client id */ + /* Fill in: msg type */ opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); /* server id */ @@ -783,7 +780,7 @@ static NOINLINE int send_d6_select(uint32_t xid) if (client6_data.ia_pd) opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); - /* Add options: + /* Add options: client-id, * "param req" option according to -O, options specified with -x */ opt_ptr = add_d6_client_options(opt_ptr); @@ -844,7 +841,7 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st struct d6_packet packet; uint8_t *opt_ptr; - /* Fill in: msg type, client id */ + /* Fill in: msg type */ opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); /* server id */ @@ -856,7 +853,7 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st if (client6_data.ia_pd) opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); - /* Add options: + /* Add options: client-id, * "param req" option according to -O, options specified with -x */ opt_ptr = add_d6_client_options(opt_ptr); @@ -878,6 +875,7 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) { struct d6_packet packet; uint8_t *opt_ptr; + struct option_set *ci; /* Fill in: msg type, client id */ opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); @@ -889,6 +887,10 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) /* IA PD */ if (client6_data.ia_pd) opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); + /* Client-id */ + ci = udhcp_find_option(client_data.options, D6_OPT_CLIENTID); + if (ci) + opt_ptr = mempcpy(opt_ptr, ci->data, D6_OPT_DATA + 2+2 + 6); bb_info_msg("sending %s", "release"); return d6_send_kernel_packet_from_client_data_ifindex( @@ -1184,7 +1186,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) { const char *str_r; IF_FEATURE_UDHCP_PORT(char *str_P;) - void *clientid_mac_ptr; + uint8_t *clientid_mac_ptr; llist_t *list_O = NULL; llist_t *list_x = NULL; int tryagain_timeout = 20; @@ -1284,22 +1286,19 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) if (d6_read_interface(client_data.interface, &client_data.ifindex, &client6_data.ll_ip6, - client_data.client_mac) + client_data_client_mac) ) { return 1; } - /* Create client ID based on mac, set clientid_mac_ptr */ - { - struct d6_option *clientid; - clientid = xzalloc(2+2+2+2+6); - clientid->code = D6_OPT_CLIENTID; - clientid->len = 2+2+6; - clientid->data[1] = 3; /* DUID-LL */ - clientid->data[3] = 1; /* ethernet */ - clientid_mac_ptr = clientid->data + 2+2; - memcpy(clientid_mac_ptr, client_data.client_mac, 6); - client_data.clientid = (void*)clientid; + clientid_mac_ptr = NULL; + if (!udhcp_find_option(client_data.options, D6_OPT_CLIENTID)) { + /* not set, set the default client ID */ + client_data.clientid[1] = 3; /* DUID-LL */ + client_data.clientid[3] = 1; /* ethernet */ + clientid_mac_ptr = udhcp_insert_new_option(&client_data.options, D6_OPT_CLIENTID, + client_data.clientid, 2+2 + 6, /*dhcp6:*/ 1); + clientid_mac_ptr += 2+2 + 2+2; /* skip option code, len, DUID-LL, ethernet */ } #if !BB_MMU @@ -1386,12 +1385,13 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) if (d6_read_interface(client_data.interface, &client_data.ifindex, &client6_data.ll_ip6, - client_data.client_mac) + client_data_client_mac) ) { goto ret0; /* iface is gone? */ } - memcpy(clientid_mac_ptr, client_data.client_mac, 6); + if (clientid_mac_ptr) + memcpy(clientid_mac_ptr, client_data_client_mac, 6); switch (client_data.state) { case INIT_SELECTING: @@ -1505,7 +1505,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) continue; /* case RELEASED: */ } - /* yah, I know, *you* say it would never happen */ + /* RELEASED state (when we got SIGUSR2) ends up here. + * (wait for SIGUSR1 to re-init, or for TERM, etc) + */ timeout = INT_MAX; continue; /* back to main loop */ } /* if poll timed out */ diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index ea06405..a06eeaa 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -612,9 +612,7 @@ static void init_packet(struct dhcp_packet *packet, char type) secs = client_data.last_secs - client_data.first_secs; packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff; - memcpy(packet->chaddr, client_data.client_mac, 6); - if (client_data.clientid) - udhcp_add_binary_option(packet, client_data.clientid); + memcpy(packet->chaddr, client_data_client_mac, 6); } static void add_client_options(struct dhcp_packet *packet) @@ -715,7 +713,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested) /* Fill in: op, htype, hlen, cookie, chaddr fields, * random xid field (we override it below), - * client-id option (unless -C), message type option: + * message type option: */ init_packet(&packet, DHCPDISCOVER); @@ -724,7 +722,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested) udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); /* Add options: maxsize, - * optionally: hostname, fqdn, vendorclass, + * optionally: hostname, fqdn, vendorclass, client-id, * "param req" option according to -O, options specified with -x */ add_client_options(&packet); @@ -758,7 +756,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste */ /* Fill in: op, htype, hlen, cookie, chaddr fields, * random xid field (we override it below), - * client-id option (unless -C), message type option: + * message type option: */ init_packet(&packet, DHCPREQUEST); @@ -768,7 +766,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); /* Add options: maxsize, - * optionally: hostname, fqdn, vendorclass, + * optionally: hostname, fqdn, vendorclass, client-id, * "param req" option according to -O, and options specified with -x */ add_client_options(&packet); @@ -805,7 +803,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) */ /* Fill in: op, htype, hlen, cookie, chaddr fields, * random xid field (we override it below), - * client-id option (unless -C), message type option: + * message type option: */ init_packet(&packet, DHCPREQUEST); @@ -813,7 +811,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) packet.ciaddr = ciaddr; /* Add options: maxsize, - * optionally: hostname, fqdn, vendorclass, + * optionally: hostname, fqdn, vendorclass, client-id, * "param req" option according to -O, and options specified with -x */ add_client_options(&packet); @@ -837,7 +835,7 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req struct dhcp_packet packet; /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, - * client-id option (unless -C), message type option: + * message type option: */ init_packet(&packet, DHCPDECLINE); @@ -854,6 +852,8 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); +//TODO: add client-id opt? + bb_simple_info_msg("broadcasting decline"); return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); } @@ -865,9 +865,10 @@ ALWAYS_INLINE /* one caller, help compiler to use this fact */ int send_release(uint32_t server, uint32_t ciaddr) { struct dhcp_packet packet; + struct option_set *ci; /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, - * client-id option (unless -C), message type option: + * message type option: */ init_packet(&packet, DHCPRELEASE); @@ -876,6 +877,14 @@ int send_release(uint32_t server, uint32_t ciaddr) udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); + /* RFC 2131 section 3.1.6: + * If the client used a 'client identifier' when it obtained the lease, + * it MUST use the same 'client identifier' in the DHCPRELEASE message. + */ + ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID); + if (ci) + udhcp_add_binary_option(&packet, ci->data); + bb_info_msg("sending %s", "release"); /* Note: normally we unicast here since "server" is not zero. * However, there _are_ people who run "address-less" DHCP servers, @@ -1230,7 +1239,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) const char *str_V, *str_h, *str_F, *str_r; IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";) IF_FEATURE_UDHCP_PORT(char *str_P;) - void *clientid_mac_ptr; + uint8_t *clientid_mac_ptr; llist_t *list_O = NULL; llist_t *list_x = NULL; int tryagain_timeout = 20; @@ -1339,7 +1348,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (udhcp_read_interface(client_data.interface, &client_data.ifindex, NULL, - client_data.client_mac) + client_data_client_mac) ) { return 1; } @@ -1347,10 +1356,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) clientid_mac_ptr = NULL; if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) { /* not suppressed and not set, set the default client ID */ - client_data.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); - client_data.clientid[OPT_DATA] = 1; /* type: ethernet */ - clientid_mac_ptr = client_data.clientid + OPT_DATA+1; - memcpy(clientid_mac_ptr, client_data.client_mac, 6); + client_data_client_mac[-1] = 1; /* type: ethernet */ + clientid_mac_ptr = udhcp_insert_new_option( + &client_data.options, DHCP_CLIENT_ID, + client_data_client_mac - 1, 1 + 6, /*dhcp6:*/ 0); + clientid_mac_ptr += 3; /* skip option code, len, ethernet */ } if (str_V[0] != '\0') { // can drop -V, str_V, client_data.vendorclass, @@ -1447,12 +1457,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (udhcp_read_interface(client_data.interface, &client_data.ifindex, NULL, - client_data.client_mac) + client_data_client_mac) ) { goto ret0; /* iface is gone? */ } if (clientid_mac_ptr) - memcpy(clientid_mac_ptr, client_data.client_mac, 6); + memcpy(clientid_mac_ptr, client_data_client_mac, 6); switch (client_data.state) { case INIT_SELECTING: @@ -1569,7 +1579,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) continue; /* case RELEASED: */ } - /* yah, I know, *you* say it would never happen */ + /* RELEASED state (when we got SIGUSR2) ends up here. + * (wait for SIGUSR1 to re-init, or for TERM, etc) + */ timeout = INT_MAX; continue; /* back to main loop */ } /* if poll timed out */ @@ -1645,7 +1657,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* Ignore packets that aren't for us */ if (packet.hlen != 6 - || memcmp(packet.chaddr, client_data.client_mac, 6) != 0 + || memcmp(packet.chaddr, client_data_client_mac, 6) != 0 ) { //FIXME: need to also check that last 10 bytes are zero log1("chaddr does not match%s", ", ignoring packet"); // log2? @@ -1757,7 +1769,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (!arpping(requested_ip, NULL, (uint32_t) 0, - client_data.client_mac, + client_data_client_mac, client_data.interface, arpping_ms) ) { diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 7ad01ea..a4cc188 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h @@ -8,7 +8,8 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct client_data_t { - uint8_t client_mac[6]; /* Our mac address */ + uint8_t clientid[2+2 + 6]; /* Our mac address (prefixed by padding used for client-id) */ +#define client_data_client_mac (client_data.clientid + 2+2) IF_FEATURE_UDHCP_PORT(uint16_t port;) int ifindex; /* Index number of the interface to use */ uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ @@ -17,7 +18,6 @@ struct client_data_t { char *pidfile; /* Optionally store the process ID */ const char *script; /* User script to run at dhcp events */ struct option_set *options; /* list of DHCP options to send to server */ - uint8_t *clientid; /* Optional client id to use */ uint8_t *vendorclass; /* Optional vendor class-id to use */ uint8_t *hostname; /* Optional hostname to use */ uint8_t *fqdn; /* Optional fully qualified domain name to use */ |