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