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