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