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