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