]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-server.c
Merge pull request #9301 from keszybz/man-drop-authorgroup
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-server.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b44cd882 2/***
810adae9
LP
3 Copyright © 2013 Intel Corporation. All rights reserved.
4 Copyright © 2014 Tom Gundersen
b44cd882
TG
5***/
6
ff734080
TG
7#include <sys/ioctl.h>
8
b44cd882 9#include "sd-dhcp-server.h"
07630cea 10
b5efdb8a 11#include "alloc-util.h"
ff734080 12#include "dhcp-internal.h"
07630cea 13#include "dhcp-server-internal.h"
3ffd4af2 14#include "fd-util.h"
07630cea 15#include "in-addr-util.h"
dccca82b 16#include "sd-id128.h"
07630cea
LP
17#include "siphash24.h"
18#include "string-util.h"
9ae84244 19#include "unaligned.h"
b44cd882 20
586ac6f7
LP
21#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
22#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
4dc35568 23
45a9eac9
RM
24static void dhcp_lease_free(DHCPLease *lease) {
25 if (!lease)
26 return;
27
28 free(lease->client_id.data);
29 free(lease);
30}
31
99634696
TG
32/* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
33 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
34 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
35 * accidentally hand it out */
36int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size) {
37 struct in_addr netmask_addr;
38 be32_t netmask;
39 uint32_t server_off, broadcast_off, size_max;
40
2dead812
TG
41 assert_return(server, -EINVAL);
42 assert_return(address, -EINVAL);
99634696
TG
43 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
44 assert_return(prefixlen <= 32, -ERANGE);
99634696 45
5a941f5f 46 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
99634696
TG
47 netmask = netmask_addr.s_addr;
48
49 server_off = be32toh(address->s_addr & ~netmask);
50 broadcast_off = be32toh(~netmask);
51
52 /* the server address cannot be the subnet address */
53 assert_return(server_off != 0, -ERANGE);
54
55 /* nor the broadcast address */
56 assert_return(server_off != broadcast_off, -ERANGE);
57
58 /* 0 offset means we should set a default, we skip the first (subnet) address
59 and take the next one */
60 if (offset == 0)
61 offset = 1;
62
63 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
64 - offset /* exclude the addresses before the offset */
65 - 1; /* exclude the last (broadcast) address */
66
67 /* The pool must contain at least one address */
68 assert_return(size_max >= 1, -ERANGE);
69
70 if (size != 0)
71 assert_return(size <= size_max, -ERANGE);
72 else
73 size = size_max;
87322b3a 74
45a9eac9 75 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
45a9eac9
RM
76
77 free(server->bound_leases);
78 server->bound_leases = new0(DHCPLease*, size);
79 if (!server->bound_leases)
80 return -ENOMEM;
2dead812 81
45a9eac9
RM
82 server->pool_offset = offset;
83 server->pool_size = size;
2dead812 84
45a9eac9
RM
85 server->address = address->s_addr;
86 server->netmask = netmask;
87 server->subnet = address->s_addr & netmask;
99634696 88
45a9eac9
RM
89 if (server_off >= offset && server_off - offset < size)
90 server->bound_leases[server_off - offset] = &server->invalid_lease;
91
92 /* Drop any leases associated with the old address range */
224b0e7a 93 hashmap_clear_with_destructor(server->leases_by_client_id, dhcp_lease_free);
45a9eac9 94 }
20af7091
TG
95
96 return 0;
97}
98
04c01369 99int sd_dhcp_server_is_running(sd_dhcp_server *server) {
75677581 100 assert_return(server, false);
7c16313f
TG
101
102 return !!server->receive_message;
103}
104
b44cd882 105sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
3733eec3
LP
106
107 if (!server)
108 return NULL;
109
110 assert(server->n_ref >= 1);
111 server->n_ref++;
b44cd882
TG
112
113 return server;
114}
115
b826ab58 116void client_id_hash_func(const void *p, struct siphash *state) {
87322b3a
TG
117 const DHCPClientId *id = p;
118
119 assert(id);
120 assert(id->length);
121 assert(id->data);
122
1e2527a6 123 siphash24_compress(&id->length, sizeof(id->length), state);
b826ab58 124 siphash24_compress(id->data, id->length, state);
87322b3a
TG
125}
126
127int client_id_compare_func(const void *_a, const void *_b) {
128 const DHCPClientId *a, *b;
129
130 a = _a;
131 b = _b;
132
133 assert(!a->length || a->data);
134 assert(!b->length || b->data);
135
136 if (a->length != b->length)
137 return a->length < b->length ? -1 : 1;
138
139 return memcmp(a->data, b->data, a->length);
140}
141
d5099efc
MS
142static const struct hash_ops client_id_hash_ops = {
143 .hash = client_id_hash_func,
144 .compare = client_id_compare_func
145};
146
b44cd882 147sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
3bdace9b 148 DHCPLease *lease;
87322b3a 149
3bdace9b
LP
150 if (!server)
151 return NULL;
b44cd882 152
3733eec3
LP
153 assert(server->n_ref >= 1);
154 server->n_ref--;
155
156 if (server->n_ref > 0)
3bdace9b 157 return NULL;
ff734080 158
3bdace9b 159 log_dhcp_server(server, "UNREF");
87322b3a 160
3bdace9b 161 sd_dhcp_server_stop(server);
87322b3a 162
3bdace9b
LP
163 sd_event_unref(server->event);
164
8eb9058d 165 free(server->timezone);
1a04db0f
LP
166 free(server->dns);
167 free(server->ntp);
8eb9058d 168
3bdace9b
LP
169 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
170 dhcp_lease_free(lease);
171 hashmap_free(server->leases_by_client_id);
172
173 free(server->bound_leases);
6b430fdb 174 return mfree(server);
b44cd882
TG
175}
176
3a864fe4 177int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
4afd3348 178 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
b44cd882
TG
179
180 assert_return(ret, -EINVAL);
3a864fe4 181 assert_return(ifindex > 0, -EINVAL);
b44cd882
TG
182
183 server = new0(sd_dhcp_server, 1);
184 if (!server)
185 return -ENOMEM;
186
3733eec3 187 server->n_ref = 1;
8de4a226 188 server->fd_raw = -1;
ff734080 189 server->fd = -1;
20af7091 190 server->address = htobe32(INADDR_ANY);
59b8f6b6 191 server->netmask = htobe32(INADDR_ANY);
b3ec603c 192 server->ifindex = ifindex;
357e1b17 193
d5099efc 194 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
357e1b17
LP
195 if (!server->leases_by_client_id)
196 return -ENOMEM;
197
586ac6f7
LP
198 server->default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC);
199 server->max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC);
b44cd882 200
1cc6c93a 201 *ret = TAKE_PTR(server);
b44cd882
TG
202
203 return 0;
204}
205
32d20645 206int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
b44cd882
TG
207 int r;
208
209 assert_return(server, -EINVAL);
210 assert_return(!server->event, -EBUSY);
211
212 if (event)
213 server->event = sd_event_ref(event);
214 else {
215 r = sd_event_default(&server->event);
216 if (r < 0)
217 return r;
218 }
219
220 server->event_priority = priority;
221
222 return 0;
223}
224
225int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
226 assert_return(server, -EINVAL);
227
228 server->event = sd_event_unref(server->event);
229
230 return 0;
231}
232
233sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
234 assert_return(server, NULL);
235
236 return server->event;
237}
ff734080
TG
238
239int sd_dhcp_server_stop(sd_dhcp_server *server) {
240 assert_return(server, -EINVAL);
241
242 server->receive_message =
243 sd_event_source_unref(server->receive_message);
244
8de4a226 245 server->fd_raw = safe_close(server->fd_raw);
ff734080
TG
246 server->fd = safe_close(server->fd);
247
248 log_dhcp_server(server, "STOPPED");
249
250 return 0;
251}
252
a6f1e036
TG
253static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
254 DHCPPacket *packet, size_t len) {
969b009d
TG
255 union sockaddr_union link = {
256 .ll.sll_family = AF_PACKET,
8e38570e 257 .ll.sll_protocol = htobe16(ETH_P_IP),
b3ec603c 258 .ll.sll_ifindex = server->ifindex,
969b009d
TG
259 .ll.sll_halen = ETH_ALEN,
260 };
969b009d
TG
261
262 assert(server);
b3ec603c 263 assert(server->ifindex > 0);
969b009d
TG
264 assert(server->address);
265 assert(packet);
266 assert(len > sizeof(DHCPPacket));
267
268 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
269
270 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
a6f1e036
TG
271 packet->dhcp.yiaddr,
272 DHCP_PORT_CLIENT, len);
969b009d 273
b3ec603c 274 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
969b009d
TG
275}
276
277static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
8eb7b6a5 278 uint16_t destination_port,
969b009d
TG
279 DHCPMessage *message, size_t len) {
280 union sockaddr_union dest = {
281 .in.sin_family = AF_INET,
8eb7b6a5 282 .in.sin_port = htobe16(destination_port),
969b009d
TG
283 .in.sin_addr.s_addr = destination,
284 };
285 struct iovec iov = {
286 .iov_base = message,
287 .iov_len = len,
288 };
289 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
290 struct msghdr msg = {
291 .msg_name = &dest,
292 .msg_namelen = sizeof(dest.in),
293 .msg_iov = &iov,
294 .msg_iovlen = 1,
295 .msg_control = cmsgbuf,
296 .msg_controllen = sizeof(cmsgbuf),
297 };
298 struct cmsghdr *cmsg;
299 struct in_pktinfo *pktinfo;
969b009d
TG
300
301 assert(server);
4c9cb12c 302 assert(server->fd >= 0);
969b009d
TG
303 assert(message);
304 assert(len > sizeof(DHCPMessage));
305
306 cmsg = CMSG_FIRSTHDR(&msg);
307 assert(cmsg);
308
309 cmsg->cmsg_level = IPPROTO_IP;
310 cmsg->cmsg_type = IP_PKTINFO;
311 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
312
313 /* we attach source interface and address info to the message
314 rather than binding the socket. This will be mostly useful
315 when we gain support for arbitrary number of server addresses
316 */
317 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
318 assert(pktinfo);
319
b3ec603c 320 pktinfo->ipi_ifindex = server->ifindex;
969b009d
TG
321 pktinfo->ipi_spec_dst.s_addr = server->address;
322
0f01c1f9 323 if (sendmsg(server->fd, &msg, 0) < 0)
969b009d
TG
324 return -errno;
325
326 return 0;
327}
328
329static bool requested_broadcast(DHCPRequest *req) {
330 assert(req);
331
332 return req->message->flags & htobe16(0x8000);
333}
334
335int dhcp_server_send_packet(sd_dhcp_server *server,
336 DHCPRequest *req, DHCPPacket *packet,
337 int type, size_t optoffset) {
338 be32_t destination = INADDR_ANY;
8eb7b6a5 339 uint16_t destination_port = DHCP_PORT_CLIENT;
969b009d
TG
340 int r;
341
342 assert(server);
343 assert(req);
344 assert(req->max_optlen);
345 assert(optoffset <= req->max_optlen);
346 assert(packet);
347
348 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
22805d92 349 SD_DHCP_OPTION_SERVER_IDENTIFIER,
969b009d
TG
350 4, &server->address);
351 if (r < 0)
352 return r;
353
354 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
22805d92 355 SD_DHCP_OPTION_END, 0, NULL);
969b009d
TG
356 if (r < 0)
357 return r;
358
359 /* RFC 2131 Section 4.1
360
361 If the ’giaddr’ field in a DHCP message from a client is non-zero,
362 the server sends any return messages to the ’DHCP server’ port on the
363 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
364 field is zero and the ’ciaddr’ field is nonzero, then the server
365 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
366 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
367 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
368 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
369 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
370 messages to the client’s hardware address and ’yiaddr’ address. In
371 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
372 messages to 0xffffffff.
373
374 Section 4.3.2
375
376 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
377 different subnet. The server MUST set the broadcast bit in the
378 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
379 client, because the client may not have a correct network address
380 or subnet mask, and the client may not be answering ARP requests.
381 */
382 if (req->message->giaddr) {
383 destination = req->message->giaddr;
8eb7b6a5 384 destination_port = DHCP_PORT_SERVER;
969b009d
TG
385 if (type == DHCP_NAK)
386 packet->dhcp.flags = htobe16(0x8000);
387 } else if (req->message->ciaddr && type != DHCP_NAK)
388 destination = req->message->ciaddr;
389
d6bd972d 390 if (destination != INADDR_ANY)
8eb7b6a5
PF
391 return dhcp_server_send_udp(server, destination,
392 destination_port, &packet->dhcp,
969b009d 393 sizeof(DHCPMessage) + optoffset);
d6bd972d 394 else if (requested_broadcast(req) || type == DHCP_NAK)
a6f1e036 395 return dhcp_server_send_udp(server, INADDR_BROADCAST,
8eb7b6a5 396 destination_port, &packet->dhcp,
d6bd972d 397 sizeof(DHCPMessage) + optoffset);
969b009d 398 else
a6f1e036
TG
399 /* we cannot send UDP packet to specific MAC address when the
400 address is not yet configured, so must fall back to raw
401 packets */
969b009d
TG
402 return dhcp_server_send_unicast_raw(server, packet,
403 sizeof(DHCPPacket) + optoffset);
404}
405
4dc35568 406static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
a6f1e036
TG
407 uint8_t type, size_t *_optoffset,
408 DHCPRequest *req) {
4dc35568 409 _cleanup_free_ DHCPPacket *packet = NULL;
1231c4d2 410 size_t optoffset = 0;
4dc35568
TG
411 int r;
412
413 assert(server);
414 assert(ret);
415 assert(_optoffset);
bd57b450 416 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
4dc35568
TG
417
418 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
419 if (!packet)
420 return -ENOMEM;
421
a6f1e036 422 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
76253e73
DW
423 be32toh(req->message->xid), type, ARPHRD_ETHER,
424 req->max_optlen, &optoffset);
4dc35568
TG
425 if (r < 0)
426 return r;
427
428 packet->dhcp.flags = req->message->flags;
429 packet->dhcp.giaddr = req->message->giaddr;
430 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
431
432 *_optoffset = optoffset;
1cc6c93a 433 *ret = TAKE_PTR(packet);
4dc35568
TG
434
435 return 0;
436}
437
a6f1e036
TG
438static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
439 be32_t address) {
4dc35568
TG
440 _cleanup_free_ DHCPPacket *packet = NULL;
441 size_t offset;
442 be32_t lease_time;
443 int r;
444
445 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
446 if (r < 0)
447 return r;
448
2dead812 449 packet->dhcp.yiaddr = address;
4dc35568 450
c7d9ffe6 451 lease_time = htobe32(req->lifetime);
4dc35568 452 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 453 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
a6f1e036 454 &lease_time);
4dc35568
TG
455 if (r < 0)
456 return r;
457
59b8f6b6 458 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 459 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
59b8f6b6
TG
460 if (r < 0)
461 return r;
462
77ff6022
CG
463 if (server->emit_router) {
464 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
465 SD_DHCP_OPTION_ROUTER, 4, &server->address);
466 if (r < 0)
467 return r;
468 }
59b8f6b6 469
4dc35568
TG
470 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
471 if (r < 0)
472 return r;
473
474 return 0;
475}
476
a6f1e036
TG
477static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
478 be32_t address) {
2dead812
TG
479 _cleanup_free_ DHCPPacket *packet = NULL;
480 size_t offset;
481 be32_t lease_time;
482 int r;
483
484 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
485 if (r < 0)
486 return r;
487
488 packet->dhcp.yiaddr = address;
489
c7d9ffe6 490 lease_time = htobe32(req->lifetime);
2dead812 491 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 492 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
a6f1e036 493 &lease_time);
2dead812
TG
494 if (r < 0)
495 return r;
496
59b8f6b6 497 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
22805d92 498 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
59b8f6b6
TG
499 if (r < 0)
500 return r;
501
77ff6022
CG
502 if (server->emit_router) {
503 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
504 SD_DHCP_OPTION_ROUTER, 4, &server->address);
505 if (r < 0)
506 return r;
507 }
59b8f6b6 508
1a04db0f
LP
509 if (server->n_dns > 0) {
510 r = dhcp_option_append(
511 &packet->dhcp, req->max_optlen, &offset, 0,
22805d92 512 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
1a04db0f
LP
513 sizeof(struct in_addr) * server->n_dns, server->dns);
514 if (r < 0)
515 return r;
516 }
517
518 if (server->n_ntp > 0) {
519 r = dhcp_option_append(
520 &packet->dhcp, req->max_optlen, &offset, 0,
22805d92 521 SD_DHCP_OPTION_NTP_SERVER,
1a04db0f
LP
522 sizeof(struct in_addr) * server->n_ntp, server->ntp);
523 if (r < 0)
524 return r;
525 }
526
8eb9058d
LP
527 if (server->timezone) {
528 r = dhcp_option_append(
529 &packet->dhcp, req->max_optlen, &offset, 0,
22805d92 530 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
8eb9058d
LP
531 strlen(server->timezone), server->timezone);
532 if (r < 0)
533 return r;
534 }
535
2dead812
TG
536 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
537 if (r < 0)
538 return r;
539
540 return 0;
541}
542
bd57b450
TG
543static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
544 _cleanup_free_ DHCPPacket *packet = NULL;
545 size_t offset;
546 int r;
547
548 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
549 if (r < 0)
550 return r;
551
b3ec603c 552 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
bd57b450
TG
553}
554
a6f1e036
TG
555static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
556 be32_t gateway, uint8_t chaddr[]) {
52750344
TG
557 _cleanup_free_ DHCPPacket *packet = NULL;
558 size_t optoffset = 0;
559 int r;
560
561 assert(server);
562 assert(address != INADDR_ANY);
563 assert(chaddr);
564
565 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
566 if (!packet)
567 return -ENOMEM;
568
569 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
76253e73
DW
570 DHCP_FORCERENEW, ARPHRD_ETHER,
571 DHCP_MIN_OPTIONS_SIZE, &optoffset);
52750344
TG
572 if (r < 0)
573 return r;
574
575 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
22805d92 576 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
52750344
TG
577 if (r < 0)
578 return r;
579
580 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
581
8eb7b6a5
PF
582 r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
583 &packet->dhcp,
52750344 584 sizeof(DHCPMessage) + optoffset);
c15fb62a
TA
585 if (r < 0)
586 return r;
52750344
TG
587
588 return 0;
589}
590
b3ec603c 591static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
89ca10c6 592 DHCPRequest *req = userdata;
816e2e7a
TG
593
594 assert(req);
595
596 switch(code) {
22805d92 597 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
c7d9ffe6 598 if (len == 4)
9ae84244 599 req->lifetime = unaligned_read_be32(option);
c7d9ffe6
TG
600
601 break;
22805d92 602 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
2dead812 603 if (len == 4)
9ae84244 604 memcpy(&req->requested_ip, option, sizeof(be32_t));
2dead812
TG
605
606 break;
22805d92 607 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
816e2e7a 608 if (len == 4)
9ae84244 609 memcpy(&req->server_id, option, sizeof(be32_t));
816e2e7a
TG
610
611 break;
22805d92 612 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
816e2e7a
TG
613 if (len >= 2) {
614 uint8_t *data;
615
616 data = memdup(option, len);
617 if (!data)
618 return -ENOMEM;
619
620 free(req->client_id.data);
621 req->client_id.data = data;
622 req->client_id.length = len;
623 }
624
625 break;
22805d92 626 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
76a9d0f1
LP
627
628 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
9ae84244 629 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
816e2e7a
TG
630
631 break;
632 }
633
634 return 0;
635}
636
637static void dhcp_request_free(DHCPRequest *req) {
638 if (!req)
639 return;
640
641 free(req->client_id.data);
642 free(req);
643}
644
645DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
816e2e7a 646
586ac6f7 647static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
816e2e7a
TG
648 assert(req);
649 assert(message);
650
651 req->message = message;
652
e2acdb6b 653 /* set client id based on MAC address if client did not send an explicit
a6f1e036 654 one */
816e2e7a 655 if (!req->client_id.data) {
9a0f246f 656 void *data;
816e2e7a 657
9a0f246f 658 data = malloc0(ETH_ALEN + 1);
816e2e7a
TG
659 if (!data)
660 return -ENOMEM;
661
9a0f246f
LP
662 ((uint8_t*) data)[0] = 0x01;
663 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
664
816e2e7a
TG
665 req->client_id.length = ETH_ALEN + 1;
666 req->client_id.data = data;
816e2e7a
TG
667 }
668
669 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
670 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
671
9a0f246f 672 if (req->lifetime <= 0)
586ac6f7
LP
673 req->lifetime = MAX(1ULL, server->default_lease_time);
674
675 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
676 req->lifetime = server->max_lease_time;
c7d9ffe6 677
816e2e7a
TG
678 return 0;
679}
680
87322b3a
TG
681static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
682 assert(server);
683
684 if (!server->pool_size)
685 return -EINVAL;
686
99634696
TG
687 if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
688 be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
689 return -ERANGE;
87322b3a 690
99634696 691 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
87322b3a
TG
692}
693
83cedf7a
TG
694#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
695
be077570
TG
696int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
697 size_t length) {
8e766630 698 _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
f693e9b3 699 _cleanup_free_ char *error_message = NULL;
87322b3a 700 DHCPLease *existing_lease;
816e2e7a 701 int type, r;
be077570
TG
702
703 assert(server);
704 assert(message);
705
706 if (message->op != BOOTREQUEST ||
707 message->htype != ARPHRD_ETHER ||
708 message->hlen != ETHER_ADDR_LEN)
709 return 0;
710
816e2e7a
TG
711 req = new0(DHCPRequest, 1);
712 if (!req)
713 return -ENOMEM;
714
f693e9b3 715 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
be077570
TG
716 if (type < 0)
717 return 0;
718
586ac6f7 719 r = ensure_sane_request(server, req, message);
816e2e7a
TG
720 if (r < 0)
721 /* this only fails on critical errors */
722 return r;
723
a6f1e036
TG
724 existing_lease = hashmap_get(server->leases_by_client_id,
725 &req->client_id);
87322b3a 726
4dc35568 727 switch(type) {
9a0f246f
LP
728
729 case DHCP_DISCOVER: {
87322b3a
TG
730 be32_t address = INADDR_ANY;
731 unsigned i;
2dead812 732
4dc35568
TG
733 log_dhcp_server(server, "DISCOVER (0x%x)",
734 be32toh(req->message->xid));
735
2dead812
TG
736 if (!server->pool_size)
737 /* no pool allocated */
738 return 0;
739
87322b3a
TG
740 /* for now pick a random free address from the pool */
741 if (existing_lease)
742 address = existing_lease->address;
743 else {
b826ab58 744 struct siphash state;
0cb3c286 745 uint64_t hash;
99634696 746 uint32_t next_offer;
83cedf7a
TG
747
748 /* even with no persistence of leases, we try to offer the same client
749 the same IP address. we do this by using the hash of the client id
750 as the offset into the pool of leases when finding the next free one */
751
0cb3c286 752 siphash24_init(&state, HASH_KEY.bytes);
b826ab58 753 client_id_hash_func(&req->client_id, &state);
933f9cae 754 hash = htole64(siphash24_finalize(&state));
0cb3c286 755 next_offer = hash % server->pool_size;
83cedf7a 756
87322b3a 757 for (i = 0; i < server->pool_size; i++) {
83cedf7a 758 if (!server->bound_leases[next_offer]) {
99634696 759 address = server->subnet | htobe32(server->pool_offset + next_offer);
87322b3a 760 break;
6408ba5f
LP
761 }
762
763 next_offer = (next_offer + 1) % server->pool_size;
87322b3a
TG
764 }
765 }
766
767 if (address == INADDR_ANY)
768 /* no free addresses left */
769 return 0;
2dead812
TG
770
771 r = server_send_offer(server, req, address);
6e741541 772 if (r < 0)
4dc35568 773 /* this only fails on critical errors */
6e741541 774 return log_dhcp_server_errno(server, r, "Could not send offer: %m");
be077570 775
6e741541
LP
776 log_dhcp_server(server, "OFFER (0x%x)", be32toh(req->message->xid));
777 return DHCP_OFFER;
4dc35568 778 }
5b34277c 779 case DHCP_DECLINE:
f693e9b3 780 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
5b34277c
TG
781
782 /* TODO: make sure we don't offer this address again */
783
784 return 1;
785
9a0f246f 786 case DHCP_REQUEST: {
2dead812 787 be32_t address;
bd57b450 788 bool init_reboot = false;
87322b3a 789 int pool_offset;
2dead812
TG
790
791 /* see RFC 2131, section 4.3.2 */
792
793 if (req->server_id) {
794 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
795 be32toh(req->message->xid));
796
797 /* SELECTING */
798 if (req->server_id != server->address)
799 /* client did not pick us */
800 return 0;
801
802 if (req->message->ciaddr)
803 /* this MUST be zero */
804 return 0;
805
806 if (!req->requested_ip)
807 /* this must be filled in with the yiaddr
808 from the chosen OFFER */
809 return 0;
810
811 address = req->requested_ip;
812 } else if (req->requested_ip) {
813 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
814 be32toh(req->message->xid));
815
816 /* INIT-REBOOT */
817 if (req->message->ciaddr)
818 /* this MUST be zero */
819 return 0;
820
bd57b450 821 /* TODO: check more carefully if IP is correct */
2dead812 822 address = req->requested_ip;
bd57b450 823 init_reboot = true;
2dead812
TG
824 } else {
825 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
826 be32toh(req->message->xid));
827
828 /* REBINDING / RENEWING */
829 if (!req->message->ciaddr)
830 /* this MUST be filled in with clients IP address */
831 return 0;
832
833 address = req->message->ciaddr;
834 }
835
87322b3a
TG
836 pool_offset = get_pool_offset(server, address);
837
838 /* verify that the requested address is from the pool, and either
839 owned by the current client or free */
840 if (pool_offset >= 0 &&
841 server->bound_leases[pool_offset] == existing_lease) {
842 DHCPLease *lease;
a7f7d1bd 843 usec_t time_now = 0;
87322b3a
TG
844
845 if (!existing_lease) {
846 lease = new0(DHCPLease, 1);
357e1b17
LP
847 if (!lease)
848 return -ENOMEM;
28c78e07 849 lease->address = address;
87322b3a
TG
850 lease->client_id.data = memdup(req->client_id.data,
851 req->client_id.length);
02557f97
TA
852 if (!lease->client_id.data) {
853 free(lease);
87322b3a 854 return -ENOMEM;
02557f97 855 }
87322b3a 856 lease->client_id.length = req->client_id.length;
a6f1e036
TG
857 memcpy(&lease->chaddr, &req->message->chaddr,
858 ETH_ALEN);
52750344 859 lease->gateway = req->message->giaddr;
87322b3a
TG
860 } else
861 lease = existing_lease;
862
a6f1e036
TG
863 r = sd_event_now(server->event,
864 clock_boottime_or_monotonic(),
865 &time_now);
bff92d2c
SS
866 if (r < 0) {
867 if (!existing_lease)
868 dhcp_lease_free(lease);
38a03f06 869 return r;
bff92d2c
SS
870 }
871
87322b3a
TG
872 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
873
2dead812
TG
874 r = server_send_ack(server, req, address);
875 if (r < 0) {
876 /* this only fails on critical errors */
6e741541 877 log_dhcp_server_errno(server, r, "Could not send ack: %m");
87322b3a
TG
878
879 if (!existing_lease)
880 dhcp_lease_free(lease);
881
2dead812
TG
882 return r;
883 } else {
884 log_dhcp_server(server, "ACK (0x%x)",
885 be32toh(req->message->xid));
87322b3a
TG
886
887 server->bound_leases[pool_offset] = lease;
a6f1e036
TG
888 hashmap_put(server->leases_by_client_id,
889 &lease->client_id, lease);
87322b3a 890
2dead812
TG
891 return DHCP_ACK;
892 }
6e741541 893
bd57b450
TG
894 } else if (init_reboot) {
895 r = server_send_nak(server, req);
6e741541 896 if (r < 0)
bd57b450 897 /* this only fails on critical errors */
6e741541
LP
898 return log_dhcp_server_errno(server, r, "Could not send nak: %m");
899
900 log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
901 return DHCP_NAK;
bd57b450 902 }
2dead812
TG
903
904 break;
905 }
9a0f246f 906
500792d8
TG
907 case DHCP_RELEASE: {
908 int pool_offset;
909
910 log_dhcp_server(server, "RELEASE (0x%x)",
911 be32toh(req->message->xid));
912
913 if (!existing_lease)
914 return 0;
915
916 if (existing_lease->address != req->message->ciaddr)
917 return 0;
918
919 pool_offset = get_pool_offset(server, req->message->ciaddr);
920 if (pool_offset < 0)
921 return 0;
922
923 if (server->bound_leases[pool_offset] == existing_lease) {
924 server->bound_leases[pool_offset] = NULL;
925 hashmap_remove(server->leases_by_client_id, existing_lease);
926 dhcp_lease_free(existing_lease);
c3922c0c 927 }
500792d8 928
c3922c0c
LP
929 return 0;
930 }}
4dc35568
TG
931
932 return 0;
be077570
TG
933}
934
ff734080
TG
935static int server_receive_message(sd_event_source *s, int fd,
936 uint32_t revents, void *userdata) {
be077570 937 _cleanup_free_ DHCPMessage *message = NULL;
3a864fe4 938 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
ff734080
TG
939 sd_dhcp_server *server = userdata;
940 struct iovec iov = {};
941 struct msghdr msg = {
942 .msg_iov = &iov,
943 .msg_iovlen = 1,
3a864fe4
TG
944 .msg_control = cmsgbuf,
945 .msg_controllen = sizeof(cmsgbuf),
ff734080 946 };
3a864fe4 947 struct cmsghdr *cmsg;
4edc2c9b 948 ssize_t buflen, len;
57027d03 949 int r;
ff734080
TG
950
951 assert(server);
952
4edc2c9b
LP
953 buflen = next_datagram_size_fd(fd);
954 if (buflen < 0)
955 return buflen;
ff734080 956
0d43d2fc 957 message = malloc(buflen);
ff734080
TG
958 if (!message)
959 return -ENOMEM;
960
961 iov.iov_base = message;
962 iov.iov_len = buflen;
963
a38d9945 964 len = recvmsg(fd, &msg, 0);
0d43d2fc 965 if (len < 0) {
4c701096 966 if (IN_SET(errno, EAGAIN, EINTR))
0d43d2fc
TG
967 return 0;
968
969 return -errno;
6408ba5f
LP
970 }
971 if ((size_t)len < sizeof(DHCPMessage))
be077570 972 return 0;
ff734080 973
2a1288ff 974 CMSG_FOREACH(cmsg, &msg) {
3a864fe4
TG
975 if (cmsg->cmsg_level == IPPROTO_IP &&
976 cmsg->cmsg_type == IP_PKTINFO &&
977 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
978 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
979
a6f1e036
TG
980 /* TODO figure out if this can be done as a filter on
981 * the socket, like for IPv6 */
b3ec603c 982 if (server->ifindex != info->ipi_ifindex)
3a864fe4
TG
983 return 0;
984
985 break;
986 }
987 }
988
57027d03
LP
989 r = dhcp_server_handle_message(server, message, (size_t) len);
990 if (r < 0)
991 log_dhcp_server_errno(server, r, "Couldn't process incoming message: %m");
992
993 return 0;
ff734080
TG
994}
995
996int sd_dhcp_server_start(sd_dhcp_server *server) {
997 int r;
998
999 assert_return(server, -EINVAL);
1000 assert_return(server->event, -EINVAL);
1001 assert_return(!server->receive_message, -EBUSY);
cfcbb135
LP
1002 assert_return(server->fd_raw < 0, -EBUSY);
1003 assert_return(server->fd < 0, -EBUSY);
20af7091 1004 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
ff734080 1005
8de4a226
TG
1006 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
1007 if (r < 0) {
1008 r = -errno;
1009 sd_dhcp_server_stop(server);
1010 return r;
1011 }
1012 server->fd_raw = r;
1013
3e7b9f76 1014 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
ff734080
TG
1015 if (r < 0) {
1016 sd_dhcp_server_stop(server);
1017 return r;
1018 }
1019 server->fd = r;
1020
1021 r = sd_event_add_io(server->event, &server->receive_message,
1022 server->fd, EPOLLIN,
1023 server_receive_message, server);
1024 if (r < 0) {
1025 sd_dhcp_server_stop(server);
1026 return r;
1027 }
1028
1029 r = sd_event_source_set_priority(server->receive_message,
1030 server->event_priority);
1031 if (r < 0) {
1032 sd_dhcp_server_stop(server);
1033 return r;
1034 }
1035
1036 log_dhcp_server(server, "STARTED");
1037
1038 return 0;
1039}
52750344
TG
1040
1041int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1042 unsigned i;
621ac3d2 1043 int r = 0;
52750344
TG
1044
1045 assert_return(server, -EINVAL);
1046 assert(server->bound_leases);
1047
1048 for (i = 0; i < server->pool_size; i++) {
1049 DHCPLease *lease = server->bound_leases[i];
1050
99634696 1051 if (!lease || lease == &server->invalid_lease)
52750344
TG
1052 continue;
1053
1054 r = server_send_forcerenew(server, lease->address,
1055 lease->gateway,
1056 lease->chaddr);
1057 if (r < 0)
1058 return r;
6408ba5f
LP
1059
1060 log_dhcp_server(server, "FORCERENEW");
52750344
TG
1061 }
1062
1063 return r;
1064}
8eb9058d 1065
64d6c229 1066int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
8eb9058d
LP
1067 int r;
1068
1069 assert_return(server, -EINVAL);
089fb865 1070 assert_return(timezone_is_valid(tz, LOG_DEBUG), -EINVAL);
8eb9058d 1071
64d6c229 1072 if (streq_ptr(tz, server->timezone))
8eb9058d
LP
1073 return 0;
1074
64d6c229 1075 r = free_and_strdup(&server->timezone, tz);
8eb9058d
LP
1076 if (r < 0)
1077 return r;
1078
1079 return 1;
1080}
586ac6f7
LP
1081
1082int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1083 assert_return(server, -EINVAL);
1084
1085 if (t == server->max_lease_time)
1086 return 0;
1087
1088 server->max_lease_time = t;
1089 return 1;
1090}
1091
1092int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1093 assert_return(server, -EINVAL);
1094
1095 if (t == server->default_lease_time)
1096 return 0;
1097
1098 server->default_lease_time = t;
1099 return 1;
1100}
1a04db0f
LP
1101
1102int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
1103 assert_return(server, -EINVAL);
1104 assert_return(dns || n <= 0, -EINVAL);
1105
1106 if (server->n_dns == n &&
1107 memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0)
1108 return 0;
1109
1110 if (n <= 0) {
1111 server->dns = mfree(server->dns);
1112 server->n_dns = 0;
1113 } else {
1114 struct in_addr *c;
1115
1116 c = newdup(struct in_addr, dns, n);
1117 if (!c)
1118 return -ENOMEM;
1119
1120 free(server->dns);
1121 server->dns = c;
1122 server->n_dns = n;
1123 }
1124
1125 return 1;
1126}
1127
1128int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
1129 assert_return(server, -EINVAL);
1130 assert_return(ntp || n <= 0, -EINVAL);
1131
1132 if (server->n_ntp == n &&
1133 memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0)
1134 return 0;
1135
1136 if (n <= 0) {
1137 server->ntp = mfree(server->ntp);
1138 server->n_ntp = 0;
1139 } else {
1140 struct in_addr *c;
1141
1142 c = newdup(struct in_addr, ntp, n);
1143 if (!c)
1144 return -ENOMEM;
1145
1146 free(server->ntp);
1147 server->ntp = c;
1148 server->n_ntp = n;
1149 }
1150
1151 return 1;
1152}
77ff6022
CG
1153
1154int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
1155 assert_return(server, -EINVAL);
1156
1157 if (enabled == server->emit_router)
1158 return 0;
1159
1160 server->emit_router = enabled;
1161
1162 return 1;
1163}