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