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