]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-server.c
sd-dhcp-server: Send replies to BOOTP relay server port
[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 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
472 SD_DHCP_OPTION_ROUTER, 4, &server->address);
473 if (r < 0)
474 return r;
475
476 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
477 if (r < 0)
478 return r;
479
480 return 0;
481 }
482
483 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
484 be32_t address) {
485 _cleanup_free_ DHCPPacket *packet = NULL;
486 size_t offset;
487 be32_t lease_time;
488 int r;
489
490 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
491 if (r < 0)
492 return r;
493
494 packet->dhcp.yiaddr = address;
495
496 lease_time = htobe32(req->lifetime);
497 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
498 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
499 &lease_time);
500 if (r < 0)
501 return r;
502
503 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
504 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
505 if (r < 0)
506 return r;
507
508 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
509 SD_DHCP_OPTION_ROUTER, 4, &server->address);
510 if (r < 0)
511 return r;
512
513 if (server->n_dns > 0) {
514 r = dhcp_option_append(
515 &packet->dhcp, req->max_optlen, &offset, 0,
516 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
517 sizeof(struct in_addr) * server->n_dns, server->dns);
518 if (r < 0)
519 return r;
520 }
521
522 if (server->n_ntp > 0) {
523 r = dhcp_option_append(
524 &packet->dhcp, req->max_optlen, &offset, 0,
525 SD_DHCP_OPTION_NTP_SERVER,
526 sizeof(struct in_addr) * server->n_ntp, server->ntp);
527 if (r < 0)
528 return r;
529 }
530
531 if (server->timezone) {
532 r = dhcp_option_append(
533 &packet->dhcp, req->max_optlen, &offset, 0,
534 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
535 strlen(server->timezone), server->timezone);
536 if (r < 0)
537 return r;
538 }
539
540 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
541 if (r < 0)
542 return r;
543
544 return 0;
545 }
546
547 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
548 _cleanup_free_ DHCPPacket *packet = NULL;
549 size_t offset;
550 int r;
551
552 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
553 if (r < 0)
554 return r;
555
556 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
557 }
558
559 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
560 be32_t gateway, uint8_t chaddr[]) {
561 _cleanup_free_ DHCPPacket *packet = NULL;
562 size_t optoffset = 0;
563 int r;
564
565 assert(server);
566 assert(address != INADDR_ANY);
567 assert(chaddr);
568
569 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
570 if (!packet)
571 return -ENOMEM;
572
573 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
574 DHCP_FORCERENEW, ARPHRD_ETHER,
575 DHCP_MIN_OPTIONS_SIZE, &optoffset);
576 if (r < 0)
577 return r;
578
579 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
580 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
581 if (r < 0)
582 return r;
583
584 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
585
586 r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
587 &packet->dhcp,
588 sizeof(DHCPMessage) + optoffset);
589 if (r < 0)
590 return r;
591
592 return 0;
593 }
594
595 static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
596 DHCPRequest *req = userdata;
597
598 assert(req);
599
600 switch(code) {
601 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
602 if (len == 4)
603 req->lifetime = be32toh(*(be32_t*)option);
604
605 break;
606 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
607 if (len == 4)
608 req->requested_ip = *(be32_t*)option;
609
610 break;
611 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
612 if (len == 4)
613 req->server_id = *(be32_t*)option;
614
615 break;
616 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
617 if (len >= 2) {
618 uint8_t *data;
619
620 data = memdup(option, len);
621 if (!data)
622 return -ENOMEM;
623
624 free(req->client_id.data);
625 req->client_id.data = data;
626 req->client_id.length = len;
627 }
628
629 break;
630 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
631 if (len == 2)
632 req->max_optlen = be16toh(*(be16_t*)option) -
633 - sizeof(DHCPPacket);
634
635 break;
636 }
637
638 return 0;
639 }
640
641 static void dhcp_request_free(DHCPRequest *req) {
642 if (!req)
643 return;
644
645 free(req->client_id.data);
646 free(req);
647 }
648
649 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
650 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
651
652 static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
653 assert(req);
654 assert(message);
655
656 req->message = message;
657
658 /* set client id based on MAC address if client did not send an explicit
659 one */
660 if (!req->client_id.data) {
661 void *data;
662
663 data = malloc0(ETH_ALEN + 1);
664 if (!data)
665 return -ENOMEM;
666
667 ((uint8_t*) data)[0] = 0x01;
668 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
669
670 req->client_id.length = ETH_ALEN + 1;
671 req->client_id.data = data;
672 }
673
674 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
675 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
676
677 if (req->lifetime <= 0)
678 req->lifetime = MAX(1ULL, server->default_lease_time);
679
680 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
681 req->lifetime = server->max_lease_time;
682
683 return 0;
684 }
685
686 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
687 assert(server);
688
689 if (!server->pool_size)
690 return -EINVAL;
691
692 if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
693 be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
694 return -ERANGE;
695
696 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
697 }
698
699 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
700
701 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
702 size_t length) {
703 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
704 _cleanup_free_ char *error_message = NULL;
705 DHCPLease *existing_lease;
706 int type, r;
707
708 assert(server);
709 assert(message);
710
711 if (message->op != BOOTREQUEST ||
712 message->htype != ARPHRD_ETHER ||
713 message->hlen != ETHER_ADDR_LEN)
714 return 0;
715
716 req = new0(DHCPRequest, 1);
717 if (!req)
718 return -ENOMEM;
719
720 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
721 if (type < 0)
722 return 0;
723
724 r = ensure_sane_request(server, req, message);
725 if (r < 0)
726 /* this only fails on critical errors */
727 return r;
728
729 existing_lease = hashmap_get(server->leases_by_client_id,
730 &req->client_id);
731
732 switch(type) {
733
734 case DHCP_DISCOVER: {
735 be32_t address = INADDR_ANY;
736 unsigned i;
737
738 log_dhcp_server(server, "DISCOVER (0x%x)",
739 be32toh(req->message->xid));
740
741 if (!server->pool_size)
742 /* no pool allocated */
743 return 0;
744
745 /* for now pick a random free address from the pool */
746 if (existing_lease)
747 address = existing_lease->address;
748 else {
749 struct siphash state;
750 uint64_t hash;
751 uint32_t next_offer;
752
753 /* even with no persistence of leases, we try to offer the same client
754 the same IP address. we do this by using the hash of the client id
755 as the offset into the pool of leases when finding the next free one */
756
757 siphash24_init(&state, HASH_KEY.bytes);
758 client_id_hash_func(&req->client_id, &state);
759 hash = htole64(siphash24_finalize(&state));
760 next_offer = hash % server->pool_size;
761
762 for (i = 0; i < server->pool_size; i++) {
763 if (!server->bound_leases[next_offer]) {
764 address = server->subnet | htobe32(server->pool_offset + next_offer);
765 break;
766 } else
767 next_offer = (next_offer + 1) % server->pool_size;
768 }
769 }
770
771 if (address == INADDR_ANY)
772 /* no free addresses left */
773 return 0;
774
775 r = server_send_offer(server, req, address);
776 if (r < 0) {
777 /* this only fails on critical errors */
778 log_dhcp_server(server, "could not send offer: %s",
779 strerror(-r));
780 return r;
781 } else {
782 log_dhcp_server(server, "OFFER (0x%x)",
783 be32toh(req->message->xid));
784 return DHCP_OFFER;
785 }
786
787 break;
788 }
789 case DHCP_DECLINE:
790 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
791
792 /* TODO: make sure we don't offer this address again */
793
794 return 1;
795
796 case DHCP_REQUEST: {
797 be32_t address;
798 bool init_reboot = false;
799 int pool_offset;
800
801 /* see RFC 2131, section 4.3.2 */
802
803 if (req->server_id) {
804 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
805 be32toh(req->message->xid));
806
807 /* SELECTING */
808 if (req->server_id != server->address)
809 /* client did not pick us */
810 return 0;
811
812 if (req->message->ciaddr)
813 /* this MUST be zero */
814 return 0;
815
816 if (!req->requested_ip)
817 /* this must be filled in with the yiaddr
818 from the chosen OFFER */
819 return 0;
820
821 address = req->requested_ip;
822 } else if (req->requested_ip) {
823 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
824 be32toh(req->message->xid));
825
826 /* INIT-REBOOT */
827 if (req->message->ciaddr)
828 /* this MUST be zero */
829 return 0;
830
831 /* TODO: check more carefully if IP is correct */
832 address = req->requested_ip;
833 init_reboot = true;
834 } else {
835 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
836 be32toh(req->message->xid));
837
838 /* REBINDING / RENEWING */
839 if (!req->message->ciaddr)
840 /* this MUST be filled in with clients IP address */
841 return 0;
842
843 address = req->message->ciaddr;
844 }
845
846 pool_offset = get_pool_offset(server, address);
847
848 /* verify that the requested address is from the pool, and either
849 owned by the current client or free */
850 if (pool_offset >= 0 &&
851 server->bound_leases[pool_offset] == existing_lease) {
852 DHCPLease *lease;
853 usec_t time_now = 0;
854
855 if (!existing_lease) {
856 lease = new0(DHCPLease, 1);
857 lease->address = req->requested_ip;
858 lease->client_id.data = memdup(req->client_id.data,
859 req->client_id.length);
860 if (!lease->client_id.data) {
861 free(lease);
862 return -ENOMEM;
863 }
864 lease->client_id.length = req->client_id.length;
865 memcpy(&lease->chaddr, &req->message->chaddr,
866 ETH_ALEN);
867 lease->gateway = req->message->giaddr;
868 } else
869 lease = existing_lease;
870
871 r = sd_event_now(server->event,
872 clock_boottime_or_monotonic(),
873 &time_now);
874 if (r < 0) {
875 if (!existing_lease)
876 dhcp_lease_free(lease);
877 return r;
878 }
879
880 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
881
882 r = server_send_ack(server, req, address);
883 if (r < 0) {
884 /* this only fails on critical errors */
885 log_dhcp_server(server, "could not send ack: %s",
886 strerror(-r));
887
888 if (!existing_lease)
889 dhcp_lease_free(lease);
890
891 return r;
892 } else {
893 log_dhcp_server(server, "ACK (0x%x)",
894 be32toh(req->message->xid));
895
896 server->bound_leases[pool_offset] = lease;
897 hashmap_put(server->leases_by_client_id,
898 &lease->client_id, lease);
899
900 return DHCP_ACK;
901 }
902 } else if (init_reboot) {
903 r = server_send_nak(server, req);
904 if (r < 0) {
905 /* this only fails on critical errors */
906 log_dhcp_server(server, "could not send nak: %s",
907 strerror(-r));
908 return r;
909 } else {
910 log_dhcp_server(server, "NAK (0x%x)",
911 be32toh(req->message->xid));
912 return DHCP_NAK;
913 }
914 }
915
916 break;
917 }
918
919 case DHCP_RELEASE: {
920 int pool_offset;
921
922 log_dhcp_server(server, "RELEASE (0x%x)",
923 be32toh(req->message->xid));
924
925 if (!existing_lease)
926 return 0;
927
928 if (existing_lease->address != req->message->ciaddr)
929 return 0;
930
931 pool_offset = get_pool_offset(server, req->message->ciaddr);
932 if (pool_offset < 0)
933 return 0;
934
935 if (server->bound_leases[pool_offset] == existing_lease) {
936 server->bound_leases[pool_offset] = NULL;
937 hashmap_remove(server->leases_by_client_id, existing_lease);
938 dhcp_lease_free(existing_lease);
939
940 return 1;
941 } else
942 return 0;
943 }
944 }
945
946 return 0;
947 }
948
949 static int server_receive_message(sd_event_source *s, int fd,
950 uint32_t revents, void *userdata) {
951 _cleanup_free_ DHCPMessage *message = NULL;
952 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
953 sd_dhcp_server *server = userdata;
954 struct iovec iov = {};
955 struct msghdr msg = {
956 .msg_iov = &iov,
957 .msg_iovlen = 1,
958 .msg_control = cmsgbuf,
959 .msg_controllen = sizeof(cmsgbuf),
960 };
961 struct cmsghdr *cmsg;
962 ssize_t buflen, len;
963
964 assert(server);
965
966 buflen = next_datagram_size_fd(fd);
967 if (buflen < 0)
968 return buflen;
969
970 message = malloc(buflen);
971 if (!message)
972 return -ENOMEM;
973
974 iov.iov_base = message;
975 iov.iov_len = buflen;
976
977 len = recvmsg(fd, &msg, 0);
978 if (len < 0) {
979 if (errno == EAGAIN || errno == EINTR)
980 return 0;
981
982 return -errno;
983 } else if ((size_t)len < sizeof(DHCPMessage))
984 return 0;
985
986 CMSG_FOREACH(cmsg, &msg) {
987 if (cmsg->cmsg_level == IPPROTO_IP &&
988 cmsg->cmsg_type == IP_PKTINFO &&
989 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
990 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
991
992 /* TODO figure out if this can be done as a filter on
993 * the socket, like for IPv6 */
994 if (server->ifindex != info->ipi_ifindex)
995 return 0;
996
997 break;
998 }
999 }
1000
1001 return dhcp_server_handle_message(server, message, (size_t)len);
1002 }
1003
1004 int sd_dhcp_server_start(sd_dhcp_server *server) {
1005 int r;
1006
1007 assert_return(server, -EINVAL);
1008 assert_return(server->event, -EINVAL);
1009 assert_return(!server->receive_message, -EBUSY);
1010 assert_return(server->fd_raw == -1, -EBUSY);
1011 assert_return(server->fd == -1, -EBUSY);
1012 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1013
1014 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
1015 if (r < 0) {
1016 r = -errno;
1017 sd_dhcp_server_stop(server);
1018 return r;
1019 }
1020 server->fd_raw = r;
1021
1022 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
1023 if (r < 0) {
1024 sd_dhcp_server_stop(server);
1025 return r;
1026 }
1027 server->fd = r;
1028
1029 r = sd_event_add_io(server->event, &server->receive_message,
1030 server->fd, EPOLLIN,
1031 server_receive_message, server);
1032 if (r < 0) {
1033 sd_dhcp_server_stop(server);
1034 return r;
1035 }
1036
1037 r = sd_event_source_set_priority(server->receive_message,
1038 server->event_priority);
1039 if (r < 0) {
1040 sd_dhcp_server_stop(server);
1041 return r;
1042 }
1043
1044 log_dhcp_server(server, "STARTED");
1045
1046 return 0;
1047 }
1048
1049 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1050 unsigned i;
1051 int r = 0;
1052
1053 assert_return(server, -EINVAL);
1054 assert(server->bound_leases);
1055
1056 for (i = 0; i < server->pool_size; i++) {
1057 DHCPLease *lease = server->bound_leases[i];
1058
1059 if (!lease || lease == &server->invalid_lease)
1060 continue;
1061
1062 r = server_send_forcerenew(server, lease->address,
1063 lease->gateway,
1064 lease->chaddr);
1065 if (r < 0)
1066 return r;
1067 else
1068 log_dhcp_server(server, "FORCERENEW");
1069 }
1070
1071 return r;
1072 }
1073
1074 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1075 int r;
1076
1077 assert_return(server, -EINVAL);
1078 assert_return(timezone_is_valid(tz), -EINVAL);
1079
1080 if (streq_ptr(tz, server->timezone))
1081 return 0;
1082
1083 r = free_and_strdup(&server->timezone, tz);
1084 if (r < 0)
1085 return r;
1086
1087 return 1;
1088 }
1089
1090 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1091 assert_return(server, -EINVAL);
1092
1093 if (t == server->max_lease_time)
1094 return 0;
1095
1096 server->max_lease_time = t;
1097 return 1;
1098 }
1099
1100 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1101 assert_return(server, -EINVAL);
1102
1103 if (t == server->default_lease_time)
1104 return 0;
1105
1106 server->default_lease_time = t;
1107 return 1;
1108 }
1109
1110 int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
1111 assert_return(server, -EINVAL);
1112 assert_return(dns || n <= 0, -EINVAL);
1113
1114 if (server->n_dns == n &&
1115 memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0)
1116 return 0;
1117
1118 if (n <= 0) {
1119 server->dns = mfree(server->dns);
1120 server->n_dns = 0;
1121 } else {
1122 struct in_addr *c;
1123
1124 c = newdup(struct in_addr, dns, n);
1125 if (!c)
1126 return -ENOMEM;
1127
1128 free(server->dns);
1129 server->dns = c;
1130 server->n_dns = n;
1131 }
1132
1133 return 1;
1134 }
1135
1136 int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
1137 assert_return(server, -EINVAL);
1138 assert_return(ntp || n <= 0, -EINVAL);
1139
1140 if (server->n_ntp == n &&
1141 memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0)
1142 return 0;
1143
1144 if (n <= 0) {
1145 server->ntp = mfree(server->ntp);
1146 server->n_ntp = 0;
1147 } else {
1148 struct in_addr *c;
1149
1150 c = newdup(struct in_addr, ntp, n);
1151 if (!c)
1152 return -ENOMEM;
1153
1154 free(server->ntp);
1155 server->ntp = c;
1156 server->n_ntp = n;
1157 }
1158
1159 return 1;
1160 }