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