summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/sd-dhcp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-server.c')
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c84
1 files changed, 46 insertions, 38 deletions
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 1f167485e3..0b8d4bb843 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -22,12 +22,15 @@
#include <sys/ioctl.h>
-#include "in-addr-util.h"
-#include "siphash24.h"
-
#include "sd-dhcp-server.h"
-#include "dhcp-server-internal.h"
+
+#include "alloc-util.h"
#include "dhcp-internal.h"
+#include "dhcp-server-internal.h"
+#include "fd-util.h"
+#include "in-addr-util.h"
+#include "siphash24.h"
+#include "string-util.h"
#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
@@ -93,7 +96,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
return 0;
}
-bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
+int sd_dhcp_server_is_running(sd_dhcp_server *server) {
assert_return(server, false);
return !!server->receive_message;
@@ -110,18 +113,15 @@ sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
return server;
}
-unsigned long client_id_hash_func(const void *p,
- const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
+void client_id_hash_func(const void *p, struct siphash *state) {
const DHCPClientId *id = p;
assert(id);
assert(id->length);
assert(id->data);
- siphash24((uint8_t*) &u, id->data, id->length, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&id->length, sizeof(id->length), state);
+ siphash24_compress(id->data, id->length, state);
}
int client_id_compare_func(const void *_a, const void *_b) {
@@ -185,7 +185,7 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
}
int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
- _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
+ _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
assert_return(ret, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
@@ -354,13 +354,13 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
assert(packet);
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
- DHCP_OPTION_SERVER_IDENTIFIER,
+ SD_DHCP_OPTION_SERVER_IDENTIFIER,
4, &server->address);
if (r < 0)
return r;
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
- DHCP_OPTION_END, 0, NULL);
+ SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
@@ -457,18 +457,18 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
lease_time = htobe32(req->lifetime);
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
+ SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
&lease_time);
if (r < 0)
return r;
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
+ SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
if (r < 0)
return r;
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_ROUTER, 4, &server->address);
+ SD_DHCP_OPTION_ROUTER, 4, &server->address);
if (r < 0)
return r;
@@ -494,25 +494,25 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
lease_time = htobe32(req->lifetime);
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
+ SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
&lease_time);
if (r < 0)
return r;
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
+ SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
if (r < 0)
return r;
r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_ROUTER, 4, &server->address);
+ SD_DHCP_OPTION_ROUTER, 4, &server->address);
if (r < 0)
return r;
if (server->n_dns > 0) {
r = dhcp_option_append(
&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_DOMAIN_NAME_SERVER,
+ SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
sizeof(struct in_addr) * server->n_dns, server->dns);
if (r < 0)
return r;
@@ -521,7 +521,7 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
if (server->n_ntp > 0) {
r = dhcp_option_append(
&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_NTP_SERVER,
+ SD_DHCP_OPTION_NTP_SERVER,
sizeof(struct in_addr) * server->n_ntp, server->ntp);
if (r < 0)
return r;
@@ -530,7 +530,7 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
if (server->timezone) {
r = dhcp_option_append(
&packet->dhcp, req->max_optlen, &offset, 0,
- DHCP_OPTION_NEW_TZDB_TIMEZONE,
+ SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
strlen(server->timezone), server->timezone);
if (r < 0)
return r;
@@ -576,7 +576,7 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
return r;
r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
- &optoffset, 0, DHCP_OPTION_END, 0, NULL);
+ &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
@@ -596,22 +596,22 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
assert(req);
switch(code) {
- case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
+ case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
if (len == 4)
req->lifetime = be32toh(*(be32_t*)option);
break;
- case DHCP_OPTION_REQUESTED_IP_ADDRESS:
+ case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
if (len == 4)
req->requested_ip = *(be32_t*)option;
break;
- case DHCP_OPTION_SERVER_IDENTIFIER:
+ case SD_DHCP_OPTION_SERVER_IDENTIFIER:
if (len == 4)
req->server_id = *(be32_t*)option;
break;
- case DHCP_OPTION_CLIENT_IDENTIFIER:
+ case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
if (len >= 2) {
uint8_t *data;
@@ -625,7 +625,7 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
}
break;
- case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
+ case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
if (len == 2)
req->max_optlen = be16toh(*(be16_t*)option) -
- sizeof(DHCPPacket);
@@ -699,6 +699,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length) {
_cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
+ _cleanup_free_ char *error_message = NULL;
DHCPLease *existing_lease;
int type, r;
@@ -714,7 +715,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (!req)
return -ENOMEM;
- type = dhcp_option_parse(message, length, parse_request, req);
+ type = dhcp_option_parse(message, length, parse_request, req, &error_message);
if (type < 0)
return 0;
@@ -743,13 +744,18 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (existing_lease)
address = existing_lease->address;
else {
+ struct siphash state;
+ uint64_t hash;
uint32_t next_offer;
/* even with no persistence of leases, we try to offer the same client
the same IP address. we do this by using the hash of the client id
as the offset into the pool of leases when finding the next free one */
- next_offer = client_id_hash_func(&req->client_id, HASH_KEY.bytes) % server->pool_size;
+ siphash24_init(&state, HASH_KEY.bytes);
+ client_id_hash_func(&req->client_id, &state);
+ hash = htole64(siphash24_finalize(&state));
+ next_offer = hash % server->pool_size;
for (i = 0; i < server->pool_size; i++) {
if (!server->bound_leases[next_offer]) {
@@ -779,8 +785,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
break;
}
case DHCP_DECLINE:
- log_dhcp_server(server, "DECLINE (0x%x)",
- be32toh(req->message->xid));
+ log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
/* TODO: make sure we don't offer this address again */
@@ -958,10 +963,10 @@ static int server_receive_message(sd_event_source *s, int fd,
if (ioctl(fd, FIONREAD, &buflen) < 0)
return -errno;
- if (buflen < 0)
+ else if (buflen < 0)
return -EIO;
- message = malloc0(buflen);
+ message = malloc(buflen);
if (!message)
return -ENOMEM;
@@ -969,9 +974,12 @@ static int server_receive_message(sd_event_source *s, int fd,
iov.iov_len = buflen;
len = recvmsg(fd, &msg, 0);
- if (len < buflen)
- return 0;
- else if ((size_t)len < sizeof(DHCPMessage))
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ return -errno;
+ } else if ((size_t)len < sizeof(DHCPMessage))
return 0;
CMSG_FOREACH(cmsg, &msg) {