diff options
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-client.c')
-rw-r--r-- | src/libsystemd-network/sd-dhcp-client.c | 248 |
1 files changed, 58 insertions, 190 deletions
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 24bcd74..1eb8509 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -15,8 +15,8 @@ #include "alloc-util.h" #include "device-util.h" +#include "dhcp-client-id-internal.h" #include "dhcp-client-internal.h" -#include "dhcp-identifier.h" #include "dhcp-lease-internal.h" #include "dhcp-network.h" #include "dhcp-option.h" @@ -39,7 +39,6 @@ #include "utf8.h" #include "web-util.h" -#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) @@ -48,32 +47,6 @@ #define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report * transient failure. */ -typedef struct sd_dhcp_client_id { - uint8_t type; - union { - struct { - /* 0: Generic (non-LL) (RFC 2132) */ - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ gen; - struct { - /* 1: Ethernet Link-Layer (RFC 2132) */ - uint8_t haddr[ETH_ALEN]; - } _packed_ eth; - struct { - /* 2 - 254: ARP/Link-Layer (RFC 2132) */ - uint8_t haddr[0]; - } _packed_ ll; - struct { - /* 255: Node-specific (RFC 4361) */ - be32_t iaid; - struct duid duid; - } _packed_ ns; - struct { - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ raw; - }; -} _packed_ sd_dhcp_client_id; - struct sd_dhcp_client { unsigned n_ref; @@ -89,6 +62,7 @@ struct sd_dhcp_client { int fd; uint16_t port; + uint16_t server_port; union sockaddr_union link; sd_event_source *receive_message; bool request_broadcast; @@ -100,7 +74,6 @@ struct sd_dhcp_client { struct hw_addr_data bcast_addr; uint16_t arp_type; sd_dhcp_client_id client_id; - size_t client_id_len; char *hostname; char *vendor_class_identifier; char *mudurl; @@ -181,58 +154,6 @@ static int client_receive_message_udp( static void client_stop(sd_dhcp_client *client, int error); static int client_restart(sd_dhcp_client *client); -int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret) { - const sd_dhcp_client_id *client_id = data; - _cleanup_free_ char *t = NULL; - int r = 0; - - assert_return(data, -EINVAL); - assert_return(len >= 1, -EINVAL); - assert_return(ret, -EINVAL); - - len -= 1; - if (len > MAX_CLIENT_ID_LEN) - return -EINVAL; - - switch (client_id->type) { - case 0: - if (utf8_is_printable((char *) client_id->gen.data, len)) - r = asprintf(&t, "%.*s", (int) len, client_id->gen.data); - else - r = asprintf(&t, "DATA"); - break; - case 1: - if (len == sizeof_field(sd_dhcp_client_id, eth)) - r = asprintf(&t, "%02x:%02x:%02x:%02x:%02x:%02x", - client_id->eth.haddr[0], - client_id->eth.haddr[1], - client_id->eth.haddr[2], - client_id->eth.haddr[3], - client_id->eth.haddr[4], - client_id->eth.haddr[5]); - else - r = asprintf(&t, "ETHER"); - break; - case 2 ... 254: - r = asprintf(&t, "ARP/LL"); - break; - case 255: - if (len < sizeof(uint32_t)) - r = asprintf(&t, "IAID/DUID"); - else { - uint32_t iaid = be32toh(client_id->ns.iaid); - /* TODO: check and stringify DUID */ - r = asprintf(&t, "IAID:0x%x/DUID", iaid); - } - break; - } - if (r < 0) - return -ENOMEM; - - *ret = TAKE_PTR(t); - return 0; -} - int dhcp_client_set_state_callback( sd_dhcp_client *client, sd_dhcp_client_callback_t cb, @@ -363,34 +284,14 @@ int sd_dhcp_client_set_mac( return 0; } -int sd_dhcp_client_get_client_id( - sd_dhcp_client *client, - uint8_t *ret_type, - const uint8_t **ret_data, - size_t *ret_data_len) { - +int sd_dhcp_client_get_client_id(sd_dhcp_client *client, const sd_dhcp_client_id **ret) { assert_return(client, -EINVAL); + assert_return(ret, -EINVAL); - if (client->client_id_len > 0) { - if (client->client_id_len <= offsetof(sd_dhcp_client_id, raw.data)) - return -EINVAL; - - if (ret_type) - *ret_type = client->client_id.type; - if (ret_data) - *ret_data = client->client_id.raw.data; - if (ret_data_len) - *ret_data_len = client->client_id_len - offsetof(sd_dhcp_client_id, raw.data); - return 1; - } - - if (ret_type) - *ret_type = 0; - if (ret_data) - *ret_data = NULL; - if (ret_data_len) - *ret_data_len = 0; + if (!sd_dhcp_client_id_is_set(&client->client_id)) + return -ENODATA; + *ret = &client->client_id; return 0; } @@ -403,7 +304,7 @@ int sd_dhcp_client_set_client_id( assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(data, -EINVAL); - assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); + assert_return(client_id_data_size_is_valid(data_len), -EINVAL); /* For hardware types, log debug message about unexpected data length. * @@ -416,42 +317,28 @@ int sd_dhcp_client_set_client_id( "Changing client ID to hardware type %u with unexpected address length %zu", type, data_len); - client->client_id.type = type; - memcpy(&client->client_id.raw.data, data, data_len); - client->client_id_len = data_len + sizeof (client->client_id.type); - - return 0; + return sd_dhcp_client_id_set(&client->client_id, type, data, data_len); } -/** - * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid - * without further modification. Otherwise, if duid_type is supported, DUID - * is set based on that type. Otherwise, an error is returned. - */ -static int dhcp_client_set_iaid( +static int dhcp_client_set_iaid_duid( sd_dhcp_client *client, bool iaid_set, - uint32_t iaid) { + uint32_t iaid, + sd_dhcp_duid *duid) { int r; - assert_return(client, -EINVAL); - assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - - zero(client->client_id); - client->client_id.type = 255; - - if (iaid_set) - client->client_id.ns.iaid = htobe32(iaid); - else { + if (!iaid_set) { r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr, /* legacy_unstable_byteorder = */ true, - &client->client_id.ns.iaid); + &iaid); if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set IAID: %m"); + return r; + + iaid = be32toh(iaid); } - return 0; + return sd_dhcp_client_id_set_iaid_duid(&client->client_id, iaid, duid); } int sd_dhcp_client_set_iaid_duid_llt( @@ -460,23 +347,17 @@ int sd_dhcp_client_set_iaid_duid_llt( uint32_t iaid, usec_t llt_time) { - size_t len; + sd_dhcp_duid duid; int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - r = dhcp_client_set_iaid(client, iaid_set, iaid); + r = sd_dhcp_duid_set_llt(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time); if (r < 0) return r; - r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m"); - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; - - return 0; + return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid); } int sd_dhcp_client_set_iaid_duid_ll( @@ -484,23 +365,17 @@ int sd_dhcp_client_set_iaid_duid_ll( bool iaid_set, uint32_t iaid) { - size_t len; + sd_dhcp_duid duid; int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - r = dhcp_client_set_iaid(client, iaid_set, iaid); + r = sd_dhcp_duid_set_ll(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type); if (r < 0) return r; - r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m"); - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; - - return 0; + return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid); } int sd_dhcp_client_set_iaid_duid_en( @@ -508,23 +383,17 @@ int sd_dhcp_client_set_iaid_duid_en( bool iaid_set, uint32_t iaid) { - size_t len; + sd_dhcp_duid duid; int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - r = dhcp_client_set_iaid(client, iaid_set, iaid); + r = sd_dhcp_duid_set_en(&duid); if (r < 0) return r; - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m"); - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; - - return 0; + return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid); } int sd_dhcp_client_set_iaid_duid_uuid( @@ -532,23 +401,17 @@ int sd_dhcp_client_set_iaid_duid_uuid( bool iaid_set, uint32_t iaid) { - size_t len; + sd_dhcp_duid duid; int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - r = dhcp_client_set_iaid(client, iaid_set, iaid); + r = sd_dhcp_duid_set_uuid(&duid); if (r < 0) return r; - r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m"); - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; - - return 0; + return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid); } int sd_dhcp_client_set_iaid_duid_raw( @@ -556,27 +419,21 @@ int sd_dhcp_client_set_iaid_duid_raw( bool iaid_set, uint32_t iaid, uint16_t duid_type, - const uint8_t *duid, - size_t duid_len) { + const uint8_t *duid_data, + size_t duid_data_len) { - size_t len; + sd_dhcp_duid duid; int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - assert_return(duid || duid_len == 0, -EINVAL); + assert_return(duid_data || duid_data_len == 0, -EINVAL); - r = dhcp_client_set_iaid(client, iaid_set, iaid); + r = sd_dhcp_duid_set(&duid, duid_type, duid_data, duid_data_len); if (r < 0) return r; - r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID: %m"); - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; - - return 0; + return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid); } int sd_dhcp_client_set_rapid_commit(sd_dhcp_client *client, bool rapid_commit) { @@ -660,6 +517,18 @@ int sd_dhcp_client_set_client_port( return 0; } +int sd_dhcp_client_set_port( + sd_dhcp_client *client, + uint16_t port) { + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + + client->server_port = port; + + return 0; +} + int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { assert_return(client, -EINVAL); assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE); @@ -925,8 +794,8 @@ static int client_message_init( Identifier option is not set */ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_CLIENT_IDENTIFIER, - client->client_id_len, - &client->client_id); + client->client_id.size, + client->client_id.raw); if (r < 0) return r; @@ -1035,7 +904,7 @@ static int dhcp_client_send_raw( size_t len) { dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port, - INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type); + INADDR_BROADCAST, client->server_port, len, client->ip_service_type); return dhcp_network_send_raw_socket(client->fd, &client->link, packet, len); @@ -1257,7 +1126,7 @@ static int client_send_request(sd_dhcp_client *client) { if (client->state == DHCP_STATE_RENEWING) r = dhcp_network_send_udp_socket(client->fd, client->lease->server_address, - DHCP_PORT_SERVER, + client->server_port, &request->dhcp, sizeof(DHCPMessage) + optoffset); else @@ -1599,10 +1468,8 @@ static int client_parse_message( if (r < 0) return r; - if (client->client_id_len > 0) { - r = dhcp_lease_set_client_id(lease, - (uint8_t *) &client->client_id, - client->client_id_len); + if (sd_dhcp_client_id_is_set(&client->client_id)) { + r = dhcp_lease_set_client_id(lease, &client->client_id); if (r < 0) return r; } @@ -2302,7 +2169,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { return r; /* If no client identifier exists, construct an RFC 4361-compliant one */ - if (client->client_id_len == 0) { + if (!sd_dhcp_client_id_is_set(&client->client_id)) { r = sd_dhcp_client_set_iaid_duid_en(client, /* iaid_set = */ false, /* iaid = */ 0); if (r < 0) return r; @@ -2349,7 +2216,7 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) { r = dhcp_network_send_udp_socket(client->fd, client->lease->server_address, - DHCP_PORT_SERVER, + client->server_port, &release->dhcp, sizeof(DHCPMessage) + optoffset); if (r < 0) @@ -2383,7 +2250,7 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) { r = dhcp_network_send_udp_socket(client->fd, client->lease->server_address, - DHCP_PORT_SERVER, + client->server_port, &release->dhcp, sizeof(DHCPMessage) + optoffset); if (r < 0) @@ -2528,6 +2395,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { .fd = -EBADF, .mtu = DHCP_MIN_PACKET_SIZE, .port = DHCP_PORT_CLIENT, + .server_port = DHCP_PORT_SERVER, .anonymize = !!anonymize, .max_discover_attempts = UINT64_MAX, .max_request_attempts = 5, |