udhcpc: include client-id option in DECLINEs, even if it's a custom -x 61:HEX option
No binary (build failed)
—
(log yok)
| @@ -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; | |
| } | |
| @@ -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) \ | |
| @@ -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 */ | |
| @@ -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) | |
| ) { | |
| @@ -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 */ | |