chiark / gitweb /
sd-dhcp-client: Add an explicit stop state for the DHCP client
[elogind.git] / src / libsystemd-network / 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 <net/if_arp.h>
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
28
29 #include "util.h"
30 #include "list.h"
31 #include "refcnt.h"
32
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "dhcp-lease-internal.h"
36 #include "sd-dhcp-client.h"
37
38 struct sd_dhcp_client {
39         RefCount n_ref;
40
41         DHCPState state;
42         sd_event *event;
43         int event_priority;
44         sd_event_source *timeout_resend;
45         int index;
46         int fd;
47         union sockaddr_union link;
48         sd_event_source *receive_message;
49         uint8_t *req_opts;
50         size_t req_opts_allocated;
51         size_t req_opts_size;
52         be32_t last_addr;
53         struct {
54                 uint8_t type;
55                 struct ether_addr mac_addr;
56         } _packed_ client_id;
57         uint32_t xid;
58         usec_t start_time;
59         uint16_t secs;
60         unsigned int attempt;
61         usec_t request_sent;
62         sd_event_source *timeout_t1;
63         sd_event_source *timeout_t2;
64         sd_event_source *timeout_expire;
65         sd_dhcp_client_cb_t cb;
66         void *userdata;
67         sd_dhcp_lease *lease;
68 };
69
70 static const uint8_t default_req_opts[] = {
71         DHCP_OPTION_SUBNET_MASK,
72         DHCP_OPTION_ROUTER,
73         DHCP_OPTION_HOST_NAME,
74         DHCP_OPTION_DOMAIN_NAME,
75         DHCP_OPTION_DOMAIN_NAME_SERVER,
76         DHCP_OPTION_NTP_SERVER,
77 };
78
79 static int client_receive_message_raw(sd_event_source *s, int fd,
80                                       uint32_t revents, void *userdata);
81 static int client_receive_message_udp(sd_event_source *s, int fd,
82                                       uint32_t revents, void *userdata);
83 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error);
84
85 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
86                                 void *userdata) {
87         assert_return(client, -EINVAL);
88
89         client->cb = cb;
90         client->userdata = userdata;
91
92         return 0;
93 }
94
95 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
96         size_t i;
97
98         assert_return(client, -EINVAL);
99         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
100                               DHCP_STATE_STOPPED), -EBUSY);
101
102         switch(option) {
103         case DHCP_OPTION_PAD:
104         case DHCP_OPTION_OVERLOAD:
105         case DHCP_OPTION_MESSAGE_TYPE:
106         case DHCP_OPTION_PARAMETER_REQUEST_LIST:
107         case DHCP_OPTION_END:
108                 return -EINVAL;
109
110         default:
111                 break;
112         }
113
114         for (i = 0; i < client->req_opts_size; i++)
115                 if (client->req_opts[i] == option)
116                         return -EEXIST;
117
118         if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
119                             client->req_opts_size + 1))
120                 return -ENOMEM;
121
122         client->req_opts[client->req_opts_size++] = option;
123
124         return 0;
125 }
126
127 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
128                                        const struct in_addr *last_addr) {
129         assert_return(client, -EINVAL);
130         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
131                               DHCP_STATE_STOPPED), -EBUSY);
132
133         if (last_addr)
134                 client->last_addr = last_addr->s_addr;
135         else
136                 client->last_addr = INADDR_ANY;
137
138         return 0;
139 }
140
141 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
142         assert_return(client, -EINVAL);
143         assert_return (IN_SET(client->state, DHCP_STATE_INIT,
144                               DHCP_STATE_STOPPED), -EBUSY);
145         assert_return(interface_index >= -1, -EINVAL);
146
147         client->index = interface_index;
148
149         return 0;
150 }
151
152 int sd_dhcp_client_set_mac(sd_dhcp_client *client,
153                            const struct ether_addr *addr) {
154         bool need_restart = false;
155
156         assert_return(client, -EINVAL);
157         assert_return(addr, -EINVAL);
158
159         if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
160                 return 0;
161
162         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
163                 log_dhcp_client(client, "Changing MAC address on running DHCP "
164                                 "client, restarting");
165                 need_restart = true;
166                 client = client_stop(client, DHCP_EVENT_STOP);
167         }
168
169         if (!client)
170                 return 0;
171
172         memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
173         client->client_id.type = 0x01;
174
175         if (need_restart && client->state != DHCP_STATE_STOPPED)
176                 sd_dhcp_client_start(client);
177
178         return 0;
179 }
180
181 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
182         assert_return(client, -EINVAL);
183         assert_return(ret, -EINVAL);
184
185         if (client->state != DHCP_STATE_BOUND &&
186             client->state != DHCP_STATE_RENEWING &&
187             client->state != DHCP_STATE_REBINDING)
188                 return -EADDRNOTAVAIL;
189
190         *ret = sd_dhcp_lease_ref(client->lease);
191
192         return 0;
193 }
194
195 static sd_dhcp_client *client_notify(sd_dhcp_client *client, int event) {
196         if (client->cb) {
197                 client = sd_dhcp_client_ref(client);
198                 client->cb(client, event, client->userdata);
199                 client = sd_dhcp_client_unref(client);
200         }
201
202         return client;
203 }
204
205 static int client_initialize(sd_dhcp_client *client) {
206         assert_return(client, -EINVAL);
207
208         client->receive_message =
209                 sd_event_source_unref(client->receive_message);
210
211         client->fd = safe_close(client->fd);
212
213         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
214
215         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
216         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
217         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
218
219         client->attempt = 1;
220
221         client->state = DHCP_STATE_INIT;
222         client->xid = 0;
223
224         if (client->lease)
225                 client->lease = sd_dhcp_lease_unref(client->lease);
226
227         return 0;
228 }
229
230 static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
231         assert_return(client, NULL);
232
233         log_dhcp_client(client, "STOPPED %d", error);
234
235         client = client_notify(client, error);
236
237         if (client)
238                 client_initialize(client);
239
240         return client;
241 }
242
243 static int client_message_init(sd_dhcp_client *client, DHCPMessage *message,
244                                uint8_t type, uint8_t **opt, size_t *optlen) {
245         int r;
246
247         assert(client);
248         assert(client->secs);
249         assert(message);
250         assert(opt);
251         assert(optlen);
252
253         r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt,
254                               optlen);
255         if (r < 0)
256                 return r;
257
258         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
259            refuse to issue an DHCP lease if 'secs' is set to zero */
260         message->secs = htobe16(client->secs);
261
262         memcpy(&message->chaddr, &client->client_id.mac_addr, ETH_ALEN);
263
264         if (client->state == DHCP_STATE_RENEWING ||
265             client->state == DHCP_STATE_REBINDING)
266                 message->ciaddr = client->lease->address;
267
268         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
269            Identifier option is not set */
270         r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
271                                sizeof(client->client_id), &client->client_id);
272         if (r < 0)
273                 return r;
274
275         if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
276                 be16_t max_size;
277
278                 r = dhcp_option_append(opt, optlen,
279                                        DHCP_OPTION_PARAMETER_REQUEST_LIST,
280                                        client->req_opts_size,
281                                        client->req_opts);
282                 if (r < 0)
283                         return r;
284
285                 /* Some DHCP servers will send bigger DHCP packets than the
286                    defined default size unless the Maximum Messge Size option
287                    is explicitely set */
288                 max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
289                                    DHCP_MIN_OPTIONS_SIZE);
290                 r = dhcp_option_append(opt, optlen,
291                                        DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
292                                        2, &max_size);
293                 if (r < 0)
294                         return r;
295         }
296
297         return 0;
298 }
299
300 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
301                                 size_t len) {
302         dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
303                                       INADDR_BROADCAST, DHCP_PORT_SERVER, len);
304
305         return dhcp_network_send_raw_socket(client->fd, &client->link,
306                                             packet, len);
307 }
308
309 static int client_send_discover(sd_dhcp_client *client) {
310         _cleanup_free_ DHCPPacket *discover = NULL;
311         size_t optlen, len;
312         uint8_t *opt;
313         usec_t time_now;
314         int r;
315
316         assert(client);
317
318         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
319         if (r < 0)
320                 return r;
321         assert(time_now >= client->start_time);
322
323         /* seconds between sending first and last DISCOVER
324          * must always be strictly positive to deal with broken servers */
325         client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
326
327         optlen = DHCP_MIN_OPTIONS_SIZE;
328         len = sizeof(DHCPPacket) + optlen;
329
330         discover = malloc0(len);
331         if (!discover)
332                 return -ENOMEM;
333
334         r = client_message_init(client, &discover->dhcp, DHCP_DISCOVER,
335                                 &opt, &optlen);
336         if (r < 0)
337                 return r;
338
339         if (client->last_addr != INADDR_ANY) {
340                 r = dhcp_option_append(&opt, &optlen,
341                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
342                                          4, &client->last_addr);
343                 if (r < 0)
344                         return r;
345         }
346
347         r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
348         if (r < 0)
349                 return r;
350
351         r = dhcp_client_send_raw(client, discover, len - optlen);
352         if (r < 0)
353                 return r;
354
355         log_dhcp_client(client, "DISCOVER");
356
357         return 0;
358 }
359
360 static int client_send_request(sd_dhcp_client *client) {
361         _cleanup_free_ DHCPPacket *request;
362         size_t optlen, len;
363         uint8_t *opt;
364         int r;
365
366         optlen = DHCP_MIN_OPTIONS_SIZE;
367         len = sizeof(DHCPPacket) + optlen;
368
369         request = malloc0(len);
370         if (!request)
371                 return -ENOMEM;
372
373         r = client_message_init(client, &request->dhcp, DHCP_REQUEST, &opt,
374                                 &optlen);
375         if (r < 0)
376                 return r;
377
378         switch (client->state) {
379
380         case DHCP_STATE_INIT_REBOOT:
381                 r = dhcp_option_append(&opt, &optlen,
382                                          DHCP_OPTION_REQUESTED_IP_ADDRESS,
383                                          4, &client->last_addr);
384                 if (r < 0)
385                         return r;
386                 break;
387
388         case DHCP_STATE_REQUESTING:
389                 r = dhcp_option_append(&opt, &optlen,
390                                        DHCP_OPTION_REQUESTED_IP_ADDRESS,
391                                        4, &client->lease->address);
392                 if (r < 0)
393                         return r;
394
395                 r = dhcp_option_append(&opt, &optlen,
396                                        DHCP_OPTION_SERVER_IDENTIFIER,
397                                        4, &client->lease->server_address);
398                 if (r < 0)
399                         return r;
400                 break;
401
402         case DHCP_STATE_INIT:
403         case DHCP_STATE_SELECTING:
404         case DHCP_STATE_REBOOTING:
405         case DHCP_STATE_BOUND:
406         case DHCP_STATE_RENEWING:
407         case DHCP_STATE_REBINDING:
408
409                 break;
410
411         case DHCP_STATE_STOPPED:
412                 return -EINVAL;
413         }
414
415         r = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
416         if (r < 0)
417                 return r;
418
419         if (client->state == DHCP_STATE_RENEWING) {
420                 r = dhcp_network_send_udp_socket(client->fd,
421                                                  client->lease->server_address,
422                                                  DHCP_PORT_SERVER,
423                                                  &request->dhcp,
424                                                  len - optlen - DHCP_IP_UDP_SIZE);
425         } else {
426                 r = dhcp_client_send_raw(client, request, len - optlen);
427         }
428         if (r < 0)
429                 return r;
430
431         log_dhcp_client(client, "REQUEST");
432
433         return 0;
434 }
435
436 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
437                                  void *userdata) {
438         sd_dhcp_client *client = userdata;
439         usec_t next_timeout = 0;
440         uint64_t time_now;
441         uint32_t time_left;
442         int r;
443
444         assert(s);
445         assert(client);
446         assert(client->event);
447
448         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
449         if (r < 0)
450                 goto error;
451
452         switch (client->state) {
453         case DHCP_STATE_RENEWING:
454
455                 time_left = (client->lease->t2 - client->lease->t1) / 2;
456                 if (time_left < 60)
457                         time_left = 60;
458
459                 next_timeout = time_now + time_left * USEC_PER_SEC;
460
461                 break;
462
463         case DHCP_STATE_REBINDING:
464
465                 time_left = (client->lease->lifetime - client->lease->t2) / 2;
466                 if (time_left < 60)
467                         time_left = 60;
468
469                 next_timeout = time_now + time_left * USEC_PER_SEC;
470                 break;
471
472         case DHCP_STATE_REBOOTING:
473                 /* start over as we did not receive a timely ack or nak */
474                 client->state = DHCP_STATE_INIT;
475                 client->attempt = 1;
476                 client->xid = random_u32();
477
478                 /* fall through */
479         case DHCP_STATE_INIT:
480         case DHCP_STATE_INIT_REBOOT:
481         case DHCP_STATE_SELECTING:
482         case DHCP_STATE_REQUESTING:
483         case DHCP_STATE_BOUND:
484
485                 if (client->attempt < 64)
486                         client->attempt *= 2;
487
488                 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
489
490                 break;
491
492         case DHCP_STATE_STOPPED:
493                 r = -EINVAL;
494                 goto error;
495         }
496
497         next_timeout += (random_u32() & 0x1fffff);
498
499         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
500
501         r = sd_event_add_time(client->event,
502                               &client->timeout_resend,
503                               CLOCK_MONOTONIC,
504                               next_timeout, 10 * USEC_PER_MSEC,
505                               client_timeout_resend, client);
506         if (r < 0)
507                 goto error;
508
509         r = sd_event_source_set_priority(client->timeout_resend,
510                                          client->event_priority);
511         if (r < 0)
512                 goto error;
513
514         switch (client->state) {
515         case DHCP_STATE_INIT:
516                 r = client_send_discover(client);
517                 if (r >= 0) {
518                         client->state = DHCP_STATE_SELECTING;
519                         client->attempt = 1;
520                 } else {
521                         if (client->attempt >= 64)
522                                 goto error;
523                 }
524
525                 break;
526
527         case DHCP_STATE_SELECTING:
528                 r = client_send_discover(client);
529                 if (r < 0 && client->attempt >= 64)
530                         goto error;
531
532                 break;
533
534         case DHCP_STATE_INIT_REBOOT:
535         case DHCP_STATE_REQUESTING:
536         case DHCP_STATE_RENEWING:
537         case DHCP_STATE_REBINDING:
538                 r = client_send_request(client);
539                 if (r < 0 && client->attempt >= 64)
540                          goto error;
541
542                 if (client->state == DHCP_STATE_INIT_REBOOT)
543                         client->state = DHCP_STATE_REBOOTING;
544
545                 client->request_sent = time_now;
546
547                 break;
548
549         case DHCP_STATE_REBOOTING:
550         case DHCP_STATE_BOUND:
551
552                 break;
553
554         case DHCP_STATE_STOPPED:
555                 r = -EINVAL;
556                 goto error;
557         }
558
559         return 0;
560
561 error:
562         client_stop(client, r);
563
564         /* Errors were dealt with when stopping the client, don't spill
565            errors into the event loop handler */
566         return 0;
567 }
568
569 static int client_initialize_events(sd_dhcp_client *client,
570                                     sd_event_io_handler_t io_callback) {
571         int r;
572
573         assert(client);
574         assert(client->event);
575
576         r = sd_event_add_io(client->event, &client->receive_message,
577                             client->fd, EPOLLIN, io_callback,
578                             client);
579         if (r < 0)
580                 goto error;
581
582         r = sd_event_source_set_priority(client->receive_message,
583                                          client->event_priority);
584         if (r < 0)
585                 goto error;
586
587         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
588
589         r = sd_event_add_time(client->event,
590                               &client->timeout_resend,
591                               CLOCK_MONOTONIC,
592                               0, 0,
593                               client_timeout_resend, client);
594         if (r < 0)
595                 goto error;
596
597         r = sd_event_source_set_priority(client->timeout_resend,
598                                          client->event_priority);
599
600 error:
601         if (r < 0)
602                 client_stop(client, r);
603
604         return 0;
605
606 }
607
608 static int client_start(sd_dhcp_client *client) {
609         int r;
610
611         assert_return(client, -EINVAL);
612         assert_return(client->event, -EINVAL);
613         assert_return(client->index > 0, -EINVAL);
614         assert_return(client->fd < 0, -EBUSY);
615         assert_return(client->xid == 0, -EINVAL);
616         assert_return(client->state == DHCP_STATE_INIT ||
617                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
618
619         client->xid = random_u32();
620
621         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
622
623         if (r < 0) {
624                 client_stop(client, r);
625                 return r;
626         }
627         client->fd = r;
628
629         if (client->state == DHCP_STATE_INIT) {
630                 client->start_time = now(CLOCK_MONOTONIC);
631                 client->secs = 0;
632         }
633
634         log_dhcp_client(client, "STARTED");
635
636         return client_initialize_events(client, client_receive_message_raw);
637 }
638
639 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
640                                  void *userdata) {
641         sd_dhcp_client *client = userdata;
642
643         log_dhcp_client(client, "EXPIRED");
644
645         client = client_notify(client, DHCP_EVENT_EXPIRED);
646
647         /* lease was lost, start over if not freed or stopped in callback */
648         if (client && client->state != DHCP_STATE_STOPPED) {
649                 client_initialize(client);
650                 client_start(client);
651         }
652
653         return 0;
654 }
655
656 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
657         sd_dhcp_client *client = userdata;
658         int r;
659
660         client->receive_message = sd_event_source_unref(client->receive_message);
661         client->fd = safe_close(client->fd);
662
663         client->state = DHCP_STATE_REBINDING;
664         client->attempt = 1;
665
666         r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
667         if (r < 0) {
668                 client_stop(client, r);
669                 return 0;
670         }
671
672         client->fd = r;
673
674         log_dhcp_client(client, "TIMEOUT T2");
675
676         return client_initialize_events(client, client_receive_message_raw);
677 }
678
679 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
680                              void *userdata) {
681         sd_dhcp_client *client = userdata;
682         int r;
683
684         client->state = DHCP_STATE_RENEWING;
685         client->attempt = 1;
686
687         r = dhcp_network_bind_udp_socket(client->index,
688                                          client->lease->address,
689                                          DHCP_PORT_CLIENT);
690         if (r < 0) {
691                 client_stop(client, r);
692                 return 0;
693         }
694
695         client->fd = r;
696
697         log_dhcp_client(client, "TIMEOUT T1");
698
699         return client_initialize_events(client, client_receive_message_udp);
700 }
701
702 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
703                                size_t len) {
704         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
705         int r;
706
707         r = dhcp_lease_new(&lease);
708         if (r < 0)
709                 return r;
710
711         r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
712         if (r != DHCP_OFFER) {
713                 log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
714                 return -ENOMSG;
715         }
716
717         lease->next_server = offer->siaddr;
718
719         lease->address = offer->yiaddr;
720
721         if (lease->address == INADDR_ANY ||
722             lease->server_address == INADDR_ANY ||
723             lease->lifetime == 0) {
724                 log_dhcp_client(client, "receieved lease lacks address, server "
725                                 "address or lease lifetime, ignoring");
726                 return -ENOMSG;
727         }
728
729         if (lease->subnet_mask == INADDR_ANY) {
730                 r = dhcp_lease_set_default_subnet_mask(lease);
731                 if (r < 0) {
732                         log_dhcp_client(client, "receieved lease lacks subnet "
733                                         "mask, and a fallback one can not be "
734                                         "generated, ignoring");
735                         return -ENOMSG;
736                 }
737         }
738
739         client->lease = lease;
740         lease = NULL;
741
742         log_dhcp_client(client, "OFFER");
743
744         return 0;
745 }
746
747 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
748                              size_t len) {
749         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
750         int r;
751
752         r = dhcp_lease_new(&lease);
753         if (r < 0)
754                 return r;
755
756         r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
757         if (r == DHCP_NAK) {
758                 log_dhcp_client(client, "NAK");
759                 return DHCP_EVENT_NO_LEASE;
760         }
761
762         if (r != DHCP_ACK) {
763                 log_dhcp_client(client, "receieved message was not an ACK, ignoring");
764                 return -ENOMSG;
765         }
766
767         lease->next_server = ack->siaddr;
768
769         lease->address = ack->yiaddr;
770
771         if (lease->address == INADDR_ANY ||
772             lease->server_address == INADDR_ANY ||
773             lease->lifetime == 0) {
774                 log_dhcp_client(client, "receieved lease lacks address, server "
775                                 "address or lease lifetime, ignoring");
776                 return -ENOMSG;
777         }
778
779         if (lease->subnet_mask == INADDR_ANY) {
780                 r = dhcp_lease_set_default_subnet_mask(lease);
781                 if (r < 0) {
782                         log_dhcp_client(client, "receieved lease lacks subnet "
783                                         "mask, and a fallback one can not be "
784                                         "generated, ignoring");
785                         return -ENOMSG;
786                 }
787         }
788
789         r = DHCP_EVENT_IP_ACQUIRE;
790         if (client->lease) {
791                 if (client->lease->address != lease->address ||
792                     client->lease->subnet_mask != lease->subnet_mask ||
793                     client->lease->router != lease->router) {
794                         r = DHCP_EVENT_IP_CHANGE;
795                 }
796
797                 client->lease = sd_dhcp_lease_unref(client->lease);
798         }
799
800         client->lease = lease;
801         lease = NULL;
802
803         log_dhcp_client(client, "ACK");
804
805         return r;
806 }
807
808 static uint64_t client_compute_timeout(sd_dhcp_client *client,
809                                        uint32_t lifetime, double factor) {
810         assert(client);
811         assert(client->request_sent);
812         assert(lifetime);
813
814         return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
815                 + (random_u32() & 0x1fffff);
816 }
817
818 static int client_set_lease_timeouts(sd_dhcp_client *client) {
819         usec_t time_now;
820         uint64_t lifetime_timeout;
821         uint64_t t2_timeout;
822         uint64_t t1_timeout;
823         char time_string[FORMAT_TIMESPAN_MAX];
824         int r;
825
826         assert(client);
827         assert(client->event);
828         assert(client->lease);
829         assert(client->lease->lifetime);
830
831         client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
832         client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
833         client->timeout_expire = sd_event_source_unref(client->timeout_expire);
834
835         /* don't set timers for infinite leases */
836         if (client->lease->lifetime == 0xffffffff)
837                 return 0;
838
839         r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
840         if (r < 0)
841                 return r;
842         assert(client->request_sent <= time_now);
843
844         /* convert the various timeouts from relative (secs) to absolute (usecs) */
845         lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
846         if (client->lease->t1 && client->lease->t2) {
847                 /* both T1 and T2 are given */
848                 if (client->lease->t1 < client->lease->t2 &&
849                     client->lease->t2 < client->lease->lifetime) {
850                         /* they are both valid */
851                         t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
852                         t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
853                 } else {
854                         /* discard both */
855                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
856                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
857                         t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
858                         client->lease->t1 = client->lease->lifetime / 2;
859                 }
860         } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
861                 /* only T2 is given, and it is valid */
862                 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
863                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
864                 client->lease->t1 = client->lease->lifetime / 2;
865                 if (t2_timeout <= t1_timeout) {
866                         /* the computed T1 would be invalid, so discard T2 */
867                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
868                         client->lease->t2 = (client->lease->lifetime * 7) / 8;
869                 }
870         } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
871                 /* only T1 is given, and it is valid */
872                 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
873                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
874                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
875                 if (t2_timeout <= t1_timeout) {
876                         /* the computed T2 would be invalid, so discard T1 */
877                         t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
878                         client->lease->t2 = client->lease->lifetime / 2;
879                 }
880         } else {
881                 /* fall back to the default timeouts */
882                 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
883                 client->lease->t1 = client->lease->lifetime / 2;
884                 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
885                 client->lease->t2 = (client->lease->lifetime * 7) / 8;
886         }
887
888         /* arm lifetime timeout */
889         r = sd_event_add_time(client->event, &client->timeout_expire,
890                               CLOCK_MONOTONIC,
891                               lifetime_timeout, 10 * USEC_PER_MSEC,
892                               client_timeout_expire, client);
893         if (r < 0)
894                 return r;
895
896         r = sd_event_source_set_priority(client->timeout_expire,
897                                          client->event_priority);
898         if (r < 0)
899                 return r;
900
901         log_dhcp_client(client, "lease expires in %s",
902                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
903                         lifetime_timeout - time_now, 0));
904
905         /* don't arm earlier timeouts if this has already expired */
906         if (lifetime_timeout <= time_now)
907                 return 0;
908
909         /* arm T2 timeout */
910         r = sd_event_add_time(client->event,
911                               &client->timeout_t2,
912                               CLOCK_MONOTONIC,
913                               t2_timeout,
914                               10 * USEC_PER_MSEC,
915                               client_timeout_t2, client);
916         if (r < 0)
917                 return r;
918
919         r = sd_event_source_set_priority(client->timeout_t2,
920                                          client->event_priority);
921         if (r < 0)
922                 return r;
923
924         log_dhcp_client(client, "T2 expires in %s",
925                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
926                         t2_timeout - time_now, 0));
927
928         /* don't arm earlier timeout if this has already expired */
929         if (t2_timeout <= time_now)
930                 return 0;
931
932         /* arm T1 timeout */
933         r = sd_event_add_time(client->event,
934                               &client->timeout_t1,
935                               CLOCK_MONOTONIC,
936                               t1_timeout, 10 * USEC_PER_MSEC,
937                               client_timeout_t1, client);
938         if (r < 0)
939                 return r;
940
941         r = sd_event_source_set_priority(client->timeout_t1,
942                                          client->event_priority);
943         if (r < 0)
944                 return r;
945
946         log_dhcp_client(client, "T1 expires in %s",
947                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
948                         t1_timeout - time_now, 0));
949
950         return 0;
951 }
952
953 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
954                                  int len) {
955         int r = 0, notify_event = 0;
956
957         assert(client);
958         assert(client->event);
959         assert(message);
960
961         if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
962                 log_dhcp_client(client, "not a DHCP message: ignoring");
963                 return 0;
964         }
965
966         if (message->op != BOOTREPLY) {
967                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
968                 return 0;
969         }
970
971         if (be32toh(message->xid) != client->xid) {
972                 log_dhcp_client(client, "received xid (%u) does not match "
973                                 "expected (%u): ignoring",
974                                 be32toh(message->xid), client->xid);
975                 return 0;
976         }
977
978         if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
979                 log_dhcp_client(client, "not an ethernet packet");
980                 return 0;
981         }
982
983         if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
984                    ETH_ALEN)) {
985                 log_dhcp_client(client, "received chaddr does not match "
986                                 "expected: ignoring");
987                 return 0;
988         }
989
990         switch (client->state) {
991         case DHCP_STATE_SELECTING:
992
993                 r = client_handle_offer(client, message, len);
994                 if (r >= 0) {
995
996                         client->timeout_resend =
997                                 sd_event_source_unref(client->timeout_resend);
998
999                         client->state = DHCP_STATE_REQUESTING;
1000                         client->attempt = 1;
1001
1002                         r = sd_event_add_time(client->event,
1003                                               &client->timeout_resend,
1004                                               CLOCK_MONOTONIC,
1005                                               0, 0,
1006                                               client_timeout_resend, client);
1007                         if (r < 0)
1008                                 goto error;
1009
1010                         r = sd_event_source_set_priority(client->timeout_resend,
1011                                                          client->event_priority);
1012                         if (r < 0)
1013                                 goto error;
1014                 } else if (r == -ENOMSG)
1015                         /* invalid message, let's ignore it */
1016                         return 0;
1017
1018                 break;
1019
1020         case DHCP_STATE_REBOOTING:
1021         case DHCP_STATE_REQUESTING:
1022         case DHCP_STATE_RENEWING:
1023         case DHCP_STATE_REBINDING:
1024
1025                 r = client_handle_ack(client, message, len);
1026                 if (r == DHCP_EVENT_NO_LEASE) {
1027
1028                         client->timeout_resend =
1029                                 sd_event_source_unref(client->timeout_resend);
1030
1031                         if (client->state == DHCP_STATE_REBOOTING) {
1032                                 r = client_initialize(client);
1033                                 if (r < 0)
1034                                         goto error;
1035
1036                                 r = client_start(client);
1037                                 if (r < 0)
1038                                         goto error;
1039                         }
1040
1041                         goto error;
1042                 } else if (r >= 0) {
1043                         client->timeout_resend =
1044                                 sd_event_source_unref(client->timeout_resend);
1045
1046                         if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1047                                    DHCP_STATE_REBOOTING))
1048                                 notify_event = DHCP_EVENT_IP_ACQUIRE;
1049                         else if (r != DHCP_EVENT_IP_ACQUIRE)
1050                                 notify_event = r;
1051
1052                         client->state = DHCP_STATE_BOUND;
1053                         client->attempt = 1;
1054
1055                         client->last_addr = client->lease->address;
1056
1057                         r = client_set_lease_timeouts(client);
1058                         if (r < 0)
1059                                 goto error;
1060
1061                         if (notify_event) {
1062                                 client = client_notify(client, notify_event);
1063                                 if (!client ||
1064                                     client->state == DHCP_STATE_STOPPED)
1065                                         return 0;
1066                         }
1067
1068                         client->receive_message =
1069                                 sd_event_source_unref(client->receive_message);
1070                         client->fd = safe_close(client->fd);
1071                 } else if (r == -ENOMSG)
1072                         /* invalid message, let's ignore it */
1073                         return 0;
1074
1075                 break;
1076
1077         case DHCP_STATE_INIT:
1078         case DHCP_STATE_INIT_REBOOT:
1079         case DHCP_STATE_BOUND:
1080
1081                 break;
1082
1083         case DHCP_STATE_STOPPED:
1084                 r = -EINVAL;
1085                 goto error;
1086         }
1087
1088 error:
1089         if (r < 0 || r == DHCP_EVENT_NO_LEASE)
1090                 client_stop(client, r);
1091
1092         return r;
1093 }
1094
1095 static int client_receive_message_udp(sd_event_source *s, int fd,
1096                                       uint32_t revents, void *userdata) {
1097         sd_dhcp_client *client = userdata;
1098         _cleanup_free_ DHCPMessage *message = NULL;
1099         int buflen = 0, len, r;
1100
1101         assert(s);
1102         assert(client);
1103
1104         r = ioctl(fd, FIONREAD, &buflen);
1105         if (r < 0 || buflen <= 0)
1106                 buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE;
1107
1108         message = malloc0(buflen);
1109         if (!message)
1110                 return -ENOMEM;
1111
1112         len = read(fd, message, buflen);
1113         if (len < 0) {
1114                 log_dhcp_client(client, "could not receive message from UDP "
1115                                 "socket: %s", strerror(errno));
1116                 return 0;
1117         } else if ((size_t)len < sizeof(DHCPMessage))
1118                 return 0;
1119
1120         return client_handle_message(client, message, len);
1121 }
1122
1123 static int client_receive_message_raw(sd_event_source *s, int fd,
1124                                       uint32_t revents, void *userdata) {
1125         sd_dhcp_client *client = userdata;
1126         _cleanup_free_ DHCPPacket *packet = NULL;
1127         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1128         struct iovec iov = {};
1129         struct msghdr msg = {
1130                 .msg_iov = &iov,
1131                 .msg_iovlen = 1,
1132                 .msg_control = cmsgbuf,
1133                 .msg_controllen = sizeof(cmsgbuf),
1134         };
1135         struct cmsghdr *cmsg;
1136         bool checksum = true;
1137         int buflen = 0, len, r;
1138
1139         assert(s);
1140         assert(client);
1141
1142         r = ioctl(fd, FIONREAD, &buflen);
1143         if (r < 0 || buflen <= 0)
1144                 buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE;
1145
1146         packet = malloc0(buflen);
1147         if (!packet)
1148                 return -ENOMEM;
1149
1150         iov.iov_base = packet;
1151         iov.iov_len = buflen;
1152
1153         len = recvmsg(fd, &msg, 0);
1154         if (len < 0) {
1155                 log_dhcp_client(client, "could not receive message from raw "
1156                                 "socket: %s", strerror(errno));
1157                 return 0;
1158         } else if ((size_t)len < sizeof(DHCPPacket))
1159                 return 0;
1160
1161         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1162                 if (cmsg->cmsg_level == SOL_PACKET &&
1163                     cmsg->cmsg_type == PACKET_AUXDATA &&
1164                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1165                         struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1166
1167                         checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1168                         break;
1169                 }
1170         }
1171
1172         r = dhcp_packet_verify_headers(packet, len, checksum);
1173         if (r < 0)
1174                 return 0;
1175
1176         len -= DHCP_IP_UDP_SIZE;
1177
1178         return client_handle_message(client, &packet->dhcp, len);
1179 }
1180
1181 int sd_dhcp_client_start(sd_dhcp_client *client) {
1182         int r;
1183
1184         assert_return(client, -EINVAL);
1185
1186         r = client_initialize(client);
1187         if (r < 0)
1188                 return r;
1189
1190         if (client->last_addr)
1191                 client->state = DHCP_STATE_INIT_REBOOT;
1192
1193         return client_start(client);
1194 }
1195
1196 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1197         assert_return(client, -EINVAL);
1198
1199         if (client_stop(client, DHCP_EVENT_STOP))
1200                 client->state = DHCP_STATE_STOPPED;
1201
1202         return 0;
1203 }
1204
1205 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1206                                 int priority) {
1207         int r;
1208
1209         assert_return(client, -EINVAL);
1210         assert_return(!client->event, -EBUSY);
1211
1212         if (event)
1213                 client->event = sd_event_ref(event);
1214         else {
1215                 r = sd_event_default(&client->event);
1216                 if (r < 0)
1217                         return 0;
1218         }
1219
1220         client->event_priority = priority;
1221
1222         return 0;
1223 }
1224
1225 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1226         assert_return(client, -EINVAL);
1227
1228         client->event = sd_event_unref(client->event);
1229
1230         return 0;
1231 }
1232
1233 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1234         if (!client)
1235                 return NULL;
1236
1237         return client->event;
1238 }
1239
1240 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1241         if (client)
1242                 assert_se(REFCNT_INC(client->n_ref) >= 2);
1243
1244         return client;
1245 }
1246
1247 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1248         if (client && REFCNT_DEC(client->n_ref) <= 0) {
1249                 log_dhcp_client(client, "UNREF");
1250
1251                 client_initialize(client);
1252
1253                 client->receive_message =
1254                         sd_event_source_unref(client->receive_message);
1255
1256                 sd_dhcp_client_detach_event(client);
1257
1258                 free(client->req_opts);
1259                 free(client);
1260
1261                 return NULL;
1262         }
1263
1264         return client;
1265 }
1266
1267 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
1268 #define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_unrefp)
1269
1270 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1271         _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
1272
1273         assert_return(ret, -EINVAL);
1274
1275         client = new0(sd_dhcp_client, 1);
1276         if (!client)
1277                 return -ENOMEM;
1278
1279         client->n_ref = REFCNT_INIT;
1280         client->state = DHCP_STATE_INIT;
1281         client->index = -1;
1282         client->fd = -1;
1283         client->attempt = 1;
1284
1285         client->req_opts_size = ELEMENTSOF(default_req_opts);
1286
1287         client->req_opts = memdup(default_req_opts, client->req_opts_size);
1288         if (!client->req_opts)
1289                 return -ENOMEM;
1290
1291         *ret = client;
1292         client = NULL;
1293
1294         return 0;
1295 }