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