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