Line data Source code
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 <linux/if_infiniband.h>
27 : #include <sys/ioctl.h>
28 :
29 : #include "util.h"
30 : #include "refcnt.h"
31 : #include "random-util.h"
32 : #include "async.h"
33 :
34 : #include "dhcp-protocol.h"
35 : #include "dhcp-internal.h"
36 : #include "dhcp-lease-internal.h"
37 : #include "dhcp-identifier.h"
38 : #include "sd-dhcp-client.h"
39 :
40 : #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
41 : #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
42 :
43 : struct sd_dhcp_client {
44 : RefCount n_ref;
45 :
46 : DHCPState state;
47 : sd_event *event;
48 : int event_priority;
49 : sd_event_source *timeout_resend;
50 : int index;
51 : int fd;
52 : union sockaddr_union link;
53 : sd_event_source *receive_message;
54 : bool request_broadcast;
55 : uint8_t *req_opts;
56 : size_t req_opts_allocated;
57 : size_t req_opts_size;
58 : be32_t last_addr;
59 : uint8_t mac_addr[MAX_MAC_ADDR_LEN];
60 : size_t mac_addr_len;
61 : uint16_t arp_type;
62 : struct {
63 : uint8_t type;
64 : union {
65 : struct {
66 : /* 0: Generic (non-LL) (RFC 2132) */
67 : uint8_t data[MAX_CLIENT_ID_LEN];
68 : } _packed_ gen;
69 : struct {
70 : /* 1: Ethernet Link-Layer (RFC 2132) */
71 : uint8_t haddr[ETH_ALEN];
72 : } _packed_ eth;
73 : struct {
74 : /* 2 - 254: ARP/Link-Layer (RFC 2132) */
75 : uint8_t haddr[0];
76 : } _packed_ ll;
77 : struct {
78 : /* 255: Node-specific (RFC 4361) */
79 : uint32_t iaid;
80 : struct duid duid;
81 : } _packed_ ns;
82 : struct {
83 : uint8_t data[MAX_CLIENT_ID_LEN];
84 : } _packed_ raw;
85 : };
86 : } _packed_ client_id;
87 : size_t client_id_len;
88 : char *hostname;
89 : char *vendor_class_identifier;
90 : uint32_t mtu;
91 : uint32_t xid;
92 : usec_t start_time;
93 : unsigned int attempt;
94 : usec_t request_sent;
95 : sd_event_source *timeout_t1;
96 : sd_event_source *timeout_t2;
97 : sd_event_source *timeout_expire;
98 : sd_dhcp_client_cb_t cb;
99 : void *userdata;
100 : sd_dhcp_lease *lease;
101 : };
102 :
103 : static const uint8_t default_req_opts[] = {
104 : DHCP_OPTION_SUBNET_MASK,
105 : DHCP_OPTION_ROUTER,
106 : DHCP_OPTION_HOST_NAME,
107 : DHCP_OPTION_DOMAIN_NAME,
108 : DHCP_OPTION_DOMAIN_NAME_SERVER,
109 : DHCP_OPTION_NTP_SERVER,
110 : };
111 :
112 : static int client_receive_message_raw(sd_event_source *s, int fd,
113 : uint32_t revents, void *userdata);
114 : static int client_receive_message_udp(sd_event_source *s, int fd,
115 : uint32_t revents, void *userdata);
116 : static void client_stop(sd_dhcp_client *client, int error);
117 :
118 2 : int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
119 : void *userdata) {
120 2 : assert_return(client, -EINVAL);
121 :
122 2 : client->cb = cb;
123 2 : client->userdata = userdata;
124 :
125 2 : return 0;
126 : }
127 :
128 0 : int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
129 0 : assert_return(client, -EINVAL);
130 :
131 0 : client->request_broadcast = !!broadcast;
132 :
133 0 : return 0;
134 : }
135 :
136 17 : int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
137 : size_t i;
138 :
139 17 : assert_return(client, -EINVAL);
140 16 : assert_return (IN_SET(client->state, DHCP_STATE_INIT,
141 : DHCP_STATE_STOPPED), -EBUSY);
142 :
143 16 : switch(option) {
144 : case DHCP_OPTION_PAD:
145 : case DHCP_OPTION_OVERLOAD:
146 : case DHCP_OPTION_MESSAGE_TYPE:
147 : case DHCP_OPTION_PARAMETER_REQUEST_LIST:
148 : case DHCP_OPTION_END:
149 5 : return -EINVAL;
150 :
151 : default:
152 11 : break;
153 : }
154 :
155 57 : for (i = 0; i < client->req_opts_size; i++)
156 54 : if (client->req_opts[i] == option)
157 8 : return -EEXIST;
158 :
159 3 : if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
160 : client->req_opts_size + 1))
161 0 : return -ENOMEM;
162 :
163 3 : client->req_opts[client->req_opts_size++] = option;
164 :
165 3 : return 0;
166 : }
167 :
168 1 : int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
169 : const struct in_addr *last_addr) {
170 1 : assert_return(client, -EINVAL);
171 0 : assert_return (IN_SET(client->state, DHCP_STATE_INIT,
172 : DHCP_STATE_STOPPED), -EBUSY);
173 :
174 0 : if (last_addr)
175 0 : client->last_addr = last_addr->s_addr;
176 : else
177 0 : client->last_addr = INADDR_ANY;
178 :
179 0 : return 0;
180 : }
181 :
182 8 : int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
183 8 : assert_return(client, -EINVAL);
184 7 : assert_return (IN_SET(client->state, DHCP_STATE_INIT,
185 : DHCP_STATE_STOPPED), -EBUSY);
186 7 : assert_return(interface_index > 0, -EINVAL);
187 :
188 4 : client->index = interface_index;
189 :
190 4 : return 0;
191 : }
192 :
193 2 : int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
194 : size_t addr_len, uint16_t arp_type) {
195 4 : DHCP_CLIENT_DONT_DESTROY(client);
196 2 : bool need_restart = false;
197 :
198 2 : assert_return(client, -EINVAL);
199 2 : assert_return(addr, -EINVAL);
200 2 : assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
201 2 : assert_return(arp_type > 0, -EINVAL);
202 :
203 2 : if (arp_type == ARPHRD_ETHER)
204 2 : assert_return(addr_len == ETH_ALEN, -EINVAL);
205 0 : else if (arp_type == ARPHRD_INFINIBAND)
206 0 : assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
207 : else
208 0 : return -EINVAL;
209 :
210 2 : if (client->mac_addr_len == addr_len &&
211 0 : memcmp(&client->mac_addr, addr, addr_len) == 0)
212 0 : return 0;
213 :
214 2 : if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
215 0 : log_dhcp_client(client, "Changing MAC address on running DHCP "
216 : "client, restarting");
217 0 : need_restart = true;
218 0 : client_stop(client, DHCP_EVENT_STOP);
219 : }
220 :
221 2 : memcpy(&client->mac_addr, addr, addr_len);
222 2 : client->mac_addr_len = addr_len;
223 2 : client->arp_type = arp_type;
224 :
225 2 : if (need_restart && client->state != DHCP_STATE_STOPPED)
226 0 : sd_dhcp_client_start(client);
227 :
228 2 : return 0;
229 : }
230 :
231 0 : int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
232 : const uint8_t **data, size_t *data_len) {
233 :
234 0 : assert_return(client, -EINVAL);
235 0 : assert_return(type, -EINVAL);
236 0 : assert_return(data, -EINVAL);
237 0 : assert_return(data_len, -EINVAL);
238 :
239 0 : *type = 0;
240 0 : *data = NULL;
241 0 : *data_len = 0;
242 0 : if (client->client_id_len) {
243 0 : *type = client->client_id.type;
244 0 : *data = client->client_id.raw.data;
245 0 : *data_len = client->client_id_len - sizeof(client->client_id.type);
246 : }
247 :
248 0 : return 0;
249 : }
250 :
251 0 : int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
252 : const uint8_t *data, size_t data_len) {
253 0 : DHCP_CLIENT_DONT_DESTROY(client);
254 0 : bool need_restart = false;
255 :
256 0 : assert_return(client, -EINVAL);
257 0 : assert_return(data, -EINVAL);
258 0 : assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
259 :
260 0 : switch (type) {
261 : case ARPHRD_ETHER:
262 0 : if (data_len != ETH_ALEN)
263 0 : return -EINVAL;
264 0 : break;
265 : case ARPHRD_INFINIBAND:
266 0 : if (data_len != INFINIBAND_ALEN)
267 0 : return -EINVAL;
268 0 : break;
269 : default:
270 0 : break;
271 : }
272 :
273 0 : if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
274 0 : client->client_id.type == type &&
275 0 : memcmp(&client->client_id.raw.data, data, data_len) == 0)
276 0 : return 0;
277 :
278 0 : if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
279 0 : log_dhcp_client(client, "Changing client ID on running DHCP "
280 : "client, restarting");
281 0 : need_restart = true;
282 0 : client_stop(client, DHCP_EVENT_STOP);
283 : }
284 :
285 0 : client->client_id.type = type;
286 0 : memcpy(&client->client_id.raw.data, data, data_len);
287 0 : client->client_id_len = data_len + sizeof (client->client_id.type);
288 :
289 0 : if (need_restart && client->state != DHCP_STATE_STOPPED)
290 0 : sd_dhcp_client_start(client);
291 :
292 0 : return 0;
293 : }
294 :
295 0 : int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
296 : const char *hostname) {
297 0 : char *new_hostname = NULL;
298 :
299 0 : assert_return(client, -EINVAL);
300 :
301 0 : if (streq_ptr(client->hostname, hostname))
302 0 : return 0;
303 :
304 0 : if (hostname) {
305 0 : new_hostname = strdup(hostname);
306 0 : if (!new_hostname)
307 0 : return -ENOMEM;
308 : }
309 :
310 0 : free(client->hostname);
311 0 : client->hostname = new_hostname;
312 :
313 0 : return 0;
314 : }
315 :
316 0 : int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
317 : const char *vci) {
318 0 : char *new_vci = NULL;
319 :
320 0 : assert_return(client, -EINVAL);
321 :
322 0 : new_vci = strdup(vci);
323 0 : if (!new_vci)
324 0 : return -ENOMEM;
325 :
326 0 : free(client->vendor_class_identifier);
327 :
328 0 : client->vendor_class_identifier = new_vci;
329 :
330 0 : return 0;
331 : }
332 :
333 0 : int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
334 0 : assert_return(client, -EINVAL);
335 0 : assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
336 :
337 0 : client->mtu = mtu;
338 :
339 0 : return 0;
340 : }
341 :
342 1 : int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
343 1 : assert_return(client, -EINVAL);
344 1 : assert_return(ret, -EINVAL);
345 :
346 1 : if (client->state != DHCP_STATE_BOUND &&
347 0 : client->state != DHCP_STATE_RENEWING &&
348 0 : client->state != DHCP_STATE_REBINDING)
349 0 : return -EADDRNOTAVAIL;
350 :
351 1 : *ret = sd_dhcp_lease_ref(client->lease);
352 :
353 1 : return 0;
354 : }
355 :
356 3 : static void client_notify(sd_dhcp_client *client, int event) {
357 3 : if (client->cb)
358 1 : client->cb(client, event, client->userdata);
359 3 : }
360 :
361 7 : static int client_initialize(sd_dhcp_client *client) {
362 7 : assert_return(client, -EINVAL);
363 :
364 7 : client->receive_message =
365 7 : sd_event_source_unref(client->receive_message);
366 :
367 7 : client->fd = asynchronous_close(client->fd);
368 :
369 7 : client->timeout_resend = sd_event_source_unref(client->timeout_resend);
370 :
371 7 : client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
372 7 : client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
373 7 : client->timeout_expire = sd_event_source_unref(client->timeout_expire);
374 :
375 7 : client->attempt = 1;
376 :
377 7 : client->state = DHCP_STATE_INIT;
378 7 : client->xid = 0;
379 :
380 7 : if (client->lease)
381 1 : client->lease = sd_dhcp_lease_unref(client->lease);
382 :
383 7 : return 0;
384 : }
385 :
386 2 : static void client_stop(sd_dhcp_client *client, int error) {
387 2 : assert(client);
388 :
389 2 : if (error < 0)
390 0 : log_dhcp_client(client, "STOPPED: %s", strerror(-error));
391 2 : else if (error == DHCP_EVENT_STOP)
392 2 : log_dhcp_client(client, "STOPPED");
393 : else
394 0 : log_dhcp_client(client, "STOPPED: Unknown event");
395 :
396 2 : client_notify(client, error);
397 :
398 2 : client_initialize(client);
399 2 : }
400 :
401 3 : static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
402 : uint8_t type, size_t *_optlen, size_t *_optoffset) {
403 3 : _cleanup_free_ DHCPPacket *packet;
404 : size_t optlen, optoffset, size;
405 : be16_t max_size;
406 : usec_t time_now;
407 : uint16_t secs;
408 : int r;
409 :
410 3 : assert(client);
411 3 : assert(client->start_time);
412 3 : assert(ret);
413 3 : assert(_optlen);
414 3 : assert(_optoffset);
415 3 : assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
416 :
417 3 : optlen = DHCP_MIN_OPTIONS_SIZE;
418 3 : size = sizeof(DHCPPacket) + optlen;
419 :
420 3 : packet = malloc0(size);
421 3 : if (!packet)
422 0 : return -ENOMEM;
423 :
424 3 : r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
425 3 : client->arp_type, optlen, &optoffset);
426 3 : if (r < 0)
427 0 : return r;
428 :
429 : /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
430 : refuse to issue an DHCP lease if 'secs' is set to zero */
431 3 : r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
432 3 : if (r < 0)
433 0 : return r;
434 3 : assert(time_now >= client->start_time);
435 :
436 : /* seconds between sending first and last DISCOVER
437 : * must always be strictly positive to deal with broken servers */
438 3 : secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
439 3 : packet->dhcp.secs = htobe16(secs);
440 :
441 : /* RFC2132 section 4.1
442 : A client that cannot receive unicast IP datagrams until its protocol
443 : software has been configured with an IP address SHOULD set the
444 : BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
445 : DHCPREQUEST messages that client sends. The BROADCAST bit will
446 : provide a hint to the DHCP server and BOOTP relay agent to broadcast
447 : any messages to the client on the client's subnet.
448 :
449 : Note: some interfaces needs this to be enabled, but some networks
450 : needs this to be disabled as broadcasts are filteretd, so this
451 : needs to be configurable */
452 3 : if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
453 0 : packet->dhcp.flags = htobe16(0x8000);
454 :
455 : /* RFC2132 section 4.1.1:
456 : The client MUST include its hardware address in the ’chaddr’ field, if
457 : necessary for delivery of DHCP reply messages. Non-Ethernet
458 : interfaces will leave 'chaddr' empty and use the client identifier
459 : instead (eg, RFC 4390 section 2.1).
460 : */
461 3 : if (client->arp_type == ARPHRD_ETHER)
462 3 : memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
463 :
464 : /* If no client identifier exists, construct an RFC 4361-compliant one */
465 3 : if (client->client_id_len == 0) {
466 : size_t duid_len;
467 :
468 2 : client->client_id.type = 255;
469 :
470 2 : r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
471 2 : if (r < 0)
472 0 : return r;
473 :
474 2 : r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
475 2 : if (r < 0)
476 0 : return r;
477 :
478 2 : client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
479 : }
480 :
481 : /* Some DHCP servers will refuse to issue an DHCP lease if the Client
482 : Identifier option is not set */
483 3 : if (client->client_id_len) {
484 3 : r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
485 : DHCP_OPTION_CLIENT_IDENTIFIER,
486 : client->client_id_len,
487 3 : &client->client_id);
488 3 : if (r < 0)
489 0 : return r;
490 : }
491 :
492 : /* RFC2131 section 3.5:
493 : in its initial DHCPDISCOVER or DHCPREQUEST message, a
494 : client may provide the server with a list of specific
495 : parameters the client is interested in. If the client
496 : includes a list of parameters in a DHCPDISCOVER message,
497 : it MUST include that list in any subsequent DHCPREQUEST
498 : messages.
499 : */
500 3 : r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
501 : DHCP_OPTION_PARAMETER_REQUEST_LIST,
502 3 : client->req_opts_size, client->req_opts);
503 3 : if (r < 0)
504 0 : return r;
505 :
506 : /* RFC2131 section 3.5:
507 : The client SHOULD include the ’maximum DHCP message size’ option to
508 : let the server know how large the server may make its DHCP messages.
509 :
510 : Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
511 : than the defined default size unless the Maximum Messge Size option
512 : is explicitly set
513 :
514 : RFC3442 "Requirements to Avoid Sizing Constraints":
515 : Because a full routing table can be quite large, the standard 576
516 : octet maximum size for a DHCP message may be too short to contain
517 : some legitimate Classless Static Route options. Because of this,
518 : clients implementing the Classless Static Route option SHOULD send a
519 : Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
520 : stack is capable of receiving larger IP datagrams. In this case, the
521 : client SHOULD set the value of this option to at least the MTU of the
522 : interface that the client is configuring. The client MAY set the
523 : value of this option higher, up to the size of the largest UDP packet
524 : it is prepared to accept. (Note that the value specified in the
525 : Maximum DHCP Message Size option is the total maximum packet size,
526 : including IP and UDP headers.)
527 : */
528 3 : max_size = htobe16(size);
529 3 : r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
530 : DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
531 : 2, &max_size);
532 3 : if (r < 0)
533 0 : return r;
534 :
535 3 : *_optlen = optlen;
536 3 : *_optoffset = optoffset;
537 3 : *ret = packet;
538 3 : packet = NULL;
539 :
540 3 : return 0;
541 : }
542 :
543 3 : static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
544 : size_t len) {
545 3 : dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
546 : INADDR_BROADCAST, DHCP_PORT_SERVER, len);
547 :
548 3 : return dhcp_network_send_raw_socket(client->fd, &client->link,
549 : packet, len);
550 : }
551 :
552 2 : static int client_send_discover(sd_dhcp_client *client) {
553 4 : _cleanup_free_ DHCPPacket *discover = NULL;
554 : size_t optoffset, optlen;
555 : int r;
556 :
557 2 : assert(client);
558 2 : assert(client->state == DHCP_STATE_INIT ||
559 : client->state == DHCP_STATE_SELECTING);
560 :
561 2 : r = client_message_init(client, &discover, DHCP_DISCOVER,
562 : &optlen, &optoffset);
563 2 : if (r < 0)
564 0 : return r;
565 :
566 : /* the client may suggest values for the network address
567 : and lease time in the DHCPDISCOVER message. The client may include
568 : the ’requested IP address’ option to suggest that a particular IP
569 : address be assigned, and may include the ’IP address lease time’
570 : option to suggest the lease time it would like.
571 : */
572 2 : if (client->last_addr != INADDR_ANY) {
573 0 : r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
574 : DHCP_OPTION_REQUESTED_IP_ADDRESS,
575 0 : 4, &client->last_addr);
576 0 : if (r < 0)
577 0 : return r;
578 : }
579 :
580 : /* it is unclear from RFC 2131 if client should send hostname in
581 : DHCPDISCOVER but dhclient does and so we do as well
582 : */
583 2 : if (client->hostname) {
584 0 : r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
585 : DHCP_OPTION_HOST_NAME,
586 0 : strlen(client->hostname), client->hostname);
587 0 : if (r < 0)
588 0 : return r;
589 : }
590 :
591 2 : if (client->vendor_class_identifier) {
592 0 : r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
593 : DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
594 0 : strlen(client->vendor_class_identifier),
595 0 : client->vendor_class_identifier);
596 0 : if (r < 0)
597 0 : return r;
598 : }
599 :
600 2 : r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
601 : DHCP_OPTION_END, 0, NULL);
602 2 : if (r < 0)
603 0 : return r;
604 :
605 : /* We currently ignore:
606 : The client SHOULD wait a random time between one and ten seconds to
607 : desynchronize the use of DHCP at startup.
608 : */
609 2 : r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
610 2 : if (r < 0)
611 0 : return r;
612 :
613 2 : log_dhcp_client(client, "DISCOVER");
614 :
615 2 : return 0;
616 : }
617 :
618 1 : static int client_send_request(sd_dhcp_client *client) {
619 2 : _cleanup_free_ DHCPPacket *request = NULL;
620 : size_t optoffset, optlen;
621 : int r;
622 :
623 1 : r = client_message_init(client, &request, DHCP_REQUEST,
624 : &optlen, &optoffset);
625 1 : if (r < 0)
626 0 : return r;
627 :
628 1 : switch (client->state) {
629 : /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
630 : SELECTING should be REQUESTING)
631 : */
632 :
633 : case DHCP_STATE_REQUESTING:
634 : /* Client inserts the address of the selected server in ’server
635 : identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
636 : filled in with the yiaddr value from the chosen DHCPOFFER.
637 : */
638 :
639 1 : r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
640 : DHCP_OPTION_SERVER_IDENTIFIER,
641 1 : 4, &client->lease->server_address);
642 1 : if (r < 0)
643 0 : return r;
644 :
645 1 : r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
646 : DHCP_OPTION_REQUESTED_IP_ADDRESS,
647 1 : 4, &client->lease->address);
648 1 : if (r < 0)
649 0 : return r;
650 :
651 1 : break;
652 :
653 : case DHCP_STATE_INIT_REBOOT:
654 : /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
655 : option MUST be filled in with client’s notion of its previously
656 : assigned address. ’ciaddr’ MUST be zero.
657 : */
658 0 : r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
659 : DHCP_OPTION_REQUESTED_IP_ADDRESS,
660 0 : 4, &client->last_addr);
661 0 : if (r < 0)
662 0 : return r;
663 0 : break;
664 :
665 : case DHCP_STATE_RENEWING:
666 : /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
667 : option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
668 : client’s IP address.
669 : */
670 :
671 : /* fall through */
672 : case DHCP_STATE_REBINDING:
673 : /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
674 : option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
675 : client’s IP address.
676 :
677 : This message MUST be broadcast to the 0xffffffff IP broadcast address.
678 : */
679 0 : request->dhcp.ciaddr = client->lease->address;
680 :
681 0 : break;
682 :
683 : case DHCP_STATE_INIT:
684 : case DHCP_STATE_SELECTING:
685 : case DHCP_STATE_REBOOTING:
686 : case DHCP_STATE_BOUND:
687 : case DHCP_STATE_STOPPED:
688 0 : return -EINVAL;
689 : }
690 :
691 1 : if (client->hostname) {
692 0 : r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
693 : DHCP_OPTION_HOST_NAME,
694 0 : strlen(client->hostname), client->hostname);
695 0 : if (r < 0)
696 0 : return r;
697 : }
698 :
699 1 : r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
700 : DHCP_OPTION_END, 0, NULL);
701 1 : if (r < 0)
702 0 : return r;
703 :
704 1 : if (client->state == DHCP_STATE_RENEWING) {
705 0 : r = dhcp_network_send_udp_socket(client->fd,
706 0 : client->lease->server_address,
707 : DHCP_PORT_SERVER,
708 0 : &request->dhcp,
709 : sizeof(DHCPMessage) + optoffset);
710 : } else {
711 1 : r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
712 : }
713 1 : if (r < 0)
714 0 : return r;
715 :
716 1 : switch (client->state) {
717 : case DHCP_STATE_REQUESTING:
718 1 : log_dhcp_client(client, "REQUEST (requesting)");
719 1 : break;
720 : case DHCP_STATE_INIT_REBOOT:
721 0 : log_dhcp_client(client, "REQUEST (init-reboot)");
722 0 : break;
723 : case DHCP_STATE_RENEWING:
724 0 : log_dhcp_client(client, "REQUEST (renewing)");
725 0 : break;
726 : case DHCP_STATE_REBINDING:
727 0 : log_dhcp_client(client, "REQUEST (rebinding)");
728 0 : break;
729 : default:
730 0 : log_dhcp_client(client, "REQUEST (invalid)");
731 0 : break;
732 : }
733 :
734 1 : return 0;
735 : }
736 :
737 : static int client_start(sd_dhcp_client *client);
738 :
739 3 : static int client_timeout_resend(sd_event_source *s, uint64_t usec,
740 : void *userdata) {
741 3 : sd_dhcp_client *client = userdata;
742 6 : DHCP_CLIENT_DONT_DESTROY(client);
743 3 : usec_t next_timeout = 0;
744 : uint64_t time_now;
745 : uint32_t time_left;
746 : int r;
747 :
748 3 : assert(s);
749 3 : assert(client);
750 3 : assert(client->event);
751 :
752 3 : r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
753 3 : if (r < 0)
754 0 : goto error;
755 :
756 3 : switch (client->state) {
757 : case DHCP_STATE_RENEWING:
758 :
759 0 : time_left = (client->lease->t2 - client->lease->t1) / 2;
760 0 : if (time_left < 60)
761 0 : time_left = 60;
762 :
763 0 : next_timeout = time_now + time_left * USEC_PER_SEC;
764 :
765 0 : break;
766 :
767 : case DHCP_STATE_REBINDING:
768 :
769 0 : time_left = (client->lease->lifetime - client->lease->t2) / 2;
770 0 : if (time_left < 60)
771 0 : time_left = 60;
772 :
773 0 : next_timeout = time_now + time_left * USEC_PER_SEC;
774 0 : break;
775 :
776 : case DHCP_STATE_REBOOTING:
777 : /* start over as we did not receive a timely ack or nak */
778 0 : r = client_initialize(client);
779 0 : if (r < 0)
780 0 : goto error;
781 :
782 0 : r = client_start(client);
783 0 : if (r < 0)
784 0 : goto error;
785 : else {
786 0 : log_dhcp_client(client, "REBOOTED");
787 0 : return 0;
788 : }
789 :
790 : case DHCP_STATE_INIT:
791 : case DHCP_STATE_INIT_REBOOT:
792 : case DHCP_STATE_SELECTING:
793 : case DHCP_STATE_REQUESTING:
794 : case DHCP_STATE_BOUND:
795 :
796 3 : if (client->attempt < 64)
797 3 : client->attempt *= 2;
798 :
799 3 : next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
800 :
801 3 : break;
802 :
803 : case DHCP_STATE_STOPPED:
804 0 : r = -EINVAL;
805 0 : goto error;
806 : }
807 :
808 3 : next_timeout += (random_u32() & 0x1fffff);
809 :
810 3 : client->timeout_resend = sd_event_source_unref(client->timeout_resend);
811 :
812 3 : r = sd_event_add_time(client->event,
813 : &client->timeout_resend,
814 : clock_boottime_or_monotonic(),
815 : next_timeout, 10 * USEC_PER_MSEC,
816 : client_timeout_resend, client);
817 3 : if (r < 0)
818 0 : goto error;
819 :
820 3 : r = sd_event_source_set_priority(client->timeout_resend,
821 3 : client->event_priority);
822 3 : if (r < 0)
823 0 : goto error;
824 :
825 3 : r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
826 3 : if (r < 0)
827 0 : goto error;
828 :
829 3 : switch (client->state) {
830 : case DHCP_STATE_INIT:
831 2 : r = client_send_discover(client);
832 2 : if (r >= 0) {
833 2 : client->state = DHCP_STATE_SELECTING;
834 2 : client->attempt = 1;
835 : } else {
836 0 : if (client->attempt >= 64)
837 0 : goto error;
838 : }
839 :
840 2 : break;
841 :
842 : case DHCP_STATE_SELECTING:
843 0 : r = client_send_discover(client);
844 0 : if (r < 0 && client->attempt >= 64)
845 0 : goto error;
846 :
847 0 : break;
848 :
849 : case DHCP_STATE_INIT_REBOOT:
850 : case DHCP_STATE_REQUESTING:
851 : case DHCP_STATE_RENEWING:
852 : case DHCP_STATE_REBINDING:
853 1 : r = client_send_request(client);
854 1 : if (r < 0 && client->attempt >= 64)
855 0 : goto error;
856 :
857 1 : if (client->state == DHCP_STATE_INIT_REBOOT)
858 0 : client->state = DHCP_STATE_REBOOTING;
859 :
860 1 : client->request_sent = time_now;
861 :
862 1 : break;
863 :
864 : case DHCP_STATE_REBOOTING:
865 : case DHCP_STATE_BOUND:
866 :
867 0 : break;
868 :
869 : case DHCP_STATE_STOPPED:
870 0 : r = -EINVAL;
871 0 : goto error;
872 : }
873 :
874 3 : return 0;
875 :
876 : error:
877 0 : client_stop(client, r);
878 :
879 : /* Errors were dealt with when stopping the client, don't spill
880 : errors into the event loop handler */
881 0 : return 0;
882 : }
883 :
884 3 : static int client_initialize_io_events(sd_dhcp_client *client,
885 : sd_event_io_handler_t io_callback) {
886 : int r;
887 :
888 3 : assert(client);
889 3 : assert(client->event);
890 :
891 3 : r = sd_event_add_io(client->event, &client->receive_message,
892 : client->fd, EPOLLIN, io_callback,
893 : client);
894 3 : if (r < 0)
895 0 : goto error;
896 :
897 3 : r = sd_event_source_set_priority(client->receive_message,
898 3 : client->event_priority);
899 3 : if (r < 0)
900 0 : goto error;
901 :
902 3 : r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
903 3 : if (r < 0)
904 0 : goto error;
905 :
906 : error:
907 3 : if (r < 0)
908 0 : client_stop(client, r);
909 :
910 3 : return 0;
911 : }
912 :
913 2 : static int client_initialize_time_events(sd_dhcp_client *client) {
914 : int r;
915 :
916 2 : assert(client);
917 2 : assert(client->event);
918 :
919 2 : client->timeout_resend = sd_event_source_unref(client->timeout_resend);
920 :
921 2 : r = sd_event_add_time(client->event,
922 : &client->timeout_resend,
923 : clock_boottime_or_monotonic(),
924 : 0, 0,
925 : client_timeout_resend, client);
926 2 : if (r < 0)
927 0 : goto error;
928 :
929 2 : r = sd_event_source_set_priority(client->timeout_resend,
930 2 : client->event_priority);
931 2 : if (r < 0)
932 0 : goto error;
933 :
934 2 : r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
935 2 : if (r < 0)
936 0 : goto error;
937 :
938 : error:
939 2 : if (r < 0)
940 0 : client_stop(client, r);
941 :
942 2 : return 0;
943 :
944 : }
945 :
946 2 : static int client_initialize_events(sd_dhcp_client *client,
947 : sd_event_io_handler_t io_callback) {
948 2 : client_initialize_io_events(client, io_callback);
949 2 : client_initialize_time_events(client);
950 :
951 2 : return 0;
952 : }
953 :
954 2 : static int client_start(sd_dhcp_client *client) {
955 : int r;
956 :
957 2 : assert_return(client, -EINVAL);
958 2 : assert_return(client->event, -EINVAL);
959 2 : assert_return(client->index > 0, -EINVAL);
960 2 : assert_return(client->fd < 0, -EBUSY);
961 2 : assert_return(client->xid == 0, -EINVAL);
962 2 : assert_return(client->state == DHCP_STATE_INIT ||
963 : client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
964 :
965 2 : client->xid = random_u32();
966 :
967 4 : r = dhcp_network_bind_raw_socket(client->index, &client->link,
968 2 : client->xid, client->mac_addr,
969 2 : client->mac_addr_len, client->arp_type);
970 2 : if (r < 0) {
971 0 : client_stop(client, r);
972 0 : return r;
973 : }
974 2 : client->fd = r;
975 :
976 2 : if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
977 2 : client->start_time = now(clock_boottime_or_monotonic());
978 :
979 2 : return client_initialize_events(client, client_receive_message_raw);
980 : }
981 :
982 0 : static int client_timeout_expire(sd_event_source *s, uint64_t usec,
983 : void *userdata) {
984 0 : sd_dhcp_client *client = userdata;
985 0 : DHCP_CLIENT_DONT_DESTROY(client);
986 :
987 0 : log_dhcp_client(client, "EXPIRED");
988 :
989 0 : client_notify(client, DHCP_EVENT_EXPIRED);
990 :
991 : /* lease was lost, start over if not freed or stopped in callback */
992 0 : if (client->state != DHCP_STATE_STOPPED) {
993 0 : client_initialize(client);
994 0 : client_start(client);
995 : }
996 :
997 0 : return 0;
998 : }
999 :
1000 0 : static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
1001 0 : sd_dhcp_client *client = userdata;
1002 0 : DHCP_CLIENT_DONT_DESTROY(client);
1003 : int r;
1004 :
1005 0 : client->receive_message = sd_event_source_unref(client->receive_message);
1006 0 : client->fd = asynchronous_close(client->fd);
1007 :
1008 0 : client->state = DHCP_STATE_REBINDING;
1009 0 : client->attempt = 1;
1010 :
1011 0 : r = dhcp_network_bind_raw_socket(client->index, &client->link,
1012 0 : client->xid, client->mac_addr,
1013 0 : client->mac_addr_len, client->arp_type);
1014 0 : if (r < 0) {
1015 0 : client_stop(client, r);
1016 0 : return 0;
1017 : }
1018 0 : client->fd = r;
1019 :
1020 0 : return client_initialize_events(client, client_receive_message_raw);
1021 : }
1022 :
1023 0 : static int client_timeout_t1(sd_event_source *s, uint64_t usec,
1024 : void *userdata) {
1025 0 : sd_dhcp_client *client = userdata;
1026 0 : DHCP_CLIENT_DONT_DESTROY(client);
1027 :
1028 0 : client->state = DHCP_STATE_RENEWING;
1029 0 : client->attempt = 1;
1030 :
1031 0 : return client_initialize_time_events(client);
1032 : }
1033 :
1034 1 : static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
1035 : size_t len) {
1036 2 : _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
1037 : int r;
1038 :
1039 1 : r = dhcp_lease_new(&lease);
1040 1 : if (r < 0)
1041 0 : return r;
1042 :
1043 1 : if (client->client_id_len) {
1044 2 : r = dhcp_lease_set_client_id(lease,
1045 1 : (uint8_t *) &client->client_id,
1046 : client->client_id_len);
1047 1 : if (r < 0)
1048 0 : return r;
1049 : }
1050 :
1051 1 : r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
1052 1 : if (r != DHCP_OFFER) {
1053 0 : log_dhcp_client(client, "received message was not an OFFER, ignoring");
1054 0 : return -ENOMSG;
1055 : }
1056 :
1057 1 : lease->next_server = offer->siaddr;
1058 :
1059 1 : lease->address = offer->yiaddr;
1060 :
1061 2 : if (lease->address == INADDR_ANY ||
1062 2 : lease->server_address == INADDR_ANY ||
1063 1 : lease->lifetime == 0) {
1064 0 : log_dhcp_client(client, "received lease lacks address, server "
1065 : "address or lease lifetime, ignoring");
1066 0 : return -ENOMSG;
1067 : }
1068 :
1069 1 : if (lease->subnet_mask == INADDR_ANY) {
1070 0 : r = dhcp_lease_set_default_subnet_mask(lease);
1071 0 : if (r < 0) {
1072 0 : log_dhcp_client(client, "received lease lacks subnet "
1073 : "mask, and a fallback one can not be "
1074 : "generated, ignoring");
1075 0 : return -ENOMSG;
1076 : }
1077 : }
1078 :
1079 1 : sd_dhcp_lease_unref(client->lease);
1080 1 : client->lease = lease;
1081 1 : lease = NULL;
1082 :
1083 1 : log_dhcp_client(client, "OFFER");
1084 :
1085 1 : return 0;
1086 : }
1087 :
1088 0 : static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
1089 : size_t len) {
1090 : int r;
1091 :
1092 0 : r = dhcp_option_parse(force, len, NULL, NULL);
1093 0 : if (r != DHCP_FORCERENEW)
1094 0 : return -ENOMSG;
1095 :
1096 0 : log_dhcp_client(client, "FORCERENEW");
1097 :
1098 0 : return 0;
1099 : }
1100 :
1101 1 : static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
1102 : size_t len) {
1103 2 : _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
1104 : int r;
1105 :
1106 1 : r = dhcp_lease_new(&lease);
1107 1 : if (r < 0)
1108 0 : return r;
1109 :
1110 1 : if (client->client_id_len) {
1111 2 : r = dhcp_lease_set_client_id(lease,
1112 1 : (uint8_t *) &client->client_id,
1113 : client->client_id_len);
1114 1 : if (r < 0)
1115 0 : return r;
1116 : }
1117 :
1118 1 : r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
1119 1 : if (r == DHCP_NAK) {
1120 0 : log_dhcp_client(client, "NAK");
1121 0 : return -EADDRNOTAVAIL;
1122 : }
1123 :
1124 1 : if (r != DHCP_ACK) {
1125 0 : log_dhcp_client(client, "received message was not an ACK, ignoring");
1126 0 : return -ENOMSG;
1127 : }
1128 :
1129 1 : lease->next_server = ack->siaddr;
1130 :
1131 1 : lease->address = ack->yiaddr;
1132 :
1133 2 : if (lease->address == INADDR_ANY ||
1134 2 : lease->server_address == INADDR_ANY ||
1135 1 : lease->lifetime == 0) {
1136 0 : log_dhcp_client(client, "received lease lacks address, server "
1137 : "address or lease lifetime, ignoring");
1138 0 : return -ENOMSG;
1139 : }
1140 :
1141 1 : if (lease->subnet_mask == INADDR_ANY) {
1142 0 : r = dhcp_lease_set_default_subnet_mask(lease);
1143 0 : if (r < 0) {
1144 0 : log_dhcp_client(client, "received lease lacks subnet "
1145 : "mask, and a fallback one can not be "
1146 : "generated, ignoring");
1147 0 : return -ENOMSG;
1148 : }
1149 : }
1150 :
1151 1 : r = DHCP_EVENT_IP_ACQUIRE;
1152 1 : if (client->lease) {
1153 2 : if (client->lease->address != lease->address ||
1154 2 : client->lease->subnet_mask != lease->subnet_mask ||
1155 1 : client->lease->router != lease->router) {
1156 0 : r = DHCP_EVENT_IP_CHANGE;
1157 : } else
1158 1 : r = DHCP_EVENT_RENEW;
1159 :
1160 1 : client->lease = sd_dhcp_lease_unref(client->lease);
1161 : }
1162 :
1163 1 : client->lease = lease;
1164 1 : lease = NULL;
1165 :
1166 1 : log_dhcp_client(client, "ACK");
1167 :
1168 1 : return r;
1169 : }
1170 :
1171 3 : static uint64_t client_compute_timeout(sd_dhcp_client *client,
1172 : uint32_t lifetime, double factor) {
1173 3 : assert(client);
1174 3 : assert(client->request_sent);
1175 3 : assert(lifetime);
1176 :
1177 6 : return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
1178 3 : + (random_u32() & 0x1fffff);
1179 : }
1180 :
1181 1 : static int client_set_lease_timeouts(sd_dhcp_client *client) {
1182 : usec_t time_now;
1183 : uint64_t lifetime_timeout;
1184 : uint64_t t2_timeout;
1185 : uint64_t t1_timeout;
1186 : char time_string[FORMAT_TIMESPAN_MAX];
1187 : int r;
1188 :
1189 1 : assert(client);
1190 1 : assert(client->event);
1191 1 : assert(client->lease);
1192 1 : assert(client->lease->lifetime);
1193 :
1194 1 : client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1195 1 : client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1196 1 : client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1197 :
1198 : /* don't set timers for infinite leases */
1199 1 : if (client->lease->lifetime == 0xffffffff)
1200 0 : return 0;
1201 :
1202 1 : r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1203 1 : if (r < 0)
1204 0 : return r;
1205 1 : assert(client->request_sent <= time_now);
1206 :
1207 : /* convert the various timeouts from relative (secs) to absolute (usecs) */
1208 1 : lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1209 1 : if (client->lease->t1 && client->lease->t2) {
1210 : /* both T1 and T2 are given */
1211 0 : if (client->lease->t1 < client->lease->t2 &&
1212 0 : client->lease->t2 < client->lease->lifetime) {
1213 : /* they are both valid */
1214 0 : t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1215 0 : t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1216 : } else {
1217 : /* discard both */
1218 0 : t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1219 0 : client->lease->t2 = (client->lease->lifetime * 7) / 8;
1220 0 : t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1221 0 : client->lease->t1 = client->lease->lifetime / 2;
1222 : }
1223 1 : } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1224 : /* only T2 is given, and it is valid */
1225 0 : t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1226 0 : t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1227 0 : client->lease->t1 = client->lease->lifetime / 2;
1228 0 : if (t2_timeout <= t1_timeout) {
1229 : /* the computed T1 would be invalid, so discard T2 */
1230 0 : t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1231 0 : client->lease->t2 = (client->lease->lifetime * 7) / 8;
1232 : }
1233 1 : } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1234 : /* only T1 is given, and it is valid */
1235 0 : t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1236 0 : t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1237 0 : client->lease->t2 = (client->lease->lifetime * 7) / 8;
1238 0 : if (t2_timeout <= t1_timeout) {
1239 : /* the computed T2 would be invalid, so discard T1 */
1240 0 : t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1241 0 : client->lease->t2 = client->lease->lifetime / 2;
1242 : }
1243 : } else {
1244 : /* fall back to the default timeouts */
1245 1 : t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1246 1 : client->lease->t1 = client->lease->lifetime / 2;
1247 1 : t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1248 1 : client->lease->t2 = (client->lease->lifetime * 7) / 8;
1249 : }
1250 :
1251 : /* arm lifetime timeout */
1252 1 : r = sd_event_add_time(client->event, &client->timeout_expire,
1253 : clock_boottime_or_monotonic(),
1254 : lifetime_timeout, 10 * USEC_PER_MSEC,
1255 : client_timeout_expire, client);
1256 1 : if (r < 0)
1257 0 : return r;
1258 :
1259 1 : r = sd_event_source_set_priority(client->timeout_expire,
1260 1 : client->event_priority);
1261 1 : if (r < 0)
1262 0 : return r;
1263 :
1264 1 : r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
1265 1 : if (r < 0)
1266 0 : return r;
1267 :
1268 1 : log_dhcp_client(client, "lease expires in %s",
1269 : format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1270 : lifetime_timeout - time_now, 0));
1271 :
1272 : /* don't arm earlier timeouts if this has already expired */
1273 1 : if (lifetime_timeout <= time_now)
1274 0 : return 0;
1275 :
1276 : /* arm T2 timeout */
1277 1 : r = sd_event_add_time(client->event,
1278 : &client->timeout_t2,
1279 : clock_boottime_or_monotonic(),
1280 : t2_timeout,
1281 : 10 * USEC_PER_MSEC,
1282 : client_timeout_t2, client);
1283 1 : if (r < 0)
1284 0 : return r;
1285 :
1286 1 : r = sd_event_source_set_priority(client->timeout_t2,
1287 1 : client->event_priority);
1288 1 : if (r < 0)
1289 0 : return r;
1290 :
1291 1 : r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
1292 1 : if (r < 0)
1293 0 : return r;
1294 :
1295 1 : log_dhcp_client(client, "T2 expires in %s",
1296 : format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1297 : t2_timeout - time_now, 0));
1298 :
1299 : /* don't arm earlier timeout if this has already expired */
1300 1 : if (t2_timeout <= time_now)
1301 0 : return 0;
1302 :
1303 : /* arm T1 timeout */
1304 1 : r = sd_event_add_time(client->event,
1305 : &client->timeout_t1,
1306 : clock_boottime_or_monotonic(),
1307 : t1_timeout, 10 * USEC_PER_MSEC,
1308 : client_timeout_t1, client);
1309 1 : if (r < 0)
1310 0 : return r;
1311 :
1312 1 : r = sd_event_source_set_priority(client->timeout_t1,
1313 1 : client->event_priority);
1314 1 : if (r < 0)
1315 0 : return r;
1316 :
1317 1 : r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
1318 1 : if (r < 0)
1319 0 : return r;
1320 :
1321 1 : log_dhcp_client(client, "T1 expires in %s",
1322 : format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1323 : t1_timeout - time_now, 0));
1324 :
1325 1 : return 0;
1326 : }
1327 :
1328 2 : static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1329 : int len) {
1330 4 : DHCP_CLIENT_DONT_DESTROY(client);
1331 2 : int r = 0, notify_event = 0;
1332 :
1333 2 : assert(client);
1334 2 : assert(client->event);
1335 2 : assert(message);
1336 :
1337 2 : switch (client->state) {
1338 : case DHCP_STATE_SELECTING:
1339 :
1340 1 : r = client_handle_offer(client, message, len);
1341 1 : if (r >= 0) {
1342 :
1343 1 : client->timeout_resend =
1344 1 : sd_event_source_unref(client->timeout_resend);
1345 :
1346 1 : client->state = DHCP_STATE_REQUESTING;
1347 1 : client->attempt = 1;
1348 :
1349 1 : r = sd_event_add_time(client->event,
1350 : &client->timeout_resend,
1351 : clock_boottime_or_monotonic(),
1352 : 0, 0,
1353 : client_timeout_resend, client);
1354 1 : if (r < 0)
1355 0 : goto error;
1356 :
1357 1 : r = sd_event_source_set_priority(client->timeout_resend,
1358 1 : client->event_priority);
1359 1 : if (r < 0)
1360 0 : goto error;
1361 :
1362 1 : r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
1363 1 : if (r < 0)
1364 0 : goto error;
1365 0 : } else if (r == -ENOMSG)
1366 : /* invalid message, let's ignore it */
1367 0 : return 0;
1368 :
1369 1 : break;
1370 :
1371 : case DHCP_STATE_REBOOTING:
1372 : case DHCP_STATE_REQUESTING:
1373 : case DHCP_STATE_RENEWING:
1374 : case DHCP_STATE_REBINDING:
1375 :
1376 1 : r = client_handle_ack(client, message, len);
1377 1 : if (r >= 0) {
1378 1 : client->timeout_resend =
1379 1 : sd_event_source_unref(client->timeout_resend);
1380 1 : client->receive_message =
1381 1 : sd_event_source_unref(client->receive_message);
1382 1 : client->fd = asynchronous_close(client->fd);
1383 :
1384 1 : if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1385 : DHCP_STATE_REBOOTING))
1386 1 : notify_event = DHCP_EVENT_IP_ACQUIRE;
1387 0 : else if (r != DHCP_EVENT_IP_ACQUIRE)
1388 0 : notify_event = r;
1389 :
1390 1 : client->state = DHCP_STATE_BOUND;
1391 1 : client->attempt = 1;
1392 :
1393 1 : client->last_addr = client->lease->address;
1394 :
1395 1 : r = client_set_lease_timeouts(client);
1396 1 : if (r < 0) {
1397 0 : log_dhcp_client(client, "could not set lease timeouts");
1398 0 : goto error;
1399 : }
1400 :
1401 1 : r = dhcp_network_bind_udp_socket(client->lease->address,
1402 : DHCP_PORT_CLIENT);
1403 1 : if (r < 0) {
1404 0 : log_dhcp_client(client, "could not bind UDP socket");
1405 0 : goto error;
1406 : }
1407 :
1408 1 : client->fd = r;
1409 :
1410 1 : client_initialize_io_events(client, client_receive_message_udp);
1411 :
1412 1 : if (notify_event) {
1413 1 : client_notify(client, notify_event);
1414 1 : if (client->state == DHCP_STATE_STOPPED)
1415 0 : return 0;
1416 : }
1417 :
1418 0 : } else if (r == -EADDRNOTAVAIL) {
1419 : /* got a NAK, let's restart the client */
1420 0 : client->timeout_resend =
1421 0 : sd_event_source_unref(client->timeout_resend);
1422 :
1423 0 : r = client_initialize(client);
1424 0 : if (r < 0)
1425 0 : goto error;
1426 :
1427 0 : r = client_start(client);
1428 0 : if (r < 0)
1429 0 : goto error;
1430 :
1431 0 : log_dhcp_client(client, "REBOOTED");
1432 :
1433 0 : return 0;
1434 0 : } else if (r == -ENOMSG)
1435 : /* invalid message, let's ignore it */
1436 0 : return 0;
1437 :
1438 1 : break;
1439 :
1440 : case DHCP_STATE_BOUND:
1441 0 : r = client_handle_forcerenew(client, message, len);
1442 0 : if (r >= 0) {
1443 0 : r = client_timeout_t1(NULL, 0, client);
1444 0 : if (r < 0)
1445 0 : goto error;
1446 0 : } else if (r == -ENOMSG)
1447 : /* invalid message, let's ignore it */
1448 0 : return 0;
1449 :
1450 0 : break;
1451 :
1452 : case DHCP_STATE_INIT:
1453 : case DHCP_STATE_INIT_REBOOT:
1454 :
1455 0 : break;
1456 :
1457 : case DHCP_STATE_STOPPED:
1458 0 : r = -EINVAL;
1459 0 : goto error;
1460 : }
1461 :
1462 : error:
1463 2 : if (r < 0)
1464 0 : client_stop(client, r);
1465 :
1466 2 : return r;
1467 : }
1468 :
1469 0 : static int client_receive_message_udp(sd_event_source *s, int fd,
1470 : uint32_t revents, void *userdata) {
1471 0 : sd_dhcp_client *client = userdata;
1472 0 : _cleanup_free_ DHCPMessage *message = NULL;
1473 0 : int buflen = 0, len, r;
1474 0 : const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
1475 0 : const struct ether_addr *expected_chaddr = NULL;
1476 0 : uint8_t expected_hlen = 0;
1477 :
1478 0 : assert(s);
1479 0 : assert(client);
1480 :
1481 0 : r = ioctl(fd, FIONREAD, &buflen);
1482 0 : if (r < 0)
1483 0 : return r;
1484 :
1485 0 : if (buflen < 0)
1486 : /* this can't be right */
1487 0 : return -EIO;
1488 :
1489 0 : message = malloc0(buflen);
1490 0 : if (!message)
1491 0 : return -ENOMEM;
1492 :
1493 0 : len = read(fd, message, buflen);
1494 0 : if (len < 0) {
1495 0 : log_dhcp_client(client, "could not receive message from UDP "
1496 : "socket: %m");
1497 0 : return 0;
1498 0 : } else if ((size_t)len < sizeof(DHCPMessage)) {
1499 0 : log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1500 0 : return 0;
1501 : }
1502 :
1503 0 : if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1504 0 : log_dhcp_client(client, "not a DHCP message: ignoring");
1505 0 : return 0;
1506 : }
1507 :
1508 0 : if (message->op != BOOTREPLY) {
1509 0 : log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1510 0 : return 0;
1511 : }
1512 :
1513 0 : if (message->htype != client->arp_type) {
1514 0 : log_dhcp_client(client, "packet type does not match client type");
1515 0 : return 0;
1516 : }
1517 :
1518 0 : if (client->arp_type == ARPHRD_ETHER) {
1519 0 : expected_hlen = ETH_ALEN;
1520 0 : expected_chaddr = (const struct ether_addr *) &client->mac_addr;
1521 : } else {
1522 : /* Non-ethernet links expect zero chaddr */
1523 0 : expected_hlen = 0;
1524 0 : expected_chaddr = &zero_mac;
1525 : }
1526 :
1527 0 : if (message->hlen != expected_hlen) {
1528 0 : log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
1529 0 : return 0;
1530 : }
1531 :
1532 0 : if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
1533 0 : log_dhcp_client(client, "received chaddr does not match "
1534 : "expected: ignoring");
1535 0 : return 0;
1536 : }
1537 :
1538 0 : if (client->state != DHCP_STATE_BOUND &&
1539 0 : be32toh(message->xid) != client->xid) {
1540 : /* in BOUND state, we may receive FORCERENEW with xid set by server,
1541 : so ignore the xid in this case */
1542 0 : log_dhcp_client(client, "received xid (%u) does not match "
1543 : "expected (%u): ignoring",
1544 : be32toh(message->xid), client->xid);
1545 0 : return 0;
1546 : }
1547 :
1548 0 : return client_handle_message(client, message, len);
1549 : }
1550 :
1551 2 : static int client_receive_message_raw(sd_event_source *s, int fd,
1552 : uint32_t revents, void *userdata) {
1553 2 : sd_dhcp_client *client = userdata;
1554 4 : _cleanup_free_ DHCPPacket *packet = NULL;
1555 : uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1556 2 : struct iovec iov = {};
1557 2 : struct msghdr msg = {
1558 : .msg_iov = &iov,
1559 : .msg_iovlen = 1,
1560 : .msg_control = cmsgbuf,
1561 : .msg_controllen = sizeof(cmsgbuf),
1562 : };
1563 : struct cmsghdr *cmsg;
1564 2 : bool checksum = true;
1565 2 : int buflen = 0, len, r;
1566 :
1567 2 : assert(s);
1568 2 : assert(client);
1569 :
1570 2 : r = ioctl(fd, FIONREAD, &buflen);
1571 2 : if (r < 0)
1572 0 : return r;
1573 :
1574 2 : if (buflen < 0)
1575 : /* this can't be right */
1576 0 : return -EIO;
1577 :
1578 2 : packet = malloc0(buflen);
1579 2 : if (!packet)
1580 0 : return -ENOMEM;
1581 :
1582 2 : iov.iov_base = packet;
1583 2 : iov.iov_len = buflen;
1584 :
1585 2 : len = recvmsg(fd, &msg, 0);
1586 2 : if (len < 0) {
1587 0 : log_dhcp_client(client, "could not receive message from raw "
1588 : "socket: %m");
1589 0 : return 0;
1590 2 : } else if ((size_t)len < sizeof(DHCPPacket))
1591 0 : return 0;
1592 :
1593 2 : CMSG_FOREACH(cmsg, &msg) {
1594 0 : if (cmsg->cmsg_level == SOL_PACKET &&
1595 0 : cmsg->cmsg_type == PACKET_AUXDATA &&
1596 0 : cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1597 0 : struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1598 :
1599 0 : checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1600 0 : break;
1601 : }
1602 : }
1603 :
1604 2 : r = dhcp_packet_verify_headers(packet, len, checksum);
1605 2 : if (r < 0)
1606 0 : return 0;
1607 :
1608 2 : len -= DHCP_IP_UDP_SIZE;
1609 :
1610 2 : return client_handle_message(client, &packet->dhcp, len);
1611 : }
1612 :
1613 2 : int sd_dhcp_client_start(sd_dhcp_client *client) {
1614 : int r;
1615 :
1616 2 : assert_return(client, -EINVAL);
1617 :
1618 2 : r = client_initialize(client);
1619 2 : if (r < 0)
1620 0 : return r;
1621 :
1622 2 : if (client->last_addr)
1623 0 : client->state = DHCP_STATE_INIT_REBOOT;
1624 :
1625 2 : r = client_start(client);
1626 2 : if (r >= 0)
1627 2 : log_dhcp_client(client, "STARTED on ifindex %i", client->index);
1628 :
1629 2 : return r;
1630 : }
1631 :
1632 2 : int sd_dhcp_client_stop(sd_dhcp_client *client) {
1633 4 : DHCP_CLIENT_DONT_DESTROY(client);
1634 :
1635 2 : assert_return(client, -EINVAL);
1636 :
1637 2 : client_stop(client, DHCP_EVENT_STOP);
1638 2 : client->state = DHCP_STATE_STOPPED;
1639 :
1640 2 : return 0;
1641 : }
1642 :
1643 3 : int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1644 : int priority) {
1645 : int r;
1646 :
1647 3 : assert_return(client, -EINVAL);
1648 3 : assert_return(!client->event, -EBUSY);
1649 :
1650 3 : if (event)
1651 3 : client->event = sd_event_ref(event);
1652 : else {
1653 0 : r = sd_event_default(&client->event);
1654 0 : if (r < 0)
1655 0 : return 0;
1656 : }
1657 :
1658 3 : client->event_priority = priority;
1659 :
1660 3 : return 0;
1661 : }
1662 :
1663 3 : int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1664 3 : assert_return(client, -EINVAL);
1665 :
1666 3 : client->event = sd_event_unref(client->event);
1667 :
1668 3 : return 0;
1669 : }
1670 :
1671 0 : sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1672 0 : if (!client)
1673 0 : return NULL;
1674 :
1675 0 : return client->event;
1676 : }
1677 :
1678 9 : sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1679 9 : if (client)
1680 9 : assert_se(REFCNT_INC(client->n_ref) >= 2);
1681 :
1682 9 : return client;
1683 : }
1684 :
1685 16 : sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1686 16 : if (client && REFCNT_DEC(client->n_ref) == 0) {
1687 3 : log_dhcp_client(client, "FREE");
1688 :
1689 3 : client_initialize(client);
1690 :
1691 3 : client->receive_message =
1692 3 : sd_event_source_unref(client->receive_message);
1693 :
1694 3 : sd_dhcp_client_detach_event(client);
1695 :
1696 3 : sd_dhcp_lease_unref(client->lease);
1697 :
1698 3 : free(client->req_opts);
1699 3 : free(client->hostname);
1700 3 : free(client->vendor_class_identifier);
1701 3 : free(client);
1702 : }
1703 :
1704 16 : return NULL;
1705 : }
1706 :
1707 3 : int sd_dhcp_client_new(sd_dhcp_client **ret) {
1708 6 : _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1709 :
1710 3 : assert_return(ret, -EINVAL);
1711 :
1712 3 : client = new0(sd_dhcp_client, 1);
1713 3 : if (!client)
1714 0 : return -ENOMEM;
1715 :
1716 3 : client->n_ref = REFCNT_INIT;
1717 3 : client->state = DHCP_STATE_INIT;
1718 3 : client->index = -1;
1719 3 : client->fd = -1;
1720 3 : client->attempt = 1;
1721 3 : client->mtu = DHCP_DEFAULT_MIN_SIZE;
1722 :
1723 3 : client->req_opts_size = ELEMENTSOF(default_req_opts);
1724 :
1725 3 : client->req_opts = memdup(default_req_opts, client->req_opts_size);
1726 3 : if (!client->req_opts)
1727 0 : return -ENOMEM;
1728 :
1729 3 : *ret = client;
1730 3 : client = NULL;
1731 :
1732 3 : return 0;
1733 : }
|