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