diff options
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-client.c')
-rw-r--r-- | src/libsystemd-network/sd-dhcp-client.c | 97 |
1 files changed, 73 insertions, 24 deletions
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index e20d339bd5..29b22eed45 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -62,6 +62,7 @@ struct sd_dhcp_client { uint8_t *req_opts; size_t req_opts_allocated; size_t req_opts_size; + bool anonymize; be32_t last_addr; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; @@ -116,6 +117,32 @@ static const uint8_t default_req_opts[] = { SD_DHCP_OPTION_DOMAIN_NAME_SERVER, }; +/* RFC7844 section 3: + MAY contain the Parameter Request List option. + RFC7844 section 3.6: + The client intending to protect its privacy SHOULD only request a + minimal number of options in the PRL and SHOULD also randomly shuffle + the ordering of option codes in the PRL. If this random ordering + cannot be implemented, the client MAY order the option codes in the + PRL by option code number (lowest to highest). +*/ +/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */ +static const uint8_t default_req_opts_anonymize[] = { + SD_DHCP_OPTION_SUBNET_MASK, /* 1 */ + SD_DHCP_OPTION_ROUTER, /* 3 */ + SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */ + SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */ + SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */ + SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */ + SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */ + SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */ + SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */ + SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */ + SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */ + SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */ + SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */ +}; + static int client_receive_message_raw( sd_event_source *s, int fd, @@ -428,9 +455,7 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); - if (client->state != DHCP_STATE_BOUND && - client->state != DHCP_STATE_RENEWING && - client->state != DHCP_STATE_REBINDING) + if (!IN_SET(client->state, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING)) return -EADDRNOTAVAIL; if (ret) @@ -503,7 +528,7 @@ static int client_message_init( assert(ret); assert(_optlen); assert(_optoffset); - assert(type == DHCP_DISCOVER || type == DHCP_REQUEST); + assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)); optlen = DHCP_MIN_OPTIONS_SIZE; size = sizeof(DHCPPacket) + optlen; @@ -588,11 +613,18 @@ static int client_message_init( it MUST include that list in any subsequent DHCPREQUEST messages. */ - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, - client->req_opts_size, client->req_opts); - if (r < 0) - return r; + + /* RFC7844 section 3: + MAY contain the Parameter Request List option. */ + /* NOTE: in case that there would be an option to do not send + * any PRL at all, the size should be checked before sending */ + if (client->req_opts_size > 0) { + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, + client->req_opts_size, client->req_opts); + if (r < 0) + return r; + } /* RFC2131 section 3.5: The client SHOULD include the ’maximum DHCP message size’ option to @@ -616,12 +648,16 @@ static int client_message_init( Maximum DHCP Message Size option is the total maximum packet size, including IP and UDP headers.) */ - max_size = htobe16(size); - r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, - SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, - 2, &max_size); - if (r < 0) - return r; + /* RFC7844 section 3: + SHOULD NOT contain any other option. */ + if (!client->anonymize) { + max_size = htobe16(size); + r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, + SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, + 2, &max_size); + if (r < 0) + return r; + } *_optlen = optlen; *_optoffset = optoffset; @@ -671,8 +707,7 @@ static int client_send_discover(sd_dhcp_client *client) { int r; assert(client); - assert(client->state == DHCP_STATE_INIT || - client->state == DHCP_STATE_SELECTING); + assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING)); r = client_message_init(client, &discover, DHCP_DISCOVER, &optlen, &optoffset); @@ -1126,7 +1161,7 @@ static int client_start_delayed(sd_dhcp_client *client) { } client->fd = r; - if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT) + if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT)) client->start_time = now(clock_boottime_or_monotonic()); return client_initialize_events(client, client_receive_message_raw); @@ -1652,7 +1687,7 @@ static int client_receive_message_udp( len = recv(fd, message, buflen, 0); if (len < 0) { - if (errno == EAGAIN || errno == EINTR) + if (IN_SET(errno, EAGAIN, EINTR)) return 0; return log_dhcp_client_errno(client, errno, @@ -1746,7 +1781,7 @@ static int client_receive_message_raw( len = recvmsg(fd, &msg, 0); if (len < 0) { - if (errno == EAGAIN || errno == EINTR) + if (IN_SET(errno, EAGAIN, EINTR)) return 0; return log_dhcp_client_errno(client, errno, @@ -1783,7 +1818,14 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { if (r < 0) return r; - if (client->last_addr) + /* RFC7844 section 3.3: + SHOULD perform a complete four-way handshake, starting with a + DHCPDISCOVER, to obtain a new address lease. If the client can + ascertain that this is exactly the same network to which it was + previously connected, and if the link-layer address did not change, + the client MAY issue a DHCPREQUEST to try to reclaim the current + address. */ + if (client->last_addr && !client->anonymize) client->state = DHCP_STATE_INIT_REBOOT; r = client_start(client); @@ -1875,7 +1917,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { return mfree(client); } -int sd_dhcp_client_new(sd_dhcp_client **ret) { +int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL; assert_return(ret, -EINVAL); @@ -1892,8 +1934,15 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { client->mtu = DHCP_DEFAULT_MIN_SIZE; client->port = DHCP_PORT_CLIENT; - client->req_opts_size = ELEMENTSOF(default_req_opts); - client->req_opts = memdup(default_req_opts, client->req_opts_size); + client->anonymize = !!anonymize; + /* NOTE: this could be moved to a function. */ + if (anonymize) { + client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize); + client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size); + } else { + client->req_opts_size = ELEMENTSOF(default_req_opts); + client->req_opts = memdup(default_req_opts, client->req_opts_size); + } if (!client->req_opts) return -ENOMEM; |