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