]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-server.c
45b813669e527c4d1c86b9f48a21b045bd3dd66c
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-server.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright (C) 2013 Intel Corporation. All rights reserved.
4 Copyright (C) 2014 Tom Gundersen
5 ***/
6
7 #include <sys/ioctl.h>
8
9 #include "sd-dhcp-server.h"
10
11 #include "alloc-util.h"
12 #include "dhcp-internal.h"
13 #include "dhcp-server-internal.h"
14 #include "fd-util.h"
15 #include "in-addr-util.h"
16 #include "sd-id128.h"
17 #include "siphash24.h"
18 #include "string-util.h"
19 #include "unaligned.h"
20
21 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
22 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
23
24 static void dhcp_lease_free(DHCPLease *lease) {
25 if (!lease)
26 return;
27
28 free(lease->client_id.data);
29 free(lease);
30 }
31
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 */
36 int 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
41 assert_return(server, -EINVAL);
42 assert_return(address, -EINVAL);
43 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
44 assert_return(prefixlen <= 32, -ERANGE);
45
46 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
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;
74
75 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
76
77 free(server->bound_leases);
78 server->bound_leases = new0(DHCPLease*, size);
79 if (!server->bound_leases)
80 return -ENOMEM;
81
82 server->pool_offset = offset;
83 server->pool_size = size;
84
85 server->address = address->s_addr;
86 server->netmask = netmask;
87 server->subnet = address->s_addr & netmask;
88
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 */
93 hashmap_clear_with_destructor(server->leases_by_client_id, dhcp_lease_free);
94 }
95
96 return 0;
97 }
98
99 int sd_dhcp_server_is_running(sd_dhcp_server *server) {
100 assert_return(server, false);
101
102 return !!server->receive_message;
103 }
104
105 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
106
107 if (!server)
108 return NULL;
109
110 assert(server->n_ref >= 1);
111 server->n_ref++;
112
113 return server;
114 }
115
116 void client_id_hash_func(const void *p, struct siphash *state) {
117 const DHCPClientId *id = p;
118
119 assert(id);
120 assert(id->length);
121 assert(id->data);
122
123 siphash24_compress(&id->length, sizeof(id->length), state);
124 siphash24_compress(id->data, id->length, state);
125 }
126
127 int 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
142 static const struct hash_ops client_id_hash_ops = {
143 .hash = client_id_hash_func,
144 .compare = client_id_compare_func
145 };
146
147 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
148 DHCPLease *lease;
149
150 if (!server)
151 return NULL;
152
153 assert(server->n_ref >= 1);
154 server->n_ref--;
155
156 if (server->n_ref > 0)
157 return NULL;
158
159 log_dhcp_server(server, "UNREF");
160
161 sd_dhcp_server_stop(server);
162
163 sd_event_unref(server->event);
164
165 free(server->timezone);
166 free(server->dns);
167 free(server->ntp);
168
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);
174 return mfree(server);
175 }
176
177 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
178 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
179
180 assert_return(ret, -EINVAL);
181 assert_return(ifindex > 0, -EINVAL);
182
183 server = new0(sd_dhcp_server, 1);
184 if (!server)
185 return -ENOMEM;
186
187 server->n_ref = 1;
188 server->fd_raw = -1;
189 server->fd = -1;
190 server->address = htobe32(INADDR_ANY);
191 server->netmask = htobe32(INADDR_ANY);
192 server->ifindex = ifindex;
193
194 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
195 if (!server->leases_by_client_id)
196 return -ENOMEM;
197
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);
200
201 *ret = TAKE_PTR(server);
202
203 return 0;
204 }
205
206 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
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
225 int 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
233 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
234 assert_return(server, NULL);
235
236 return server->event;
237 }
238
239 int 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
245 server->fd_raw = safe_close(server->fd_raw);
246 server->fd = safe_close(server->fd);
247
248 log_dhcp_server(server, "STOPPED");
249
250 return 0;
251 }
252
253 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
254 DHCPPacket *packet, size_t len) {
255 union sockaddr_union link = {
256 .ll.sll_family = AF_PACKET,
257 .ll.sll_protocol = htobe16(ETH_P_IP),
258 .ll.sll_ifindex = server->ifindex,
259 .ll.sll_halen = ETH_ALEN,
260 };
261
262 assert(server);
263 assert(server->ifindex > 0);
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,
271 packet->dhcp.yiaddr,
272 DHCP_PORT_CLIENT, len);
273
274 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
275 }
276
277 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
278 uint16_t destination_port,
279 DHCPMessage *message, size_t len) {
280 union sockaddr_union dest = {
281 .in.sin_family = AF_INET,
282 .in.sin_port = htobe16(destination_port),
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;
300
301 assert(server);
302 assert(server->fd >= 0);
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
320 pktinfo->ipi_ifindex = server->ifindex;
321 pktinfo->ipi_spec_dst.s_addr = server->address;
322
323 if (sendmsg(server->fd, &msg, 0) < 0)
324 return -errno;
325
326 return 0;
327 }
328
329 static bool requested_broadcast(DHCPRequest *req) {
330 assert(req);
331
332 return req->message->flags & htobe16(0x8000);
333 }
334
335 int 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;
339 uint16_t destination_port = DHCP_PORT_CLIENT;
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,
349 SD_DHCP_OPTION_SERVER_IDENTIFIER,
350 4, &server->address);
351 if (r < 0)
352 return r;
353
354 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
355 SD_DHCP_OPTION_END, 0, NULL);
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;
384 destination_port = DHCP_PORT_SERVER;
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
390 if (destination != INADDR_ANY)
391 return dhcp_server_send_udp(server, destination,
392 destination_port, &packet->dhcp,
393 sizeof(DHCPMessage) + optoffset);
394 else if (requested_broadcast(req) || type == DHCP_NAK)
395 return dhcp_server_send_udp(server, INADDR_BROADCAST,
396 destination_port, &packet->dhcp,
397 sizeof(DHCPMessage) + optoffset);
398 else
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 */
402 return dhcp_server_send_unicast_raw(server, packet,
403 sizeof(DHCPPacket) + optoffset);
404 }
405
406 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
407 uint8_t type, size_t *_optoffset,
408 DHCPRequest *req) {
409 _cleanup_free_ DHCPPacket *packet = NULL;
410 size_t optoffset = 0;
411 int r;
412
413 assert(server);
414 assert(ret);
415 assert(_optoffset);
416 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
417
418 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
419 if (!packet)
420 return -ENOMEM;
421
422 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
423 be32toh(req->message->xid), type, ARPHRD_ETHER,
424 req->max_optlen, &optoffset);
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;
433 *ret = TAKE_PTR(packet);
434
435 return 0;
436 }
437
438 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
439 be32_t address) {
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
449 packet->dhcp.yiaddr = address;
450
451 lease_time = htobe32(req->lifetime);
452 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
453 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
454 &lease_time);
455 if (r < 0)
456 return r;
457
458 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
459 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
460 if (r < 0)
461 return r;
462
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 }
469
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
477 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
478 be32_t address) {
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
490 lease_time = htobe32(req->lifetime);
491 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
492 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
493 &lease_time);
494 if (r < 0)
495 return r;
496
497 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
498 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
499 if (r < 0)
500 return r;
501
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 }
508
509 if (server->n_dns > 0) {
510 r = dhcp_option_append(
511 &packet->dhcp, req->max_optlen, &offset, 0,
512 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
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,
521 SD_DHCP_OPTION_NTP_SERVER,
522 sizeof(struct in_addr) * server->n_ntp, server->ntp);
523 if (r < 0)
524 return r;
525 }
526
527 if (server->timezone) {
528 r = dhcp_option_append(
529 &packet->dhcp, req->max_optlen, &offset, 0,
530 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
531 strlen(server->timezone), server->timezone);
532 if (r < 0)
533 return r;
534 }
535
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
543 static 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
552 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
553 }
554
555 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
556 be32_t gateway, uint8_t chaddr[]) {
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,
570 DHCP_FORCERENEW, ARPHRD_ETHER,
571 DHCP_MIN_OPTIONS_SIZE, &optoffset);
572 if (r < 0)
573 return r;
574
575 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
576 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
577 if (r < 0)
578 return r;
579
580 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
581
582 r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
583 &packet->dhcp,
584 sizeof(DHCPMessage) + optoffset);
585 if (r < 0)
586 return r;
587
588 return 0;
589 }
590
591 static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
592 DHCPRequest *req = userdata;
593
594 assert(req);
595
596 switch(code) {
597 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
598 if (len == 4)
599 req->lifetime = unaligned_read_be32(option);
600
601 break;
602 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
603 if (len == 4)
604 memcpy(&req->requested_ip, option, sizeof(be32_t));
605
606 break;
607 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
608 if (len == 4)
609 memcpy(&req->server_id, option, sizeof(be32_t));
610
611 break;
612 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
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;
626 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
627
628 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
629 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
630
631 break;
632 }
633
634 return 0;
635 }
636
637 static void dhcp_request_free(DHCPRequest *req) {
638 if (!req)
639 return;
640
641 free(req->client_id.data);
642 free(req);
643 }
644
645 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
646
647 static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
648 assert(req);
649 assert(message);
650
651 req->message = message;
652
653 /* set client id based on MAC address if client did not send an explicit
654 one */
655 if (!req->client_id.data) {
656 void *data;
657
658 data = malloc0(ETH_ALEN + 1);
659 if (!data)
660 return -ENOMEM;
661
662 ((uint8_t*) data)[0] = 0x01;
663 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
664
665 req->client_id.length = ETH_ALEN + 1;
666 req->client_id.data = data;
667 }
668
669 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
670 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
671
672 if (req->lifetime <= 0)
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;
677
678 return 0;
679 }
680
681 static 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
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;
690
691 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
692 }
693
694 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
695
696 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
697 size_t length) {
698 _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
699 _cleanup_free_ char *error_message = NULL;
700 DHCPLease *existing_lease;
701 int type, r;
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
711 req = new0(DHCPRequest, 1);
712 if (!req)
713 return -ENOMEM;
714
715 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
716 if (type < 0)
717 return 0;
718
719 r = ensure_sane_request(server, req, message);
720 if (r < 0)
721 /* this only fails on critical errors */
722 return r;
723
724 existing_lease = hashmap_get(server->leases_by_client_id,
725 &req->client_id);
726
727 switch(type) {
728
729 case DHCP_DISCOVER: {
730 be32_t address = INADDR_ANY;
731 unsigned i;
732
733 log_dhcp_server(server, "DISCOVER (0x%x)",
734 be32toh(req->message->xid));
735
736 if (!server->pool_size)
737 /* no pool allocated */
738 return 0;
739
740 /* for now pick a random free address from the pool */
741 if (existing_lease)
742 address = existing_lease->address;
743 else {
744 struct siphash state;
745 uint64_t hash;
746 uint32_t next_offer;
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
752 siphash24_init(&state, HASH_KEY.bytes);
753 client_id_hash_func(&req->client_id, &state);
754 hash = htole64(siphash24_finalize(&state));
755 next_offer = hash % server->pool_size;
756
757 for (i = 0; i < server->pool_size; i++) {
758 if (!server->bound_leases[next_offer]) {
759 address = server->subnet | htobe32(server->pool_offset + next_offer);
760 break;
761 }
762
763 next_offer = (next_offer + 1) % server->pool_size;
764 }
765 }
766
767 if (address == INADDR_ANY)
768 /* no free addresses left */
769 return 0;
770
771 r = server_send_offer(server, req, address);
772 if (r < 0)
773 /* this only fails on critical errors */
774 return log_dhcp_server_errno(server, r, "Could not send offer: %m");
775
776 log_dhcp_server(server, "OFFER (0x%x)", be32toh(req->message->xid));
777 return DHCP_OFFER;
778 }
779 case DHCP_DECLINE:
780 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
781
782 /* TODO: make sure we don't offer this address again */
783
784 return 1;
785
786 case DHCP_REQUEST: {
787 be32_t address;
788 bool init_reboot = false;
789 int pool_offset;
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
821 /* TODO: check more carefully if IP is correct */
822 address = req->requested_ip;
823 init_reboot = true;
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
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;
843 usec_t time_now = 0;
844
845 if (!existing_lease) {
846 lease = new0(DHCPLease, 1);
847 if (!lease)
848 return -ENOMEM;
849 lease->address = address;
850 lease->client_id.data = memdup(req->client_id.data,
851 req->client_id.length);
852 if (!lease->client_id.data) {
853 free(lease);
854 return -ENOMEM;
855 }
856 lease->client_id.length = req->client_id.length;
857 memcpy(&lease->chaddr, &req->message->chaddr,
858 ETH_ALEN);
859 lease->gateway = req->message->giaddr;
860 } else
861 lease = existing_lease;
862
863 r = sd_event_now(server->event,
864 clock_boottime_or_monotonic(),
865 &time_now);
866 if (r < 0) {
867 if (!existing_lease)
868 dhcp_lease_free(lease);
869 return r;
870 }
871
872 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
873
874 r = server_send_ack(server, req, address);
875 if (r < 0) {
876 /* this only fails on critical errors */
877 log_dhcp_server_errno(server, r, "Could not send ack: %m");
878
879 if (!existing_lease)
880 dhcp_lease_free(lease);
881
882 return r;
883 } else {
884 log_dhcp_server(server, "ACK (0x%x)",
885 be32toh(req->message->xid));
886
887 server->bound_leases[pool_offset] = lease;
888 hashmap_put(server->leases_by_client_id,
889 &lease->client_id, lease);
890
891 return DHCP_ACK;
892 }
893
894 } else if (init_reboot) {
895 r = server_send_nak(server, req);
896 if (r < 0)
897 /* this only fails on critical errors */
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;
902 }
903
904 break;
905 }
906
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);
927 }
928
929 return 0;
930 }}
931
932 return 0;
933 }
934
935 static int server_receive_message(sd_event_source *s, int fd,
936 uint32_t revents, void *userdata) {
937 _cleanup_free_ DHCPMessage *message = NULL;
938 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
939 sd_dhcp_server *server = userdata;
940 struct iovec iov = {};
941 struct msghdr msg = {
942 .msg_iov = &iov,
943 .msg_iovlen = 1,
944 .msg_control = cmsgbuf,
945 .msg_controllen = sizeof(cmsgbuf),
946 };
947 struct cmsghdr *cmsg;
948 ssize_t buflen, len;
949 int r;
950
951 assert(server);
952
953 buflen = next_datagram_size_fd(fd);
954 if (buflen < 0)
955 return buflen;
956
957 message = malloc(buflen);
958 if (!message)
959 return -ENOMEM;
960
961 iov.iov_base = message;
962 iov.iov_len = buflen;
963
964 len = recvmsg(fd, &msg, 0);
965 if (len < 0) {
966 if (IN_SET(errno, EAGAIN, EINTR))
967 return 0;
968
969 return -errno;
970 }
971 if ((size_t)len < sizeof(DHCPMessage))
972 return 0;
973
974 CMSG_FOREACH(cmsg, &msg) {
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
980 /* TODO figure out if this can be done as a filter on
981 * the socket, like for IPv6 */
982 if (server->ifindex != info->ipi_ifindex)
983 return 0;
984
985 break;
986 }
987 }
988
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;
994 }
995
996 int 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);
1002 assert_return(server->fd_raw < 0, -EBUSY);
1003 assert_return(server->fd < 0, -EBUSY);
1004 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1005
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
1014 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
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 }
1040
1041 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1042 unsigned i;
1043 int r = 0;
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
1051 if (!lease || lease == &server->invalid_lease)
1052 continue;
1053
1054 r = server_send_forcerenew(server, lease->address,
1055 lease->gateway,
1056 lease->chaddr);
1057 if (r < 0)
1058 return r;
1059
1060 log_dhcp_server(server, "FORCERENEW");
1061 }
1062
1063 return r;
1064 }
1065
1066 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1067 int r;
1068
1069 assert_return(server, -EINVAL);
1070 assert_return(timezone_is_valid(tz, LOG_DEBUG), -EINVAL);
1071
1072 if (streq_ptr(tz, server->timezone))
1073 return 0;
1074
1075 r = free_and_strdup(&server->timezone, tz);
1076 if (r < 0)
1077 return r;
1078
1079 return 1;
1080 }
1081
1082 int 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
1092 int 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 }
1101
1102 int 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
1128 int 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 }
1153
1154 int 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 }