chiark / gitweb /
1df89dc65111d2ece72766bb9e2cce203b8aef96
[elogind.git] / src / libsystemd / sd-dhcp-client.c
1 /***
2   This file is part of systemd.
3
4   Copyright (C) 2013 Intel Corporation. All rights reserved.
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <net/ethernet.h>
25 #include <sys/param.h>
26
27 #include "util.h"
28 #include "list.h"
29
30 #include "dhcp-protocol.h"
31 #include "dhcp-internal.h"
32 #include "sd-dhcp-client.h"
33
34 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
35
36 struct DHCPLease {
37         uint32_t t1;
38         uint32_t t2;
39         uint32_t lifetime;
40         be32_t address;
41         be32_t server_address;
42         be32_t subnet_mask;
43         be32_t router;
44         struct in_addr **dns;
45 };
46
47 typedef struct DHCPLease DHCPLease;
48
49 struct sd_dhcp_client {
50         DHCPState state;
51         sd_event *event;
52         sd_event_source *timeout_resend;
53         int index;
54         int fd;
55         union sockaddr_union link;
56         sd_event_source *receive_message;
57         uint8_t *req_opts;
58         size_t req_opts_allocated;
59         size_t req_opts_size;
60         be32_t last_addr;
61         struct ether_addr mac_addr;
62         uint32_t xid;
63         usec_t start_time;
64         unsigned int attempt;
65         usec_t request_sent;
66         sd_event_source *timeout_t1;
67         sd_event_source *timeout_t2;
68         sd_event_source *timeout_expire;
69         sd_dhcp_client_cb_t cb;
70         void *userdata;
71         DHCPLease *lease;
72 };
73
74 static const uint8_t default_req_opts[] = {
75         DHCP_OPTION_SUBNET_MASK,
76         DHCP_OPTION_ROUTER,
77         DHCP_OPTION_HOST_NAME,
78         DHCP_OPTION_DOMAIN_NAME,
79         DHCP_OPTION_DOMAIN_NAME_SERVER,
80         DHCP_OPTION_NTP_SERVER,
81 };
82
83 static int client_receive_message(sd_event_source *s, int fd,
84                                   uint32_t revents, void *userdata);
85
86 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
87                                 void *userdata)
88 {
89         assert_return(client, -EINVAL);
90
91         client->cb = cb;
92         client->userdata = userdata;
93
94         return 0;
95 }
96
97 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option)
98 {
99         size_t i;
100
101         assert_return(client, -EINVAL);
102         assert_return (client->state == DHCP_STATE_INIT, -EBUSY);
103
104         switch(option) {
105         case DHCP_OPTION_PAD:
106         case DHCP_OPTION_OVERLOAD:
107         case DHCP_OPTION_MESSAGE_TYPE:
108         case DHCP_OPTION_PARAMETER_REQUEST_LIST:
109         case DHCP_OPTION_END:
110                 return -EINVAL;
111
112         default:
113                 break;
114         }
115
116         for (i = 0; i < client->req_opts_size; i++)
117                 if (client->req_opts[i] == option)
118                         return -EEXIST;
119
120         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
121                             client->req_opts_size + 1))
122                 return -ENOMEM;
123
124         client->req_opts[client->req_opts_size++] = option;
125
126         return 0;
127 }
128
129 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
130                                        const struct in_addr *last_addr)
131 {
132         assert_return(client, -EINVAL);
133         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
134
135         if (last_addr)
136                 client->last_addr = last_addr->s_addr;
137         else
138                 client->last_addr = INADDR_ANY;
139
140         return 0;
141 }
142
143 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index)
144 {
145         assert_return(client, -EINVAL);
146         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
147         assert_return(interface_index >= -1, -EINVAL);
148
149         client->index = interface_index;
150
151         return 0;
152 }
153
154 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
155                            const struct ether_addr *addr)
156 {
157         assert_return(client, -EINVAL);
158         assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
159
160         memcpy(&client->mac_addr, addr, ETH_ALEN);
161
162         return 0;
163 }
164
165 int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr)
166 {
167         assert_return(client, -EINVAL);
168         assert_return(addr, -EINVAL);
169
170         switch (client->state) {
171         case DHCP_STATE_INIT:
172         case DHCP_STATE_SELECTING:
173         case DHCP_STATE_INIT_REBOOT:
174         case DHCP_STATE_REBOOTING:
175         case DHCP_STATE_REQUESTING:
176                 return -EADDRNOTAVAIL;
177
178         case DHCP_STATE_BOUND:
179         case DHCP_STATE_RENEWING:
180         case DHCP_STATE_REBINDING:
181                 addr->s_addr = client->lease->address;
182
183                 break;
184         }
185
186         return 0;
187 }
188
189 int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr)
190 {
191         assert_return(client, -EINVAL);
192         assert_return(addr, -EINVAL);
193
194         switch (client->state) {
195         case DHCP_STATE_INIT:
196         case DHCP_STATE_SELECTING:
197         case DHCP_STATE_INIT_REBOOT:
198         case DHCP_STATE_REBOOTING:
199         case DHCP_STATE_REQUESTING:
200                 return -EADDRNOTAVAIL;
201
202         case DHCP_STATE_BOUND:
203         case DHCP_STATE_RENEWING:
204         case DHCP_STATE_REBINDING:
205                 addr->s_addr = client->lease->subnet_mask;
206
207                 break;
208         }
209
210         return 0;
211 }
212
213 int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr)
214 {
215         assert_return(client, -EINVAL);
216         assert_return(addr, -EINVAL);
217
218         switch (client->state) {
219         case DHCP_STATE_INIT:
220         case DHCP_STATE_SELECTING:
221         case DHCP_STATE_INIT_REBOOT:
222         case DHCP_STATE_REBOOTING:
223         case DHCP_STATE_REQUESTING:
224                 return -EADDRNOTAVAIL;
225
226         case DHCP_STATE_BOUND:
227         case DHCP_STATE_RENEWING:
228         case DHCP_STATE_REBINDING:
229                 if (client->lease->dns)
230                         *addr = client->lease->dns;
231                 else
232                         return -ENOENT;
233
234                 break;
235         }
236
237         return 0;
238 }
239
240 int sd_dhcp_client_prefixlen(const struct in_addr *addr)
241 {
242         int len = 0;
243         uint32_t mask;
244
245         assert_return(addr, -EADDRNOTAVAIL);
246
247         mask = be32toh(addr->s_addr);
248         while (mask) {
249                 len++;
250                 mask = mask << 1;
251         }
252
253         return len;
254 }
255
256 int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr)
257 {
258         assert_return(client, -EINVAL);
259         assert_return(addr, -EINVAL);
260
261         switch (client->state) {
262         case DHCP_STATE_INIT:
263         case DHCP_STATE_SELECTING:
264         case DHCP_STATE_INIT_REBOOT:
265         case DHCP_STATE_REBOOTING:
266         case DHCP_STATE_REQUESTING:
267                 return -EADDRNOTAVAIL;
268
269         case DHCP_STATE_BOUND:
270         case DHCP_STATE_RENEWING:
271         case DHCP_STATE_REBINDING:
272                 addr->s_addr = client->lease->router;
273
274                 break;
275         }
276
277         return 0;
278 }
279
280 static int client_notify(sd_dhcp_client *client, int event)
281 {
282         if (client->cb)
283                 client->cb(client, event, client->userdata);
284
285         return 0;
286 }
287
288 static void in_addrs_free(struct in_addr **addrs) {
289         unsigned i;
290
291         if (!addrs)
292                 return;
293
294         for (i = 0; addrs[i]; i++)
295                 free(addrs[i]);
296
297         free(addrs);
298 }
299
300 static int client_stop(sd_dhcp_client *client, int error)
301 {
302         assert_return(client, -EINVAL);
303
304         client->receive_message =
305                 sd_event_source_unref(client->receive_message);
306
307         if (client->fd >= 0)
308                 close(client->fd);
309         client->fd = -1;
310
311         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
312
313         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
314         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
315         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
316
317         client->attempt = 1;
318
319         client_notify(client, error);
320
321         switch (client->state) {
322
323         case DHCP_STATE_INIT:
324         case DHCP_STATE_SELECTING:
325         case DHCP_STATE_REQUESTING:
326         case DHCP_STATE_BOUND:
327
328                 client->start_time = 0;
329                 client->state = DHCP_STATE_INIT;
330                 break;
331
332         case DHCP_STATE_INIT_REBOOT:
333         case DHCP_STATE_REBOOTING:
334         case DHCP_STATE_RENEWING:
335         case DHCP_STATE_REBINDING:
336
337                 break;
338         }
339
340         if (client->lease) {
341                 in_addrs_free(client->lease->dns);
342                 free(client->lease);
343                 client->lease = NULL;
344         }
345
346         return 0;
347 }
348
349 static int client_packet_init(sd_dhcp_client *client, uint8_t type,
350                               DHCPMessage *message, uint16_t secs,
351                               uint8_t **opt, size_t *optlen)
352 {
353         int err;
354         be16_t max_size;
355
356         *opt = (uint8_t *)(message + 1);
357
358         if (*optlen < 4)
359                 return -ENOBUFS;
360         *optlen -= 4;
361
362         message->op = BOOTREQUEST;
363         message->htype = 1;
364         message->hlen = ETHER_ADDR_LEN;
365         message->xid = htobe32(client->xid);
366
367         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
368            refuse to issue an DHCP lease if 'secs' is set to zero */
369         message->secs = htobe16(secs);
370
371         if (client->state == DHCP_STATE_RENEWING ||
372             client->state == DHCP_STATE_REBINDING)
373                 message->ciaddr = client->lease->address;
374
375         memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN);
376         (*opt)[0] = 0x63;
377         (*opt)[1] = 0x82;
378         (*opt)[2] = 0x53;
379         (*opt)[3] = 0x63;
380
381         *opt += 4;
382
383         err = dhcp_option_append(opt, optlen, DHCP_OPTION_MESSAGE_TYPE, 1,
384                                  &type);
385         if (err < 0)
386                 return err;
387
388         /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
389            Identifier option is not set */
390         err = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
391                                  ETH_ALEN, &client->mac_addr);
392         if (err < 0)
393                 return err;
394
395         if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
396                 err = dhcp_option_append(opt, optlen,
397                                          DHCP_OPTION_PARAMETER_REQUEST_LIST,
398                                          client->req_opts_size,
399                                          client->req_opts);
400                 if (err < 0)
401                         return err;
402
403                 /* Some DHCP servers will send bigger DHCP packets than the
404                    defined default size unless the Maximum Messge Size option
405                    is explicitely set */
406                 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
407                                    DHCP_CLIENT_MIN_OPTIONS_SIZE);
408                 err = dhcp_option_append(opt, optlen,
409                                          DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
410                                          2, &max_size);
411                 if (err < 0)
412                         return err;
413         }
414
415         return 0;
416 }
417
418 static uint16_t client_checksum(void *buf, int len)
419 {
420         uint32_t sum;
421         uint16_t *check;
422         int i;
423         uint8_t *odd;
424
425         sum = 0;
426         check = buf;
427
428         for (i = 0; i < len / 2 ; i++)
429                 sum += check[i];
430
431         if (len & 0x01) {
432                 odd = buf;
433                 sum += odd[len - 1];
434         }
435
436         while (sum >> 16)
437                 sum = (sum & 0xffff) + (sum >> 16);
438
439         return ~sum;
440 }
441
442 static void client_append_ip_headers(DHCPPacket *packet, uint16_t len)
443 {
444         packet->ip.version = IPVERSION;
445         packet->ip.ihl = DHCP_IP_SIZE / 4;
446         packet->ip.tot_len = htobe16(len);
447
448         packet->ip.protocol = IPPROTO_UDP;
449         packet->ip.saddr = INADDR_ANY;
450         packet->ip.daddr = INADDR_BROADCAST;
451
452         packet->udp.source = htobe16(DHCP_PORT_CLIENT);
453         packet->udp.dest = htobe16(DHCP_PORT_SERVER);
454         packet->udp.len = htobe16(len - DHCP_IP_SIZE);
455
456         packet->ip.check = packet->udp.len;
457         packet->udp.check = client_checksum(&packet->ip.ttl, len - 8);
458
459         packet->ip.ttl = IPDEFTTL;
460         packet->ip.check = 0;
461         packet->ip.check = client_checksum(&packet->ip, DHCP_IP_SIZE);
462 }
463
464 static int client_send_discover(sd_dhcp_client *client, uint16_t secs)
465 {
466         int err = 0;
467         _cleanup_free_ DHCPPacket *discover;
468         size_t optlen, len;
469         uint8_t *opt;
470
471         optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
472         len = sizeof(DHCPPacket) + optlen;
473
474         discover = malloc0(len);
475
476         if (!discover)
477                 return -ENOMEM;
478
479         err = client_packet_init(client, DHCP_DISCOVER, &discover->dhcp,
480                                  secs, &opt, &optlen);
481         if (err < 0)
482                 return err;
483
484         if (client->last_addr != INADDR_ANY) {
485                 err = dhcp_option_append(&opt, &optlen,
486                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
487                                          4, &client->last_addr);
488                 if (err < 0)
489                         return err;
490         }
491
492         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
493         if (err < 0)
494                 return err;
495
496         client_append_ip_headers(discover, len);
497
498         err = dhcp_network_send_raw_socket(client->fd, &client->link,
499                                            discover, len);
500
501         return err;
502 }
503
504 static int client_send_request(sd_dhcp_client *client, uint16_t secs)
505 {
506         _cleanup_free_ DHCPPacket *request;
507         size_t optlen, len;
508         int err;
509         uint8_t *opt;
510
511         optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
512         len = DHCP_MESSAGE_SIZE + optlen;
513
514         request = malloc0(len);
515         if (!request)
516                 return -ENOMEM;
517
518         err = client_packet_init(client, DHCP_REQUEST, &request->dhcp, secs,
519                                  &opt, &optlen);
520         if (err < 0)
521                 return err;
522
523         if (client->state == DHCP_STATE_REQUESTING) {
524                 err = dhcp_option_append(&opt, &optlen,
525                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
526                                          4, &client->lease->address);
527                 if (err < 0)
528                         return err;
529
530                 err = dhcp_option_append(&opt, &optlen,
531                                          DHCP_OPTION_SERVER_IDENTIFIER,
532                                          4, &client->lease->server_address);
533                 if (err < 0)
534                         return err;
535         }
536
537         err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
538         if (err < 0)
539                 return err;
540
541         if (client->state == DHCP_STATE_RENEWING) {
542                 err = dhcp_network_send_udp_socket(client->fd,
543                                                    client->lease->server_address,
544                                                    &request->dhcp,
545                                                    len - DHCP_IP_UDP_SIZE);
546         } else {
547                 client_append_ip_headers(request, len);
548
549                 err = dhcp_network_send_raw_socket(client->fd, &client->link,
550                                                    request, len);
551         }
552
553         return err;
554 }
555
556 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
557                                  void *userdata)
558 {
559         sd_dhcp_client *client = userdata;
560         usec_t next_timeout = 0;
561         uint32_t time_left;
562         uint16_t secs;
563         int err = 0;
564
565         switch (client->state) {
566         case DHCP_STATE_RENEWING:
567
568                 time_left = (client->lease->t2 - client->lease->t1)/2;
569                 if (time_left < 60)
570                         time_left = 60;
571
572                 next_timeout = usec + time_left * USEC_PER_SEC;
573
574                 break;
575
576         case DHCP_STATE_REBINDING:
577
578                 time_left = (client->lease->lifetime - client->lease->t2)/2;
579                 if (time_left < 60)
580                         time_left = 60;
581
582                 next_timeout = usec + time_left * USEC_PER_SEC;
583                 break;
584
585         case DHCP_STATE_INIT:
586         case DHCP_STATE_INIT_REBOOT:
587         case DHCP_STATE_REBOOTING:
588         case DHCP_STATE_SELECTING:
589         case DHCP_STATE_REQUESTING:
590         case DHCP_STATE_BOUND:
591
592                 if (client->attempt < 64)
593                         client->attempt *= 2;
594
595                 next_timeout = usec + (client->attempt - 1) * USEC_PER_SEC;
596
597                 break;
598         }
599
600         next_timeout += (random_u32() & 0x1fffff);
601
602         err = sd_event_add_monotonic(client->event, next_timeout,
603                                      10 * USEC_PER_MSEC,
604                                      client_timeout_resend, client,
605                                      &client->timeout_resend);
606         if (err < 0)
607                 goto error;
608
609         secs = (usec - client->start_time) / USEC_PER_SEC;
610
611         switch (client->state) {
612         case DHCP_STATE_INIT:
613                 err = client_send_discover(client, secs);
614                 if (err >= 0) {
615                         client->state = DHCP_STATE_SELECTING;
616                         client->attempt = 1;
617                 } else {
618                         if (client->attempt >= 64)
619                                 goto error;
620                 }
621
622                 break;
623
624         case DHCP_STATE_SELECTING:
625                 err = client_send_discover(client, secs);
626                 if (err < 0 && client->attempt >= 64)
627                         goto error;
628
629                 break;
630
631         case DHCP_STATE_REQUESTING:
632         case DHCP_STATE_RENEWING:
633         case DHCP_STATE_REBINDING:
634                 err = client_send_request(client, secs);
635                 if (err < 0 && client->attempt >= 64)
636                          goto error;
637
638                 client->request_sent = usec;
639
640                 break;
641
642         case DHCP_STATE_INIT_REBOOT:
643         case DHCP_STATE_REBOOTING:
644         case DHCP_STATE_BOUND:
645
646                 break;
647         }
648
649         return 0;
650
651 error:
652         client_stop(client, err);
653
654         /* Errors were dealt with when stopping the client, don't spill
655            errors into the event loop handler */
656         return 0;
657 }
658
659 static int client_initialize_events(sd_dhcp_client *client, usec_t usec)
660 {
661         int r;
662
663         r = sd_event_add_io(client->event, client->fd, EPOLLIN,
664                             client_receive_message, client,
665                             &client->receive_message);
666         if (r < 0)
667                 goto error;
668
669         r = sd_event_add_monotonic(client->event, usec, 0,
670                                    client_timeout_resend, client,
671                                    &client->timeout_resend);
672
673 error:
674         if (r < 0)
675                 client_stop(client, r);
676
677         return 0;
678
679 }
680
681 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
682                                  void *userdata)
683 {
684         sd_dhcp_client *client = userdata;
685
686         client_stop(client, DHCP_EVENT_EXPIRED);
687
688         return 0;
689 }
690
691 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
692 {
693         sd_dhcp_client *client = userdata;
694         int r;
695
696         if (client->fd >= 0) {
697                 client->receive_message =
698                         sd_event_source_unref(client->receive_message);
699                 close(client->fd);
700                 client->fd = -1;
701         }
702
703         client->state = DHCP_STATE_REBINDING;
704         client->attempt = 1;
705
706         r = dhcp_network_bind_raw_socket(client->index, &client->link);
707         if (r < 0) {
708                 client_stop(client, r);
709                 return 0;
710         }
711
712         client->fd = r;
713
714         return client_initialize_events(client, usec);
715 }
716
717 static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
718 {
719         sd_dhcp_client *client = userdata;
720         int r;
721
722         client->state = DHCP_STATE_RENEWING;
723         client->attempt = 1;
724
725         r = dhcp_network_bind_udp_socket(client->index,
726                                          client->lease->address);
727         if (r < 0) {
728                 client_stop(client, r);
729                 return 0;
730         }
731
732         client->fd = r;
733
734         return client_initialize_events(client, usec);
735 }
736
737 static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
738                               void *user_data)
739 {
740         DHCPLease *lease = user_data;
741         be32_t val;
742
743         switch(code) {
744
745         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
746                 if (len == 4) {
747                         memcpy(&val, option, 4);
748                         lease->lifetime = be32toh(val);
749                 }
750
751                 break;
752
753         case DHCP_OPTION_SERVER_IDENTIFIER:
754                 if (len >= 4)
755                         memcpy(&lease->server_address, option, 4);
756
757                 break;
758
759         case DHCP_OPTION_SUBNET_MASK:
760                 if (len >= 4)
761                         memcpy(&lease->subnet_mask, option, 4);
762
763                 break;
764
765         case DHCP_OPTION_ROUTER:
766                 if (len >= 4)
767                         memcpy(&lease->router, option, 4);
768
769                 break;
770
771         case DHCP_OPTION_DOMAIN_NAME_SERVER:
772                 if (len >= 4) {
773                         unsigned i;
774
775                         in_addrs_free(lease->dns);
776
777                         lease->dns = new0(struct in_addr*, len / 4 + 1);
778                         if (!lease->dns)
779                                 return -ENOMEM;
780
781                         for (i = 0; i < len / 4; i++) {
782                                 lease->dns[i] = new0(struct in_addr, 1);
783                                 memcpy(&lease->dns[i]->s_addr, option + 4 * i, 4);
784                         }
785
786                         lease->dns[len / 4] = NULL;
787                 }
788
789                 break;
790
791         case DHCP_OPTION_RENEWAL_T1_TIME:
792                 if (len == 4) {
793                         memcpy(&val, option, 4);
794                         lease->t1 = be32toh(val);
795                 }
796
797                 break;
798
799         case DHCP_OPTION_REBINDING_T2_TIME:
800                 if (len == 4) {
801                         memcpy(&val, option, 4);
802                         lease->t2 = be32toh(val);
803                 }
804
805                 break;
806         }
807
808         return 0;
809 }
810
811 static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
812                                  size_t len)
813 {
814         size_t hdrlen;
815
816         if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
817                 return -EINVAL;
818
819         hdrlen = message->ip.ihl * 4;
820         if (hdrlen < 20 || hdrlen > len || client_checksum(&message->ip,
821                                                            hdrlen))
822                 return -EINVAL;
823
824         message->ip.check = message->udp.len;
825         message->ip.ttl = 0;
826
827         if (hdrlen + be16toh(message->udp.len) > len ||
828             client_checksum(&message->ip.ttl, be16toh(message->udp.len) + 12))
829                 return -EINVAL;
830
831         if (be16toh(message->udp.source) != DHCP_PORT_SERVER ||
832             be16toh(message->udp.dest) != DHCP_PORT_CLIENT)
833                 return -EINVAL;
834
835         if (message->dhcp.op != BOOTREPLY)
836                 return -EINVAL;
837
838         if (be32toh(message->dhcp.xid) != client->xid)
839                 return -EINVAL;
840
841         if (memcmp(&message->dhcp.chaddr[0], &client->mac_addr.ether_addr_octet,
842                     ETHER_ADDR_LEN))
843                 return -EINVAL;
844
845         return 0;
846 }
847
848 static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
849                                 size_t len)
850 {
851         int err;
852         DHCPLease *lease;
853
854         err = client_verify_headers(client, offer, len);
855         if (err < 0)
856                 return err;
857
858         lease = new0(DHCPLease, 1);
859         if (!lease)
860                 return -ENOMEM;
861
862         len = len - DHCP_IP_UDP_SIZE;
863         if (dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
864                               lease) != DHCP_OFFER)
865                 goto error;
866
867         lease->address = offer->dhcp.yiaddr;
868
869         if (lease->address == INADDR_ANY ||
870             lease->server_address == INADDR_ANY ||
871             lease->subnet_mask == INADDR_ANY ||
872             lease->lifetime == 0)
873                 goto error;
874
875         client->lease = lease;
876
877         return 0;
878
879 error:
880         free(lease);
881
882         return -ENOMSG;
883 }
884
885 static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
886                               size_t len)
887 {
888         int r;
889         DHCPPacket *ack;
890         DHCPMessage *dhcp;
891         DHCPLease *lease;
892
893         if (client->state == DHCP_STATE_RENEWING) {
894                 dhcp = (DHCPMessage *)buf;
895         } else {
896                 ack = (DHCPPacket *)buf;
897
898                 r = client_verify_headers(client, ack, len);
899                 if (r < 0)
900                         return r;
901
902                 dhcp = &ack->dhcp;
903                 len -= DHCP_IP_UDP_SIZE;
904         }
905
906         lease = new0(DHCPLease, 1);
907         if (!lease)
908                 return -ENOMEM;
909
910         r = dhcp_option_parse(dhcp, len, client_parse_offer, lease);
911
912         if (r == DHCP_NAK) {
913                 r = DHCP_EVENT_NO_LEASE;
914                 goto error;
915         }
916
917         if (r != DHCP_ACK) {
918                 r = -ENOMSG;
919                 goto error;
920         }
921
922         lease->address = dhcp->yiaddr;
923
924         if (lease->address == INADDR_ANY ||
925             lease->server_address == INADDR_ANY ||
926             lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) {
927                 r = -ENOMSG;
928                 goto error;
929         }
930
931         r = DHCP_EVENT_IP_ACQUIRE;
932         if (client->lease) {
933                 if (client->lease->address != lease->address ||
934                     client->lease->subnet_mask != lease->subnet_mask ||
935                     client->lease->router != lease->router) {
936                         r = DHCP_EVENT_IP_CHANGE;
937                 }
938
939                 free(client->lease);
940         }
941
942         client->lease = lease;
943
944         return r;
945
946 error:
947         free(lease);
948
949         return r;
950 }
951
952 static uint64_t client_compute_timeout(uint64_t request_sent,
953                                        uint32_t lifetime)
954 {
955         return request_sent + (lifetime - 3) * USEC_PER_SEC +
956                 + (random_u32() & 0x1fffff);
957 }
958
959 static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec)
960 {
961         int err;
962         uint64_t next_timeout;
963
964         if (client->lease->lifetime < 10)
965                 return -EINVAL;
966
967         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
968         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
969         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
970
971         if (!client->lease->t1)
972                 client->lease->t1 = client->lease->lifetime / 2;
973
974         next_timeout = client_compute_timeout(client->request_sent,
975                                               client->lease->t1);
976         if (next_timeout < usec)
977                 return -EINVAL;
978
979         err = sd_event_add_monotonic(client->event, next_timeout,
980                                      10 * USEC_PER_MSEC,
981                                      client_timeout_t1, client,
982                                      &client->timeout_t1);
983         if (err < 0)
984                 return err;
985
986         if (!client->lease->t2)
987                 client->lease->t2 = client->lease->lifetime * 7 / 8;
988
989         if (client->lease->t2 < client->lease->t1)
990                 return -EINVAL;
991
992         if (client->lease->lifetime < client->lease->t2)
993                 return -EINVAL;
994
995         next_timeout = client_compute_timeout(client->request_sent,
996                                               client->lease->t2);
997         if (next_timeout < usec)
998                 return -EINVAL;
999
1000         err = sd_event_add_monotonic(client->event, next_timeout,
1001                                      10 * USEC_PER_MSEC,
1002                                      client_timeout_t2, client,
1003                                      &client->timeout_t2);
1004         if (err < 0)
1005                 return err;
1006
1007         next_timeout = client_compute_timeout(client->request_sent,
1008                                               client->lease->lifetime);
1009         if (next_timeout < usec)
1010                 return -EINVAL;
1011
1012         err = sd_event_add_monotonic(client->event, next_timeout,
1013                                      10 * USEC_PER_MSEC,
1014                                      client_timeout_expire, client,
1015                                      &client->timeout_expire);
1016         if (err < 0)
1017                 return err;
1018
1019         return 0;
1020 }
1021
1022 static int client_receive_message(sd_event_source *s, int fd,
1023                                   uint32_t revents, void *userdata)
1024 {
1025         sd_dhcp_client *client = userdata;
1026         uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
1027         int buflen = sizeof(buf);
1028         int len, r = 0, notify_event = 0;
1029         DHCPPacket *message;
1030         usec_t time_now;
1031
1032         len = read(fd, &buf, buflen);
1033         if (len < 0)
1034                 return 0;
1035
1036         r = sd_event_get_now_monotonic(client->event, &time_now);
1037         if (r < 0)
1038                 goto error;
1039
1040         switch (client->state) {
1041         case DHCP_STATE_SELECTING:
1042
1043                 message = (DHCPPacket *)&buf;
1044
1045                 if (client_receive_offer(client, message, len) >= 0) {
1046
1047                         client->timeout_resend =
1048                                 sd_event_source_unref(client->timeout_resend);
1049
1050                         client->state = DHCP_STATE_REQUESTING;
1051                         client->attempt = 1;
1052
1053                         r = sd_event_add_monotonic(client->event, time_now, 0,
1054                                                    client_timeout_resend,
1055                                                    client,
1056                                                    &client->timeout_resend);
1057                         if (r < 0)
1058                                 goto error;
1059                 }
1060
1061                 break;
1062
1063         case DHCP_STATE_REQUESTING:
1064         case DHCP_STATE_RENEWING:
1065         case DHCP_STATE_REBINDING:
1066
1067                 r = client_receive_ack(client, buf, len);
1068
1069                 if (r == DHCP_EVENT_NO_LEASE)
1070                         goto error;
1071
1072                 if (r >= 0) {
1073                         client->timeout_resend =
1074                                 sd_event_source_unref(client->timeout_resend);
1075
1076                         if (client->state == DHCP_STATE_REQUESTING)
1077                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
1078                         else if (r != DHCP_EVENT_IP_ACQUIRE)
1079                                 notify_event = r;
1080
1081                         client->state = DHCP_STATE_BOUND;
1082                         client->attempt = 1;
1083
1084                         client->last_addr = client->lease->address;
1085
1086                         r = client_set_lease_timeouts(client, time_now);
1087                         if (r < 0)
1088                                 goto error;
1089
1090                         if (notify_event)
1091                                 client_notify(client, notify_event);
1092
1093                         client->receive_message =
1094                                 sd_event_source_unref(client->receive_message);
1095                         close(client->fd);
1096                         client->fd = -1;
1097                 }
1098
1099                 r = 0;
1100
1101                 break;
1102
1103         case DHCP_STATE_INIT:
1104         case DHCP_STATE_INIT_REBOOT:
1105         case DHCP_STATE_REBOOTING:
1106         case DHCP_STATE_BOUND:
1107
1108                 break;
1109         }
1110
1111 error:
1112         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1113                 return client_stop(client, r);
1114
1115         return 0;
1116 }
1117
1118 int sd_dhcp_client_start(sd_dhcp_client *client)
1119 {
1120         int r;
1121
1122         assert_return(client, -EINVAL);
1123         assert_return(client->index > 0, -EINVAL);
1124         assert_return(client->state == DHCP_STATE_INIT ||
1125                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
1126
1127         client->xid = random_u32();
1128
1129         r = dhcp_network_bind_raw_socket(client->index, &client->link);
1130
1131         if (r < 0) {
1132                 client_stop(client, r);
1133                 return r;
1134         }
1135
1136         client->fd = r;
1137         client->start_time = now(CLOCK_MONOTONIC);
1138
1139         return client_initialize_events(client, client->start_time);
1140 }
1141
1142 int sd_dhcp_client_stop(sd_dhcp_client *client)
1143 {
1144         return client_stop(client, DHCP_EVENT_STOP);
1145 }
1146
1147 sd_dhcp_client *sd_dhcp_client_free(sd_dhcp_client *client)
1148 {
1149         assert_return(client, NULL);
1150
1151         sd_dhcp_client_stop(client);
1152
1153         sd_event_unref(client->event);
1154         free(client->req_opts);
1155         free(client);
1156
1157         return NULL;
1158 }
1159
1160 sd_dhcp_client *sd_dhcp_client_new(sd_event *event)
1161 {
1162         sd_dhcp_client *client;
1163
1164         assert_return(event, NULL);
1165
1166         client = new0(sd_dhcp_client, 1);
1167         if (!client)
1168                 return NULL;
1169
1170         client->event = sd_event_ref(event);
1171         client->state = DHCP_STATE_INIT;
1172         client->index = -1;
1173         client->fd = -1;
1174         client->attempt = 1;
1175
1176         client->req_opts_size = ELEMENTSOF(default_req_opts);
1177
1178         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1179         if (!client->req_opts) {
1180                 free(client);
1181                 return NULL;
1182         }
1183
1184         return client;
1185 }