Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/libsystemd-network/sd-dhcp-client.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
/***
3
  Copyright © 2013 Intel Corporation. All rights reserved.
4
***/
5
6
#include <errno.h>
7
#include <net/ethernet.h>
8
#include <net/if_arp.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <sys/ioctl.h>
13
#include <linux/if_infiniband.h>
14
15
#include "sd-dhcp-client.h"
16
17
#include "alloc-util.h"
18
#include "async.h"
19
#include "dhcp-identifier.h"
20
#include "dhcp-internal.h"
21
#include "dhcp-lease-internal.h"
22
#include "dhcp-protocol.h"
23
#include "dns-domain.h"
24
#include "event-util.h"
25
#include "hostname-util.h"
26
#include "io-util.h"
27
#include "memory-util.h"
28
#include "random-util.h"
29
#include "string-util.h"
30
#include "strv.h"
31
32
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN)  /* Arbitrary limit */
33
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
34
35
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
36
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
37
38
struct sd_dhcp_client {
39
        unsigned n_ref;
40
41
        DHCPState state;
42
        sd_event *event;
43
        int event_priority;
44
        sd_event_source *timeout_resend;
45
        int ifindex;
46
        int fd;
47
        uint16_t port;
48
        union sockaddr_union link;
49
        sd_event_source *receive_message;
50
        bool request_broadcast;
51
        uint8_t *req_opts;
52
        size_t req_opts_allocated;
53
        size_t req_opts_size;
54
        bool anonymize;
55
        be32_t last_addr;
56
        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
57
        size_t mac_addr_len;
58
        uint16_t arp_type;
59
        struct {
60
                uint8_t type;
61
                union {
62
                        struct {
63
                                /* 0: Generic (non-LL) (RFC 2132) */
64
                                uint8_t data[MAX_CLIENT_ID_LEN];
65
                        } _packed_ gen;
66
                        struct {
67
                                /* 1: Ethernet Link-Layer (RFC 2132) */
68
                                uint8_t haddr[ETH_ALEN];
69
                        } _packed_ eth;
70
                        struct {
71
                                /* 2 - 254: ARP/Link-Layer (RFC 2132) */
72
                                uint8_t haddr[0];
73
                        } _packed_ ll;
74
                        struct {
75
                                /* 255: Node-specific (RFC 4361) */
76
                                be32_t iaid;
77
                                struct duid duid;
78
                        } _packed_ ns;
79
                        struct {
80
                                uint8_t data[MAX_CLIENT_ID_LEN];
81
                        } _packed_ raw;
82
                };
83
        } _packed_ client_id;
84
        size_t client_id_len;
85
        char *hostname;
86
        char *vendor_class_identifier;
87
        char **user_class;
88
        uint32_t mtu;
89
        uint32_t xid;
90
        usec_t start_time;
91
        uint64_t attempt;
92
        uint64_t max_attempts;
93
        usec_t request_sent;
94
        sd_event_source *timeout_t1;
95
        sd_event_source *timeout_t2;
96
        sd_event_source *timeout_expire;
97
        sd_dhcp_client_callback_t callback;
98
        void *userdata;
99
        sd_dhcp_lease *lease;
100
        usec_t start_delay;
101
};
102
103
static const uint8_t default_req_opts[] = {
104
        SD_DHCP_OPTION_SUBNET_MASK,
105
        SD_DHCP_OPTION_ROUTER,
106
        SD_DHCP_OPTION_HOST_NAME,
107
        SD_DHCP_OPTION_DOMAIN_NAME,
108
        SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
109
};
110
111
/* RFC7844 section 3:
112
   MAY contain the Parameter Request List option.
113
   RFC7844 section 3.6:
114
   The client intending to protect its privacy SHOULD only request a
115
   minimal number of options in the PRL and SHOULD also randomly shuffle
116
   the ordering of option codes in the PRL.  If this random ordering
117
   cannot be implemented, the client MAY order the option codes in the
118
   PRL by option code number (lowest to highest).
119
*/
120
/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
121
static const uint8_t default_req_opts_anonymize[] = {
122
        SD_DHCP_OPTION_SUBNET_MASK,                     /* 1 */
123
        SD_DHCP_OPTION_ROUTER,                          /* 3 */
124
        SD_DHCP_OPTION_DOMAIN_NAME_SERVER,              /* 6 */
125
        SD_DHCP_OPTION_DOMAIN_NAME,                     /* 15 */
126
        SD_DHCP_OPTION_ROUTER_DISCOVER,                 /* 31 */
127
        SD_DHCP_OPTION_STATIC_ROUTE,                    /* 33 */
128
        SD_DHCP_OPTION_VENDOR_SPECIFIC,                 /* 43 */
129
        SD_DHCP_OPTION_NETBIOS_NAMESERVER,              /* 44 */
130
        SD_DHCP_OPTION_NETBIOS_NODETYPE,                /* 46 */
131
        SD_DHCP_OPTION_NETBIOS_SCOPE,                   /* 47 */
132
        SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE,          /* 121 */
133
        SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE,  /* 249 */
134
        SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY,     /* 252 */
135
};
136
137
static int client_receive_message_raw(
138
                sd_event_source *s,
139
                int fd,
140
                uint32_t revents,
141
                void *userdata);
142
static int client_receive_message_udp(
143
                sd_event_source *s,
144
                int fd,
145
                uint32_t revents,
146
                void *userdata);
147
static void client_stop(sd_dhcp_client *client, int error);
148
149
int sd_dhcp_client_set_callback(
150
                sd_dhcp_client *client,
151
                sd_dhcp_client_callback_t cb,
152
0
                void *userdata) {
153
0
154
0
        assert_return(client, -EINVAL);
155
0
156
0
        client->callback = cb;
157
0
        client->userdata = userdata;
158
0
159
0
        return 0;
160
0
}
161
162
0
int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
163
0
        assert_return(client, -EINVAL);
164
0
165
0
        client->request_broadcast = !!broadcast;
166
0
167
0
        return 0;
168
0
}
169
170
0
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
171
0
        size_t i;
172
0
173
0
        assert_return(client, -EINVAL);
174
0
        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
175
0
176
0
        switch(option) {
177
0
178
0
        case SD_DHCP_OPTION_PAD:
179
0
        case SD_DHCP_OPTION_OVERLOAD:
180
0
        case SD_DHCP_OPTION_MESSAGE_TYPE:
181
0
        case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
182
0
        case SD_DHCP_OPTION_END:
183
0
                return -EINVAL;
184
0
185
0
        default:
186
0
                break;
187
0
        }
188
0
189
0
        for (i = 0; i < client->req_opts_size; i++)
190
0
                if (client->req_opts[i] == option)
191
0
                        return -EEXIST;
192
0
193
0
        if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
194
0
                            client->req_opts_size + 1))
195
0
                return -ENOMEM;
196
0
197
0
        client->req_opts[client->req_opts_size++] = option;
198
0
199
0
        return 0;
200
0
}
201
202
int sd_dhcp_client_set_request_address(
203
                sd_dhcp_client *client,
204
0
                const struct in_addr *last_addr) {
205
0
206
0
        assert_return(client, -EINVAL);
207
0
        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
208
0
209
0
        if (last_addr)
210
0
                client->last_addr = last_addr->s_addr;
211
0
        else
212
0
                client->last_addr = INADDR_ANY;
213
0
214
0
        return 0;
215
0
}
216
217
0
int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
218
0
219
0
        assert_return(client, -EINVAL);
220
0
        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
221
0
        assert_return(ifindex > 0, -EINVAL);
222
0
223
0
        client->ifindex = ifindex;
224
0
        return 0;
225
0
}
226
227
int sd_dhcp_client_set_mac(
228
                sd_dhcp_client *client,
229
                const uint8_t *addr,
230
                size_t addr_len,
231
0
                uint16_t arp_type) {
232
0
233
0
        DHCP_CLIENT_DONT_DESTROY(client);
234
0
        bool need_restart = false;
235
0
236
0
        assert_return(client, -EINVAL);
237
0
        assert_return(addr, -EINVAL);
238
0
        assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
239
0
        assert_return(arp_type > 0, -EINVAL);
240
0
241
0
        if (arp_type == ARPHRD_ETHER)
242
0
                assert_return(addr_len == ETH_ALEN, -EINVAL);
243
0
        else if (arp_type == ARPHRD_INFINIBAND)
244
0
                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
245
0
        else
246
0
                return -EINVAL;
247
0
248
0
        if (client->mac_addr_len == addr_len &&
249
0
            memcmp(&client->mac_addr, addr, addr_len) == 0)
250
0
                return 0;
251
0
252
0
        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
253
0
                log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
254
0
                need_restart = true;
255
0
                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
256
0
        }
257
0
258
0
        memcpy(&client->mac_addr, addr, addr_len);
259
0
        client->mac_addr_len = addr_len;
260
0
        client->arp_type = arp_type;
261
0
262
0
        if (need_restart && client->state != DHCP_STATE_STOPPED)
263
0
                sd_dhcp_client_start(client);
264
0
265
0
        return 0;
266
0
}
267
268
int sd_dhcp_client_get_client_id(
269
                sd_dhcp_client *client,
270
                uint8_t *type,
271
                const uint8_t **data,
272
0
                size_t *data_len) {
273
0
274
0
        assert_return(client, -EINVAL);
275
0
        assert_return(type, -EINVAL);
276
0
        assert_return(data, -EINVAL);
277
0
        assert_return(data_len, -EINVAL);
278
0
279
0
        *type = 0;
280
0
        *data = NULL;
281
0
        *data_len = 0;
282
0
        if (client->client_id_len) {
283
0
                *type = client->client_id.type;
284
0
                *data = client->client_id.raw.data;
285
0
                *data_len = client->client_id_len - sizeof(client->client_id.type);
286
0
        }
287
0
288
0
        return 0;
289
0
}
290
291
int sd_dhcp_client_set_client_id(
292
                sd_dhcp_client *client,
293
                uint8_t type,
294
                const uint8_t *data,
295
0
                size_t data_len) {
296
0
297
0
        DHCP_CLIENT_DONT_DESTROY(client);
298
0
        bool need_restart = false;
299
0
300
0
        assert_return(client, -EINVAL);
301
0
        assert_return(data, -EINVAL);
302
0
        assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
303
0
304
0
        if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
305
0
            client->client_id.type == type &&
306
0
            memcmp(&client->client_id.raw.data, data, data_len) == 0)
307
0
                return 0;
308
0
309
0
        /* For hardware types, log debug message about unexpected data length.
310
0
         *
311
0
         * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
312
0
         * last last 8 bytes of the address are stable and suitable to put into
313
0
         * the client-id. The caller is advised to account for that. */
314
0
        if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
315
0
            (type == ARPHRD_INFINIBAND && data_len != 8))
316
0
                log_dhcp_client(client, "Changing client ID to hardware type %u with "
317
0
                                "unexpected address length %zu",
318
0
                                type, data_len);
319
0
320
0
        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
321
0
                log_dhcp_client(client, "Changing client ID on running DHCP "
322
0
                                "client, restarting");
323
0
                need_restart = true;
324
0
                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
325
0
        }
326
0
327
0
        client->client_id.type = type;
328
0
        memcpy(&client->client_id.raw.data, data, data_len);
329
0
        client->client_id_len = data_len + sizeof (client->client_id.type);
330
0
331
0
        if (need_restart && client->state != DHCP_STATE_STOPPED)
332
0
                sd_dhcp_client_start(client);
333
0
334
0
        return 0;
335
0
}
336
337
/**
338
 * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
339
 * without further modification. Otherwise, if duid_type is supported, DUID
340
 * is set based on that type. Otherwise, an error is returned.
341
 */
342
static int dhcp_client_set_iaid_duid_internal(
343
                sd_dhcp_client *client,
344
                bool iaid_append,
345
                bool iaid_set,
346
                uint32_t iaid,
347
                uint16_t duid_type,
348
                const void *duid,
349
                size_t duid_len,
350
0
                usec_t llt_time) {
351
0
352
0
        DHCP_CLIENT_DONT_DESTROY(client);
353
0
        int r;
354
0
        size_t len;
355
0
356
0
        assert_return(client, -EINVAL);
357
0
        assert_return(duid_len == 0 || duid, -EINVAL);
358
0
359
0
        if (duid) {
360
0
                r = dhcp_validate_duid_len(duid_type, duid_len, true);
361
0
                if (r < 0)
362
0
                        return r;
363
0
        }
364
0
365
0
        zero(client->client_id);
366
0
        client->client_id.type = 255;
367
0
368
0
        if (iaid_append) {
369
0
                if (iaid_set)
370
0
                        client->client_id.ns.iaid = htobe32(iaid);
371
0
                else {
372
0
                        r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
373
0
                                                     client->mac_addr_len,
374
0
                                                     true,
375
0
                                                     &client->client_id.ns.iaid);
376
0
                        if (r < 0)
377
0
                                return r;
378
0
                }
379
0
        }
380
0
381
0
        if (duid) {
382
0
                client->client_id.ns.duid.type = htobe16(duid_type);
383
0
                memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
384
0
                len = sizeof(client->client_id.ns.duid.type) + duid_len;
385
0
        } else
386
0
                switch (duid_type) {
387
0
                case DUID_TYPE_LLT:
388
0
                        if (client->mac_addr_len == 0)
389
0
                                return -EOPNOTSUPP;
390
0
391
0
                        r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
392
0
                        if (r < 0)
393
0
                                return r;
394
0
                        break;
395
0
                case DUID_TYPE_EN:
396
0
                        r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
397
0
                        if (r < 0)
398
0
                                return r;
399
0
                        break;
400
0
                case DUID_TYPE_LL:
401
0
                        if (client->mac_addr_len == 0)
402
0
                                return -EOPNOTSUPP;
403
0
404
0
                        r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
405
0
                        if (r < 0)
406
0
                                return r;
407
0
                        break;
408
0
                case DUID_TYPE_UUID:
409
0
                        r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
410
0
                        if (r < 0)
411
0
                                return r;
412
0
                        break;
413
0
                default:
414
0
                        return -EINVAL;
415
0
                }
416
0
417
0
        client->client_id_len = sizeof(client->client_id.type) + len +
418
0
                                (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
419
0
420
0
        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
421
0
                log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
422
0
                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
423
0
                sd_dhcp_client_start(client);
424
0
        }
425
0
426
0
        return 0;
427
0
}
428
429
int sd_dhcp_client_set_iaid_duid(
430
                sd_dhcp_client *client,
431
                bool iaid_set,
432
                uint32_t iaid,
433
                uint16_t duid_type,
434
                const void *duid,
435
0
                size_t duid_len) {
436
0
        return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0);
437
0
}
438
439
int sd_dhcp_client_set_iaid_duid_llt(
440
                sd_dhcp_client *client,
441
                bool iaid_set,
442
                uint32_t iaid,
443
0
                usec_t llt_time) {
444
0
        return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time);
445
0
}
446
447
int sd_dhcp_client_set_duid(
448
                sd_dhcp_client *client,
449
                uint16_t duid_type,
450
                const void *duid,
451
0
                size_t duid_len) {
452
0
        return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0);
453
0
}
454
455
int sd_dhcp_client_set_duid_llt(
456
                sd_dhcp_client *client,
457
0
                usec_t llt_time) {
458
0
        return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time);
459
0
}
460
461
int sd_dhcp_client_set_hostname(
462
                sd_dhcp_client *client,
463
0
                const char *hostname) {
464
0
465
0
        assert_return(client, -EINVAL);
466
0
467
0
        /* Make sure hostnames qualify as DNS and as Linux hostnames */
468
0
        if (hostname &&
469
0
            !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
470
0
                return -EINVAL;
471
0
472
0
        return free_and_strdup(&client->hostname, hostname);
473
0
}
474
475
int sd_dhcp_client_set_vendor_class_identifier(
476
                sd_dhcp_client *client,
477
0
                const char *vci) {
478
0
479
0
        assert_return(client, -EINVAL);
480
0
481
0
        return free_and_strdup(&client->vendor_class_identifier, vci);
482
0
}
483
484
int sd_dhcp_client_set_user_class(
485
                sd_dhcp_client *client,
486
0
                const char* const* user_class) {
487
0
488
0
        _cleanup_strv_free_ char **s = NULL;
489
0
        char **p;
490
0
491
0
        STRV_FOREACH(p, (char **) user_class)
492
0
                if (strlen(*p) > 255)
493
0
                        return -ENAMETOOLONG;
494
0
495
0
        s = strv_copy((char **) user_class);
496
0
        if (!s)
497
0
                return -ENOMEM;
498
0
499
0
        client->user_class = TAKE_PTR(s);
500
0
501
0
        return 0;
502
0
}
503
504
int sd_dhcp_client_set_client_port(
505
                sd_dhcp_client *client,
506
0
                uint16_t port) {
507
0
508
0
        assert_return(client, -EINVAL);
509
0
510
0
        client->port = port;
511
0
512
0
        return 0;
513
0
}
514
515
0
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
516
0
        assert_return(client, -EINVAL);
517
0
        assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
518
0
519
0
        client->mtu = mtu;
520
0
521
0
        return 0;
522
0
}
523
524
0
int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
525
0
        assert_return(client, -EINVAL);
526
0
527
0
        client->max_attempts = max_attempts;
528
0
529
0
        return 0;
530
0
}
531
532
0
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
533
0
        assert_return(client, -EINVAL);
534
0
535
0
        if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
536
0
                return -EADDRNOTAVAIL;
537
0
538
0
        if (ret)
539
0
                *ret = client->lease;
540
0
541
0
        return 0;
542
0
}
543
544
0
static int client_notify(sd_dhcp_client *client, int event) {
545
0
        assert(client);
546
0
547
0
        if (client->callback)
548
0
                return client->callback(client, event, client->userdata);
549
0
550
0
        return 0;
551
0
}
552
553
0
static int client_initialize(sd_dhcp_client *client) {
554
0
        assert_return(client, -EINVAL);
555
0
556
0
        client->receive_message = sd_event_source_unref(client->receive_message);
557
0
558
0
        client->fd = asynchronous_close(client->fd);
559
0
560
0
        (void) event_source_disable(client->timeout_resend);
561
0
        (void) event_source_disable(client->timeout_t1);
562
0
        (void) event_source_disable(client->timeout_t2);
563
0
        (void) event_source_disable(client->timeout_expire);
564
0
565
0
        client->attempt = 0;
566
0
567
0
        client->state = DHCP_STATE_INIT;
568
0
        client->xid = 0;
569
0
570
0
        client->lease = sd_dhcp_lease_unref(client->lease);
571
0
572
0
        return 0;
573
0
}
574
575
0
static void client_stop(sd_dhcp_client *client, int error) {
576
0
        assert(client);
577
0
578
0
        if (error < 0)
579
0
                log_dhcp_client(client, "STOPPED: %s", strerror(-error));
580
0
        else if (error == SD_DHCP_CLIENT_EVENT_STOP)
581
0
                log_dhcp_client(client, "STOPPED");
582
0
        else
583
0
                log_dhcp_client(client, "STOPPED: Unknown event");
584
0
585
0
        client_notify(client, error);
586
0
587
0
        client_initialize(client);
588
0
}
589
590
static int client_message_init(
591
                sd_dhcp_client *client,
592
                DHCPPacket **ret,
593
                uint8_t type,
594
                size_t *_optlen,
595
0
                size_t *_optoffset) {
596
0
597
0
        _cleanup_free_ DHCPPacket *packet = NULL;
598
0
        size_t optlen, optoffset, size;
599
0
        be16_t max_size;
600
0
        usec_t time_now;
601
0
        uint16_t secs;
602
0
        int r;
603
0
604
0
        assert(client);
605
0
        assert(client->start_time);
606
0
        assert(ret);
607
0
        assert(_optlen);
608
0
        assert(_optoffset);
609
0
        assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
610
0
611
0
        optlen = DHCP_MIN_OPTIONS_SIZE;
612
0
        size = sizeof(DHCPPacket) + optlen;
613
0
614
0
        packet = malloc0(size);
615
0
        if (!packet)
616
0
                return -ENOMEM;
617
0
618
0
        r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
619
0
                              client->arp_type, optlen, &optoffset);
620
0
        if (r < 0)
621
0
                return r;
622
0
623
0
        /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
624
0
           refuse to issue an DHCP lease if 'secs' is set to zero */
625
0
        r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
626
0
        if (r < 0)
627
0
                return r;
628
0
        assert(time_now >= client->start_time);
629
0
630
0
        /* seconds between sending first and last DISCOVER
631
0
         * must always be strictly positive to deal with broken servers */
632
0
        secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
633
0
        packet->dhcp.secs = htobe16(secs);
634
0
635
0
        /* RFC2132 section 4.1
636
0
           A client that cannot receive unicast IP datagrams until its protocol
637
0
           software has been configured with an IP address SHOULD set the
638
0
           BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
639
0
           DHCPREQUEST messages that client sends.  The BROADCAST bit will
640
0
           provide a hint to the DHCP server and BOOTP relay agent to broadcast
641
0
           any messages to the client on the client's subnet.
642
0
643
0
           Note: some interfaces needs this to be enabled, but some networks
644
0
           needs this to be disabled as broadcasts are filteretd, so this
645
0
           needs to be configurable */
646
0
        if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
647
0
                packet->dhcp.flags = htobe16(0x8000);
648
0
649
0
        /* RFC2132 section 4.1.1:
650
0
           The client MUST include its hardware address in the ’chaddr’ field, if
651
0
           necessary for delivery of DHCP reply messages.  Non-Ethernet
652
0
           interfaces will leave 'chaddr' empty and use the client identifier
653
0
           instead (eg, RFC 4390 section 2.1).
654
0
         */
655
0
        if (client->arp_type == ARPHRD_ETHER)
656
0
                memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
657
0
658
0
        /* If no client identifier exists, construct an RFC 4361-compliant one */
659
0
        if (client->client_id_len == 0) {
660
0
                size_t duid_len;
661
0
662
0
                client->client_id.type = 255;
663
0
664
0
                r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
665
0
                                             true, &client->client_id.ns.iaid);
666
0
                if (r < 0)
667
0
                        return r;
668
0
669
0
                r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
670
0
                if (r < 0)
671
0
                        return r;
672
0
673
0
                client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
674
0
        }
675
0
676
0
        /* Some DHCP servers will refuse to issue an DHCP lease if the Client
677
0
           Identifier option is not set */
678
0
        if (client->client_id_len) {
679
0
                r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
680
0
                                       SD_DHCP_OPTION_CLIENT_IDENTIFIER,
681
0
                                       client->client_id_len,
682
0
                                       &client->client_id);
683
0
                if (r < 0)
684
0
                        return r;
685
0
        }
686
0
687
0
        /* RFC2131 section 3.5:
688
0
           in its initial DHCPDISCOVER or DHCPREQUEST message, a
689
0
           client may provide the server with a list of specific
690
0
           parameters the client is interested in. If the client
691
0
           includes a list of parameters in a DHCPDISCOVER message,
692
0
           it MUST include that list in any subsequent DHCPREQUEST
693
0
           messages.
694
0
         */
695
0
696
0
        /* RFC7844 section 3:
697
0
           MAY contain the Parameter Request List option. */
698
0
        /* NOTE: in case that there would be an option to do not send
699
0
         * any PRL at all, the size should be checked before sending */
700
0
        if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
701
0
                r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
702
0
                                       SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
703
0
                                       client->req_opts_size, client->req_opts);
704
0
                if (r < 0)
705
0
                        return r;
706
0
        }
707
0
708
0
        /* RFC2131 section 3.5:
709
0
           The client SHOULD include the ’maximum DHCP message size’ option to
710
0
           let the server know how large the server may make its DHCP messages.
711
0
712
0
           Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
713
0
           than the defined default size unless the Maximum Message Size option
714
0
           is explicitly set
715
0
716
0
           RFC3442 "Requirements to Avoid Sizing Constraints":
717
0
           Because a full routing table can be quite large, the standard 576
718
0
           octet maximum size for a DHCP message may be too short to contain
719
0
           some legitimate Classless Static Route options.  Because of this,
720
0
           clients implementing the Classless Static Route option SHOULD send a
721
0
           Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
722
0
           stack is capable of receiving larger IP datagrams.  In this case, the
723
0
           client SHOULD set the value of this option to at least the MTU of the
724
0
           interface that the client is configuring.  The client MAY set the
725
0
           value of this option higher, up to the size of the largest UDP packet
726
0
           it is prepared to accept.  (Note that the value specified in the
727
0
           Maximum DHCP Message Size option is the total maximum packet size,
728
0
           including IP and UDP headers.)
729
0
         */
730
0
        /* RFC7844 section 3:
731
0
           SHOULD NOT contain any other option. */
732
0
        if (!client->anonymize && type != DHCP_RELEASE) {
733
0
                max_size = htobe16(size);
734
0
                r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
735
0
                                       SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
736
0
                                       2, &max_size);
737
0
                if (r < 0)
738
0
                        return r;
739
0
        }
740
0
741
0
        *_optlen = optlen;
742
0
        *_optoffset = optoffset;
743
0
        *ret = TAKE_PTR(packet);
744
0
745
0
        return 0;
746
0
}
747
748
static int client_append_fqdn_option(
749
                DHCPMessage *message,
750
                size_t optlen,
751
                size_t *optoffset,
752
0
                const char *fqdn) {
753
0
754
0
        uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
755
0
        int r;
756
0
757
0
        buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
758
0
                    DHCP_FQDN_FLAG_E;  /* Canonical wire format */
759
0
        buffer[1] = 0;                 /* RCODE1 (deprecated) */
760
0
        buffer[2] = 0;                 /* RCODE2 (deprecated) */
761
0
762
0
        r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
763
0
        if (r > 0)
764
0
                r = dhcp_option_append(message, optlen, optoffset, 0,
765
0
                                       SD_DHCP_OPTION_FQDN, 3 + r, buffer);
766
0
767
0
        return r;
768
0
}
769
770
static int dhcp_client_send_raw(
771
                sd_dhcp_client *client,
772
                DHCPPacket *packet,
773
0
                size_t len) {
774
0
775
0
        dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
776
0
                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len);
777
0
778
0
        return dhcp_network_send_raw_socket(client->fd, &client->link,
779
0
                                            packet, len);
780
0
}
781
782
0
static int client_send_discover(sd_dhcp_client *client) {
783
0
        _cleanup_free_ DHCPPacket *discover = NULL;
784
0
        size_t optoffset, optlen;
785
0
        int r;
786
0
787
0
        assert(client);
788
0
        assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
789
0
790
0
        r = client_message_init(client, &discover, DHCP_DISCOVER,
791
0
                                &optlen, &optoffset);
792
0
        if (r < 0)
793
0
                return r;
794
0
795
0
        /* the client may suggest values for the network address
796
0
           and lease time in the DHCPDISCOVER message. The client may include
797
0
           the ’requested IP address’ option to suggest that a particular IP
798
0
           address be assigned, and may include the ’IP address lease time’
799
0
           option to suggest the lease time it would like.
800
0
         */
801
0
        if (client->last_addr != INADDR_ANY) {
802
0
                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
803
0
                                       SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
804
0
                                       4, &client->last_addr);
805
0
                if (r < 0)
806
0
                        return r;
807
0
        }
808
0
809
0
        if (client->hostname) {
810
0
                /* According to RFC 4702 "clients that send the Client FQDN option in
811
0
                   their messages MUST NOT also send the Host Name option". Just send
812
0
                   one of the two depending on the hostname type.
813
0
                */
814
0
                if (dns_name_is_single_label(client->hostname)) {
815
0
                        /* it is unclear from RFC 2131 if client should send hostname in
816
0
                           DHCPDISCOVER but dhclient does and so we do as well
817
0
                        */
818
0
                        r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
819
0
                                               SD_DHCP_OPTION_HOST_NAME,
820
0
                                               strlen(client->hostname), client->hostname);
821
0
                } else
822
0
                        r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
823
0
                                                      client->hostname);
824
0
                if (r < 0)
825
0
                        return r;
826
0
        }
827
0
828
0
        if (client->vendor_class_identifier) {
829
0
                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
830
0
                                       SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
831
0
                                       strlen(client->vendor_class_identifier),
832
0
                                       client->vendor_class_identifier);
833
0
                if (r < 0)
834
0
                        return r;
835
0
        }
836
0
837
0
        if (client->user_class) {
838
0
                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
839
0
                                       SD_DHCP_OPTION_USER_CLASS,
840
0
                                       strv_length(client->user_class),
841
0
                                       client->user_class);
842
0
                if (r < 0)
843
0
                        return r;
844
0
        }
845
0
846
0
        r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
847
0
                               SD_DHCP_OPTION_END, 0, NULL);
848
0
        if (r < 0)
849
0
                return r;
850
0
851
0
        /* We currently ignore:
852
0
           The client SHOULD wait a random time between one and ten seconds to
853
0
           desynchronize the use of DHCP at startup.
854
0
         */
855
0
        r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
856
0
        if (r < 0)
857
0
                return r;
858
0
859
0
        log_dhcp_client(client, "DISCOVER");
860
0
861
0
        return 0;
862
0
}
863
864
0
static int client_send_release(sd_dhcp_client *client) {
865
0
        _cleanup_free_ DHCPPacket *release = NULL;
866
0
        size_t optoffset, optlen;
867
0
        int r;
868
0
869
0
        assert(client);
870
0
        assert(!IN_SET(client->state, DHCP_STATE_STOPPED));
871
0
872
0
        r = client_message_init(client, &release, DHCP_RELEASE,
873
0
                                &optlen, &optoffset);
874
0
        if (r < 0)
875
0
                return r;
876
0
877
0
        /* Fill up release IP and MAC */
878
0
        release->dhcp.ciaddr = client->lease->address;
879
0
        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
880
0
881
0
        r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
882
0
                               SD_DHCP_OPTION_END, 0, NULL);
883
0
        if (r < 0)
884
0
                return r;
885
0
886
0
        r = dhcp_network_send_udp_socket(client->fd,
887
0
                                         client->lease->server_address,
888
0
                                         DHCP_PORT_SERVER,
889
0
                                         &release->dhcp,
890
0
                                         sizeof(DHCPMessage) + optoffset);
891
0
        if (r < 0)
892
0
                return r;
893
0
894
0
        log_dhcp_client(client, "RELEASE");
895
0
896
0
        return 0;
897
0
}
898
899
0
static int client_send_request(sd_dhcp_client *client) {
900
0
        _cleanup_free_ DHCPPacket *request = NULL;
901
0
        size_t optoffset, optlen;
902
0
        int r;
903
0
904
0
        assert(client);
905
0
906
0
        r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
907
0
        if (r < 0)
908
0
                return r;
909
0
910
0
        switch (client->state) {
911
0
        /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
912
0
           SELECTING should be REQUESTING)
913
0
         */
914
0
915
0
        case DHCP_STATE_REQUESTING:
916
0
                /* Client inserts the address of the selected server in ’server
917
0
                   identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
918
0
                   filled in with the yiaddr value from the chosen DHCPOFFER.
919
0
                 */
920
0
921
0
                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
922
0
                                       SD_DHCP_OPTION_SERVER_IDENTIFIER,
923
0
                                       4, &client->lease->server_address);
924
0
                if (r < 0)
925
0
                        return r;
926
0
927
0
                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
928
0
                                       SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
929
0
                                       4, &client->lease->address);
930
0
                if (r < 0)
931
0
                        return r;
932
0
933
0
                break;
934
0
935
0
        case DHCP_STATE_INIT_REBOOT:
936
0
                /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
937
0
                   option MUST be filled in with client’s notion of its previously
938
0
                   assigned address. ’ciaddr’ MUST be zero.
939
0
                 */
940
0
                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
941
0
                                       SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
942
0
                                       4, &client->last_addr);
943
0
                if (r < 0)
944
0
                        return r;
945
0
                break;
946
0
947
0
        case DHCP_STATE_RENEWING:
948
0
                /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
949
0
                   option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
950
0
                   client’s IP address.
951
0
                */
952
0
953
0
        case DHCP_STATE_REBINDING:
954
0
                /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
955
0
                   option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
956
0
                   client’s IP address.
957
0
958
0
                   This message MUST be broadcast to the 0xffffffff IP broadcast address.
959
0
                 */
960
0
                request->dhcp.ciaddr = client->lease->address;
961
0
962
0
                break;
963
0
964
0
        case DHCP_STATE_INIT:
965
0
        case DHCP_STATE_SELECTING:
966
0
        case DHCP_STATE_REBOOTING:
967
0
        case DHCP_STATE_BOUND:
968
0
        case DHCP_STATE_STOPPED:
969
0
                return -EINVAL;
970
0
        }
971
0
972
0
        if (client->hostname) {
973
0
                if (dns_name_is_single_label(client->hostname))
974
0
                        r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
975
0
                                               SD_DHCP_OPTION_HOST_NAME,
976
0
                                               strlen(client->hostname), client->hostname);
977
0
                else
978
0
                        r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
979
0
                                                      client->hostname);
980
0
                if (r < 0)
981
0
                        return r;
982
0
        }
983
0
984
0
        if (client->vendor_class_identifier) {
985
0
                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
986
0
                                       SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
987
0
                                       strlen(client->vendor_class_identifier),
988
0
                                       client->vendor_class_identifier);
989
0
                if (r < 0)
990
0
                        return r;
991
0
        }
992
0
993
0
        r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
994
0
                               SD_DHCP_OPTION_END, 0, NULL);
995
0
        if (r < 0)
996
0
                return r;
997
0
998
0
        if (client->state == DHCP_STATE_RENEWING) {
999
0
                r = dhcp_network_send_udp_socket(client->fd,
1000
0
                                                 client->lease->server_address,
1001
0
                                                 DHCP_PORT_SERVER,
1002
0
                                                 &request->dhcp,
1003
0
                                                 sizeof(DHCPMessage) + optoffset);
1004
0
        } else {
1005
0
                r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
1006
0
        }
1007
0
        if (r < 0)
1008
0
                return r;
1009
0
1010
0
        switch (client->state) {
1011
0
1012
0
        case DHCP_STATE_REQUESTING:
1013
0
                log_dhcp_client(client, "REQUEST (requesting)");
1014
0
                break;
1015
0
1016
0
        case DHCP_STATE_INIT_REBOOT:
1017
0
                log_dhcp_client(client, "REQUEST (init-reboot)");
1018
0
                break;
1019
0
1020
0
        case DHCP_STATE_RENEWING:
1021
0
                log_dhcp_client(client, "REQUEST (renewing)");
1022
0
                break;
1023
0
1024
0
        case DHCP_STATE_REBINDING:
1025
0
                log_dhcp_client(client, "REQUEST (rebinding)");
1026
0
                break;
1027
0
1028
0
        default:
1029
0
                log_dhcp_client(client, "REQUEST (invalid)");
1030
0
                break;
1031
0
        }
1032
0
1033
0
        return 0;
1034
0
}
1035
1036
static int client_start(sd_dhcp_client *client);
1037
1038
static int client_timeout_resend(
1039
                sd_event_source *s,
1040
                uint64_t usec,
1041
0
                void *userdata) {
1042
0
1043
0
        sd_dhcp_client *client = userdata;
1044
0
        DHCP_CLIENT_DONT_DESTROY(client);
1045
0
        usec_t next_timeout = 0;
1046
0
        uint64_t time_now;
1047
0
        uint32_t time_left;
1048
0
        int r;
1049
0
1050
0
        assert(s);
1051
0
        assert(client);
1052
0
        assert(client->event);
1053
0
1054
0
        r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1055
0
        if (r < 0)
1056
0
                goto error;
1057
0
1058
0
        switch (client->state) {
1059
0
1060
0
        case DHCP_STATE_RENEWING:
1061
0
1062
0
                time_left = (client->lease->t2 - client->lease->t1) / 2;
1063
0
                if (time_left < 60)
1064
0
                        time_left = 60;
1065
0
1066
0
                next_timeout = time_now + time_left * USEC_PER_SEC;
1067
0
1068
0
                break;
1069
0
1070
0
        case DHCP_STATE_REBINDING:
1071
0
1072
0
                time_left = (client->lease->lifetime - client->lease->t2) / 2;
1073
0
                if (time_left < 60)
1074
0
                        time_left = 60;
1075
0
1076
0
                next_timeout = time_now + time_left * USEC_PER_SEC;
1077
0
                break;
1078
0
1079
0
        case DHCP_STATE_REBOOTING:
1080
0
                /* start over as we did not receive a timely ack or nak */
1081
0
                r = client_initialize(client);
1082
0
                if (r < 0)
1083
0
                        goto error;
1084
0
1085
0
                r = client_start(client);
1086
0
                if (r < 0)
1087
0
                        goto error;
1088
0
                else {
1089
0
                        log_dhcp_client(client, "REBOOTED");
1090
0
                        return 0;
1091
0
                }
1092
0
1093
0
        case DHCP_STATE_INIT:
1094
0
        case DHCP_STATE_INIT_REBOOT:
1095
0
        case DHCP_STATE_SELECTING:
1096
0
        case DHCP_STATE_REQUESTING:
1097
0
        case DHCP_STATE_BOUND:
1098
0
1099
0
                if (client->attempt < client->max_attempts)
1100
0
                        client->attempt++;
1101
0
                else
1102
0
                        goto error;
1103
0
1104
0
                next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
1105
0
1106
0
                break;
1107
0
1108
0
        case DHCP_STATE_STOPPED:
1109
0
                r = -EINVAL;
1110
0
                goto error;
1111
0
        }
1112
0
1113
0
        next_timeout += (random_u32() & 0x1fffff);
1114
0
1115
0
        r = event_reset_time(client->event, &client->timeout_resend,
1116
0
                             clock_boottime_or_monotonic(),
1117
0
                             next_timeout, 10 * USEC_PER_MSEC,
1118
0
                             client_timeout_resend, client,
1119
0
                             client->event_priority, "dhcp4-resend-timer", true);
1120
0
        if (r < 0)
1121
0
                goto error;
1122
0
1123
0
        switch (client->state) {
1124
0
        case DHCP_STATE_INIT:
1125
0
                r = client_send_discover(client);
1126
0
                if (r >= 0) {
1127
0
                        client->state = DHCP_STATE_SELECTING;
1128
0
                        client->attempt = 0;
1129
0
                } else if (client->attempt >= client->max_attempts)
1130
0
                        goto error;
1131
0
1132
0
                break;
1133
0
1134
0
        case DHCP_STATE_SELECTING:
1135
0
                r = client_send_discover(client);
1136
0
                if (r < 0 && client->attempt >= client->max_attempts)
1137
0
                        goto error;
1138
0
1139
0
                break;
1140
0
1141
0
        case DHCP_STATE_INIT_REBOOT:
1142
0
        case DHCP_STATE_REQUESTING:
1143
0
        case DHCP_STATE_RENEWING:
1144
0
        case DHCP_STATE_REBINDING:
1145
0
                r = client_send_request(client);
1146
0
                if (r < 0 && client->attempt >= client->max_attempts)
1147
0
                         goto error;
1148
0
1149
0
                if (client->state == DHCP_STATE_INIT_REBOOT)
1150
0
                        client->state = DHCP_STATE_REBOOTING;
1151
0
1152
0
                client->request_sent = time_now;
1153
0
1154
0
                break;
1155
0
1156
0
        case DHCP_STATE_REBOOTING:
1157
0
        case DHCP_STATE_BOUND:
1158
0
1159
0
                break;
1160
0
1161
0
        case DHCP_STATE_STOPPED:
1162
0
                r = -EINVAL;
1163
0
                goto error;
1164
0
        }
1165
0
1166
0
        return 0;
1167
0
1168
0
error:
1169
0
        client_stop(client, r);
1170
0
1171
0
        /* Errors were dealt with when stopping the client, don't spill
1172
0
           errors into the event loop handler */
1173
0
        return 0;
1174
0
}
1175
1176
static int client_initialize_io_events(
1177
                sd_dhcp_client *client,
1178
0
                sd_event_io_handler_t io_callback) {
1179
0
1180
0
        int r;
1181
0
1182
0
        assert(client);
1183
0
        assert(client->event);
1184
0
1185
0
        r = sd_event_add_io(client->event, &client->receive_message,
1186
0
                            client->fd, EPOLLIN, io_callback,
1187
0
                            client);
1188
0
        if (r < 0)
1189
0
                goto error;
1190
0
1191
0
        r = sd_event_source_set_priority(client->receive_message,
1192
0
                                         client->event_priority);
1193
0
        if (r < 0)
1194
0
                goto error;
1195
0
1196
0
        r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
1197
0
        if (r < 0)
1198
0
                goto error;
1199
0
1200
0
error:
1201
0
        if (r < 0)
1202
0
                client_stop(client, r);
1203
0
1204
0
        return 0;
1205
0
}
1206
1207
0
static int client_initialize_time_events(sd_dhcp_client *client) {
1208
0
        uint64_t usec = 0;
1209
0
        int r;
1210
0
1211
0
        assert(client);
1212
0
        assert(client->event);
1213
0
1214
0
        if (client->start_delay) {
1215
0
                assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
1216
0
                usec += client->start_delay;
1217
0
        }
1218
0
1219
0
        r = event_reset_time(client->event, &client->timeout_resend,
1220
0
                             clock_boottime_or_monotonic(),
1221
0
                             usec, 0,
1222
0
                             client_timeout_resend, client,
1223
0
                             client->event_priority, "dhcp4-resend-timer", true);
1224
0
        if (r < 0)
1225
0
                client_stop(client, r);
1226
0
1227
0
        return 0;
1228
0
1229
0
}
1230
1231
0
static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
1232
0
        client_initialize_io_events(client, io_callback);
1233
0
        client_initialize_time_events(client);
1234
0
1235
0
        return 0;
1236
0
}
1237
1238
0
static int client_start_delayed(sd_dhcp_client *client) {
1239
0
        int r;
1240
0
1241
0
        assert_return(client, -EINVAL);
1242
0
        assert_return(client->event, -EINVAL);
1243
0
        assert_return(client->ifindex > 0, -EINVAL);
1244
0
        assert_return(client->fd < 0, -EBUSY);
1245
0
        assert_return(client->xid == 0, -EINVAL);
1246
0
        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
1247
0
1248
0
        client->xid = random_u32();
1249
0
1250
0
        r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
1251
0
                                         client->xid, client->mac_addr,
1252
0
                                         client->mac_addr_len, client->arp_type, client->port);
1253
0
        if (r < 0) {
1254
0
                client_stop(client, r);
1255
0
                return r;
1256
0
        }
1257
0
        client->fd = r;
1258
0
1259
0
        if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
1260
0
                client->start_time = now(clock_boottime_or_monotonic());
1261
0
1262
0
        return client_initialize_events(client, client_receive_message_raw);
1263
0
}
1264
1265
0
static int client_start(sd_dhcp_client *client) {
1266
0
        client->start_delay = 0;
1267
0
        return client_start_delayed(client);
1268
0
}
1269
1270
0
static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
1271
0
        sd_dhcp_client *client = userdata;
1272
0
        DHCP_CLIENT_DONT_DESTROY(client);
1273
0
1274
0
        log_dhcp_client(client, "EXPIRED");
1275
0
1276
0
        client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1277
0
1278
0
        /* lease was lost, start over if not freed or stopped in callback */
1279
0
        if (client->state != DHCP_STATE_STOPPED) {
1280
0
                client_initialize(client);
1281
0
                client_start(client);
1282
0
        }
1283
0
1284
0
        return 0;
1285
0
}
1286
1287
0
static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
1288
0
        sd_dhcp_client *client = userdata;
1289
0
        DHCP_CLIENT_DONT_DESTROY(client);
1290
0
        int r;
1291
0
1292
0
        assert(client);
1293
0
1294
0
        client->receive_message = sd_event_source_unref(client->receive_message);
1295
0
        client->fd = asynchronous_close(client->fd);
1296
0
1297
0
        client->state = DHCP_STATE_REBINDING;
1298
0
        client->attempt = 0;
1299
0
1300
0
        r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
1301
0
                                         client->xid, client->mac_addr,
1302
0
                                         client->mac_addr_len, client->arp_type,
1303
0
                                         client->port);
1304
0
        if (r < 0) {
1305
0
                client_stop(client, r);
1306
0
                return 0;
1307
0
        }
1308
0
        client->fd = r;
1309
0
1310
0
        return client_initialize_events(client, client_receive_message_raw);
1311
0
}
1312
1313
0
static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
1314
0
        sd_dhcp_client *client = userdata;
1315
0
        DHCP_CLIENT_DONT_DESTROY(client);
1316
0
1317
0
        client->state = DHCP_STATE_RENEWING;
1318
0
        client->attempt = 0;
1319
0
1320
0
        return client_initialize_time_events(client);
1321
0
}
1322
1323
0
static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
1324
0
        _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1325
0
        int r;
1326
0
1327
0
        r = dhcp_lease_new(&lease);
1328
0
        if (r < 0)
1329
0
                return r;
1330
0
1331
0
        if (client->client_id_len) {
1332
0
                r = dhcp_lease_set_client_id(lease,
1333
0
                                             (uint8_t *) &client->client_id,
1334
0
                                             client->client_id_len);
1335
0
                if (r < 0)
1336
0
                        return r;
1337
0
        }
1338
0
1339
0
        r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
1340
0
        if (r != DHCP_OFFER) {
1341
0
                log_dhcp_client(client, "received message was not an OFFER, ignoring");
1342
0
                return -ENOMSG;
1343
0
        }
1344
0
1345
0
        lease->next_server = offer->siaddr;
1346
0
        lease->address = offer->yiaddr;
1347
0
1348
0
        if (lease->address == 0 ||
1349
0
            lease->server_address == 0 ||
1350
0
            lease->lifetime == 0) {
1351
0
                log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
1352
0
                return -ENOMSG;
1353
0
        }
1354
0
1355
0
        if (!lease->have_subnet_mask) {
1356
0
                r = dhcp_lease_set_default_subnet_mask(lease);
1357
0
                if (r < 0) {
1358
0
                        log_dhcp_client(client,
1359
0
                                        "received lease lacks subnet mask, "
1360
0
                                        "and a fallback one cannot be generated, ignoring");
1361
0
                        return -ENOMSG;
1362
0
                }
1363
0
        }
1364
0
1365
0
        sd_dhcp_lease_unref(client->lease);
1366
0
        client->lease = TAKE_PTR(lease);
1367
0
1368
0
        if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
1369
0
                return -ENOMSG;
1370
0
1371
0
        log_dhcp_client(client, "OFFER");
1372
0
1373
0
        return 0;
1374
0
}
1375
1376
0
static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
1377
0
        int r;
1378
0
1379
0
        r = dhcp_option_parse(force, len, NULL, NULL, NULL);
1380
0
        if (r != DHCP_FORCERENEW)
1381
0
                return -ENOMSG;
1382
0
1383
0
        log_dhcp_client(client, "FORCERENEW");
1384
0
1385
0
        return 0;
1386
0
}
1387
1388
0
static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
1389
0
        if (a->address != b->address)
1390
0
                return false;
1391
0
1392
0
        if (a->subnet_mask != b->subnet_mask)
1393
0
                return false;
1394
0
1395
0
        if (a->router_size != b->router_size)
1396
0
                return false;
1397
0
1398
0
        for (size_t i = 0; i < a->router_size; i++)
1399
0
                if (a->router[i].s_addr != b->router[i].s_addr)
1400
0
                        return false;
1401
0
1402
0
        return true;
1403
0
}
1404
1405
0
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
1406
0
        _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1407
0
        _cleanup_free_ char *error_message = NULL;
1408
0
        int r;
1409
0
1410
0
        r = dhcp_lease_new(&lease);
1411
0
        if (r < 0)
1412
0
                return r;
1413
0
1414
0
        if (client->client_id_len) {
1415
0
                r = dhcp_lease_set_client_id(lease,
1416
0
                                             (uint8_t *) &client->client_id,
1417
0
                                             client->client_id_len);
1418
0
                if (r < 0)
1419
0
                        return r;
1420
0
        }
1421
0
1422
0
        r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
1423
0
        if (r == DHCP_NAK) {
1424
0
                log_dhcp_client(client, "NAK: %s", strna(error_message));
1425
0
                return -EADDRNOTAVAIL;
1426
0
        }
1427
0
1428
0
        if (r != DHCP_ACK) {
1429
0
                log_dhcp_client(client, "received message was not an ACK, ignoring");
1430
0
                return -ENOMSG;
1431
0
        }
1432
0
1433
0
        lease->next_server = ack->siaddr;
1434
0
1435
0
        lease->address = ack->yiaddr;
1436
0
1437
0
        if (lease->address == INADDR_ANY ||
1438
0
            lease->server_address == INADDR_ANY ||
1439
0
            lease->lifetime == 0) {
1440
0
                log_dhcp_client(client, "received lease lacks address, server "
1441
0
                                "address or lease lifetime, ignoring");
1442
0
                return -ENOMSG;
1443
0
        }
1444
0
1445
0
        if (lease->subnet_mask == INADDR_ANY) {
1446
0
                r = dhcp_lease_set_default_subnet_mask(lease);
1447
0
                if (r < 0) {
1448
0
                        log_dhcp_client(client,
1449
0
                                        "received lease lacks subnet mask, "
1450
0
                                        "and a fallback one cannot be generated, ignoring");
1451
0
                        return -ENOMSG;
1452
0
                }
1453
0
        }
1454
0
1455
0
        r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1456
0
        if (client->lease) {
1457
0
                if (lease_equal(client->lease, lease))
1458
0
                        r = SD_DHCP_CLIENT_EVENT_RENEW;
1459
0
                else
1460
0
                        r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
1461
0
1462
0
                client->lease = sd_dhcp_lease_unref(client->lease);
1463
0
        }
1464
0
1465
0
        client->lease = TAKE_PTR(lease);
1466
0
1467
0
        log_dhcp_client(client, "ACK");
1468
0
1469
0
        return r;
1470
0
}
1471
1472
0
static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
1473
0
        assert(client);
1474
0
        assert(client->request_sent);
1475
0
        assert(lifetime > 0);
1476
0
1477
0
        if (lifetime > 3)
1478
0
                lifetime -= 3;
1479
0
        else
1480
0
                lifetime = 0;
1481
0
1482
0
        return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
1483
0
                + (random_u32() & 0x1fffff);
1484
0
}
1485
1486
0
static int client_set_lease_timeouts(sd_dhcp_client *client) {
1487
0
        usec_t time_now;
1488
0
        uint64_t lifetime_timeout;
1489
0
        uint64_t t2_timeout;
1490
0
        uint64_t t1_timeout;
1491
0
        char time_string[FORMAT_TIMESPAN_MAX];
1492
0
        int r;
1493
0
1494
0
        assert(client);
1495
0
        assert(client->event);
1496
0
        assert(client->lease);
1497
0
        assert(client->lease->lifetime);
1498
0
1499
0
        /* don't set timers for infinite leases */
1500
0
        if (client->lease->lifetime == 0xffffffff) {
1501
0
                (void) event_source_disable(client->timeout_t1);
1502
0
                (void) event_source_disable(client->timeout_t2);
1503
0
                (void) event_source_disable(client->timeout_expire);
1504
0
1505
0
                return 0;
1506
0
        }
1507
0
1508
0
        r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1509
0
        if (r < 0)
1510
0
                return r;
1511
0
        assert(client->request_sent <= time_now);
1512
0
1513
0
        /* convert the various timeouts from relative (secs) to absolute (usecs) */
1514
0
        lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1515
0
        if (client->lease->t1 > 0 && client->lease->t2 > 0) {
1516
0
                /* both T1 and T2 are given */
1517
0
                if (client->lease->t1 < client->lease->t2 &&
1518
0
                    client->lease->t2 < client->lease->lifetime) {
1519
0
                        /* they are both valid */
1520
0
                        t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1521
0
                        t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1522
0
                } else {
1523
0
                        /* discard both */
1524
0
                        t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1525
0
                        client->lease->t2 = (client->lease->lifetime * 7) / 8;
1526
0
                        t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1527
0
                        client->lease->t1 = client->lease->lifetime / 2;
1528
0
                }
1529
0
        } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
1530
0
                /* only T2 is given, and it is valid */
1531
0
                t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1532
0
                t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1533
0
                client->lease->t1 = client->lease->lifetime / 2;
1534
0
                if (t2_timeout <= t1_timeout) {
1535
0
                        /* the computed T1 would be invalid, so discard T2 */
1536
0
                        t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1537
0
                        client->lease->t2 = (client->lease->lifetime * 7) / 8;
1538
0
                }
1539
0
        } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
1540
0
                /* only T1 is given, and it is valid */
1541
0
                t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1542
0
                t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1543
0
                client->lease->t2 = (client->lease->lifetime * 7) / 8;
1544
0
                if (t2_timeout <= t1_timeout) {
1545
0
                        /* the computed T2 would be invalid, so discard T1 */
1546
0
                        t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1547
0
                        client->lease->t2 = client->lease->lifetime / 2;
1548
0
                }
1549
0
        } else {
1550
0
                /* fall back to the default timeouts */
1551
0
                t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1552
0
                client->lease->t1 = client->lease->lifetime / 2;
1553
0
                t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1554
0
                client->lease->t2 = (client->lease->lifetime * 7) / 8;
1555
0
        }
1556
0
1557
0
        /* arm lifetime timeout */
1558
0
        r = event_reset_time(client->event, &client->timeout_expire,
1559
0
                             clock_boottime_or_monotonic(),
1560
0
                             lifetime_timeout, 10 * USEC_PER_MSEC,
1561
0
                             client_timeout_expire, client,
1562
0
                             client->event_priority, "dhcp4-lifetime", true);
1563
0
        if (r < 0)
1564
0
                return r;
1565
0
1566
0
        log_dhcp_client(client, "lease expires in %s",
1567
0
                        format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
1568
0
1569
0
        /* don't arm earlier timeouts if this has already expired */
1570
0
        if (lifetime_timeout <= time_now)
1571
0
                return 0;
1572
0
1573
0
        /* arm T2 timeout */
1574
0
        r = event_reset_time(client->event, &client->timeout_t2,
1575
0
                             clock_boottime_or_monotonic(),
1576
0
                             t2_timeout, 10 * USEC_PER_MSEC,
1577
0
                             client_timeout_t2, client,
1578
0
                             client->event_priority, "dhcp4-t2-timeout", true);
1579
0
        if (r < 0)
1580
0
                return r;
1581
0
1582
0
        log_dhcp_client(client, "T2 expires in %s",
1583
0
                        format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
1584
0
1585
0
        /* don't arm earlier timeout if this has already expired */
1586
0
        if (t2_timeout <= time_now)
1587
0
                return 0;
1588
0
1589
0
        /* arm T1 timeout */
1590
0
        r = event_reset_time(client->event, &client->timeout_t1,
1591
0
                             clock_boottime_or_monotonic(),
1592
0
                             t1_timeout, 10 * USEC_PER_MSEC,
1593
0
                             client_timeout_t1, client,
1594
0
                             client->event_priority, "dhcp4-t1-timer", true);
1595
0
        if (r < 0)
1596
0
                return r;
1597
0
1598
0
        log_dhcp_client(client, "T1 expires in %s",
1599
0
                        format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
1600
0
1601
0
        return 0;
1602
0
}
1603
1604
0
static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
1605
0
        DHCP_CLIENT_DONT_DESTROY(client);
1606
0
        char time_string[FORMAT_TIMESPAN_MAX];
1607
0
        int r = 0, notify_event = 0;
1608
0
1609
0
        assert(client);
1610
0
        assert(client->event);
1611
0
        assert(message);
1612
0
1613
0
        switch (client->state) {
1614
0
        case DHCP_STATE_SELECTING:
1615
0
1616
0
                r = client_handle_offer(client, message, len);
1617
0
                if (r >= 0) {
1618
0
1619
0
                        client->state = DHCP_STATE_REQUESTING;
1620
0
                        client->attempt = 0;
1621
0
1622
0
                        r = event_reset_time(client->event, &client->timeout_resend,
1623
0
                                             clock_boottime_or_monotonic(),
1624
0
                                             0, 0,
1625
0
                                             client_timeout_resend, client,
1626
0
                                             client->event_priority, "dhcp4-resend-timer", true);
1627
0
                        if (r < 0)
1628
0
                                goto error;
1629
0
                } else if (r == -ENOMSG)
1630
0
                        /* invalid message, let's ignore it */
1631
0
                        return 0;
1632
0
1633
0
                break;
1634
0
1635
0
        case DHCP_STATE_REBOOTING:
1636
0
        case DHCP_STATE_REQUESTING:
1637
0
        case DHCP_STATE_RENEWING:
1638
0
        case DHCP_STATE_REBINDING:
1639
0
1640
0
                r = client_handle_ack(client, message, len);
1641
0
                if (r >= 0) {
1642
0
                        client->start_delay = 0;
1643
0
                        (void) event_source_disable(client->timeout_resend);
1644
0
                        client->receive_message =
1645
0
                                sd_event_source_unref(client->receive_message);
1646
0
                        client->fd = asynchronous_close(client->fd);
1647
0
1648
0
                        if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1649
0
                                   DHCP_STATE_REBOOTING))
1650
0
                                notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1651
0
                        else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
1652
0
                                notify_event = r;
1653
0
1654
0
                        client->state = DHCP_STATE_BOUND;
1655
0
                        client->attempt = 0;
1656
0
1657
0
                        client->last_addr = client->lease->address;
1658
0
1659
0
                        r = client_set_lease_timeouts(client);
1660
0
                        if (r < 0) {
1661
0
                                log_dhcp_client(client, "could not set lease timeouts");
1662
0
                                goto error;
1663
0
                        }
1664
0
1665
0
                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
1666
0
                        if (r < 0) {
1667
0
                                log_dhcp_client(client, "could not bind UDP socket");
1668
0
                                goto error;
1669
0
                        }
1670
0
1671
0
                        client->fd = r;
1672
0
1673
0
                        client_initialize_io_events(client, client_receive_message_udp);
1674
0
1675
0
                        if (notify_event) {
1676
0
                                client_notify(client, notify_event);
1677
0
                                if (client->state == DHCP_STATE_STOPPED)
1678
0
                                        return 0;
1679
0
                        }
1680
0
1681
0
                } else if (r == -EADDRNOTAVAIL) {
1682
0
                        /* got a NAK, let's restart the client */
1683
0
                        client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1684
0
1685
0
                        r = client_initialize(client);
1686
0
                        if (r < 0)
1687
0
                                goto error;
1688
0
1689
0
                        r = client_start_delayed(client);
1690
0
                        if (r < 0)
1691
0
                                goto error;
1692
0
1693
0
                        log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1694
0
                                                                                client->start_delay, USEC_PER_SEC));
1695
0
1696
0
                        client->start_delay = CLAMP(client->start_delay * 2,
1697
0
                                                    RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
1698
0
1699
0
                        return 0;
1700
0
                } else if (r == -ENOMSG)
1701
0
                        /* invalid message, let's ignore it */
1702
0
                        return 0;
1703
0
1704
0
                break;
1705
0
1706
0
        case DHCP_STATE_BOUND:
1707
0
                r = client_handle_forcerenew(client, message, len);
1708
0
                if (r >= 0) {
1709
0
                        r = client_timeout_t1(NULL, 0, client);
1710
0
                        if (r < 0)
1711
0
                                goto error;
1712
0
                } else if (r == -ENOMSG)
1713
0
                        /* invalid message, let's ignore it */
1714
0
                        return 0;
1715
0
1716
0
                break;
1717
0
1718
0
        case DHCP_STATE_INIT:
1719
0
        case DHCP_STATE_INIT_REBOOT:
1720
0
1721
0
                break;
1722
0
1723
0
        case DHCP_STATE_STOPPED:
1724
0
                r = -EINVAL;
1725
0
                goto error;
1726
0
        }
1727
0
1728
0
error:
1729
0
        if (r < 0)
1730
0
                client_stop(client, r);
1731
0
1732
0
        return r;
1733
0
}
1734
1735
static int client_receive_message_udp(
1736
                sd_event_source *s,
1737
                int fd,
1738
                uint32_t revents,
1739
0
                void *userdata) {
1740
0
1741
0
        sd_dhcp_client *client = userdata;
1742
0
        _cleanup_free_ DHCPMessage *message = NULL;
1743
0
        const uint8_t *expected_chaddr = NULL;
1744
0
        uint8_t expected_hlen = 0;
1745
0
        ssize_t len, buflen;
1746
0
1747
0
        assert(s);
1748
0
        assert(client);
1749
0
1750
0
        buflen = next_datagram_size_fd(fd);
1751
0
        if (buflen == -ENETDOWN) {
1752
0
                /* the link is down. Don't return an error or the I/O event
1753
0
                   source will be disconnected and we won't be able to receive
1754
0
                   packets again when the link comes back. */
1755
0
                return 0;
1756
0
        }
1757
0
        if (buflen < 0)
1758
0
                return buflen;
1759
0
1760
0
        message = malloc0(buflen);
1761
0
        if (!message)
1762
0
                return -ENOMEM;
1763
0
1764
0
        len = recv(fd, message, buflen, 0);
1765
0
        if (len < 0) {
1766
0
                /* see comment above for why we shouldn't error out on ENETDOWN. */
1767
0
                if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
1768
0
                        return 0;
1769
0
1770
0
                return log_dhcp_client_errno(client, errno,
1771
0
                                             "Could not receive message from UDP socket: %m");
1772
0
        }
1773
0
        if ((size_t) len < sizeof(DHCPMessage)) {
1774
0
                log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
1775
0
                return 0;
1776
0
        }
1777
0
1778
0
        if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1779
0
                log_dhcp_client(client, "Not a DHCP message: ignoring");
1780
0
                return 0;
1781
0
        }
1782
0
1783
0
        if (message->op != BOOTREPLY) {
1784
0
                log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
1785
0
                return 0;
1786
0
        }
1787
0
1788
0
        if (message->htype != client->arp_type) {
1789
0
                log_dhcp_client(client, "Packet type does not match client type");
1790
0
                return 0;
1791
0
        }
1792
0
1793
0
        if (client->arp_type == ARPHRD_ETHER) {
1794
0
                expected_hlen = ETH_ALEN;
1795
0
                expected_chaddr = &client->mac_addr[0];
1796
0
        }
1797
0
1798
0
        if (message->hlen != expected_hlen) {
1799
0
                log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
1800
0
                return 0;
1801
0
        }
1802
0
1803
0
        if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
1804
0
                log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
1805
0
                return 0;
1806
0
        }
1807
0
1808
0
        if (client->state != DHCP_STATE_BOUND &&
1809
0
            be32toh(message->xid) != client->xid) {
1810
0
                /* in BOUND state, we may receive FORCERENEW with xid set by server,
1811
0
                   so ignore the xid in this case */
1812
0
                log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
1813
0
                                be32toh(message->xid), client->xid);
1814
0
                return 0;
1815
0
        }
1816
0
1817
0
        return client_handle_message(client, message, len);
1818
0
}
1819
1820
static int client_receive_message_raw(
1821
                sd_event_source *s,
1822
                int fd,
1823
                uint32_t revents,
1824
0
                void *userdata) {
1825
0
1826
0
        sd_dhcp_client *client = userdata;
1827
0
        _cleanup_free_ DHCPPacket *packet = NULL;
1828
0
        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1829
0
        struct iovec iov = {};
1830
0
        struct msghdr msg = {
1831
0
                .msg_iov = &iov,
1832
0
                .msg_iovlen = 1,
1833
0
                .msg_control = cmsgbuf,
1834
0
                .msg_controllen = sizeof(cmsgbuf),
1835
0
        };
1836
0
        struct cmsghdr *cmsg;
1837
0
        bool checksum = true;
1838
0
        ssize_t buflen, len;
1839
0
        int r;
1840
0
1841
0
        assert(s);
1842
0
        assert(client);
1843
0
1844
0
        buflen = next_datagram_size_fd(fd);
1845
0
        if (buflen == -ENETDOWN)
1846
0
                return 0;
1847
0
        if (buflen < 0)
1848
0
                return buflen;
1849
0
1850
0
        packet = malloc0(buflen);
1851
0
        if (!packet)
1852
0
                return -ENOMEM;
1853
0
1854
0
        iov = IOVEC_MAKE(packet, buflen);
1855
0
1856
0
        len = recvmsg(fd, &msg, 0);
1857
0
        if (len < 0) {
1858
0
                if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
1859
0
                        return 0;
1860
0
1861
0
                return log_dhcp_client_errno(client, errno,
1862
0
                                             "Could not receive message from raw socket: %m");
1863
0
        } else if ((size_t)len < sizeof(DHCPPacket))
1864
0
                return 0;
1865
0
1866
0
        CMSG_FOREACH(cmsg, &msg)
1867
0
                if (cmsg->cmsg_level == SOL_PACKET &&
1868
0
                    cmsg->cmsg_type == PACKET_AUXDATA &&
1869
0
                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1870
0
                        struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1871
0
1872
0
                        checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1873
0
                        break;
1874
0
                }
1875
0
1876
0
        r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
1877
0
        if (r < 0)
1878
0
                return 0;
1879
0
1880
0
        len -= DHCP_IP_UDP_SIZE;
1881
0
1882
0
        return client_handle_message(client, &packet->dhcp, len);
1883
0
}
1884
1885
0
int sd_dhcp_client_start(sd_dhcp_client *client) {
1886
0
        int r;
1887
0
1888
0
        assert_return(client, -EINVAL);
1889
0
1890
0
        r = client_initialize(client);
1891
0
        if (r < 0)
1892
0
                return r;
1893
0
1894
0
        /* RFC7844 section 3.3:
1895
0
           SHOULD perform a complete four-way handshake, starting with a
1896
0
           DHCPDISCOVER, to obtain a new address lease.  If the client can
1897
0
           ascertain that this is exactly the same network to which it was
1898
0
           previously connected, and if the link-layer address did not change,
1899
0
           the client MAY issue a DHCPREQUEST to try to reclaim the current
1900
0
           address. */
1901
0
        if (client->last_addr && !client->anonymize)
1902
0
                client->state = DHCP_STATE_INIT_REBOOT;
1903
0
1904
0
        r = client_start(client);
1905
0
        if (r >= 0)
1906
0
                log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
1907
0
1908
0
        return r;
1909
0
}
1910
1911
0
int sd_dhcp_client_send_release(sd_dhcp_client *client) {
1912
0
        assert_return(client, -EINVAL);
1913
0
1914
0
        client_send_release(client);
1915
0
1916
0
        return 0;
1917
0
}
1918
1919
0
int sd_dhcp_client_stop(sd_dhcp_client *client) {
1920
0
        DHCP_CLIENT_DONT_DESTROY(client);
1921
0
1922
0
        assert_return(client, -EINVAL);
1923
0
1924
0
        client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
1925
0
        client->state = DHCP_STATE_STOPPED;
1926
0
1927
0
        return 0;
1928
0
}
1929
1930
0
int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
1931
0
        int r;
1932
0
1933
0
        assert_return(client, -EINVAL);
1934
0
        assert_return(!client->event, -EBUSY);
1935
0
1936
0
        if (event)
1937
0
                client->event = sd_event_ref(event);
1938
0
        else {
1939
0
                r = sd_event_default(&client->event);
1940
0
                if (r < 0)
1941
0
                        return 0;
1942
0
        }
1943
0
1944
0
        client->event_priority = priority;
1945
0
1946
0
        return 0;
1947
0
}
1948
1949
0
int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1950
0
        assert_return(client, -EINVAL);
1951
0
1952
0
        client->event = sd_event_unref(client->event);
1953
0
1954
0
        return 0;
1955
0
}
1956
1957
0
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1958
0
        assert_return(client, NULL);
1959
0
1960
0
        return client->event;
1961
0
}
1962
1963
0
static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
1964
0
        assert(client);
1965
0
1966
0
        log_dhcp_client(client, "FREE");
1967
0
1968
0
        client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1969
0
        client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1970
0
        client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1971
0
        client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1972
0
1973
0
        client_initialize(client);
1974
0
1975
0
        sd_dhcp_client_detach_event(client);
1976
0
1977
0
        sd_dhcp_lease_unref(client->lease);
1978
0
1979
0
        free(client->req_opts);
1980
0
        free(client->hostname);
1981
0
        free(client->vendor_class_identifier);
1982
0
        client->user_class = strv_free(client->user_class);
1983
0
        return mfree(client);
1984
0
}
1985
1986
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
1987
1988
0
int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
1989
0
        _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
1990
0
1991
0
        assert_return(ret, -EINVAL);
1992
0
1993
0
        client = new(sd_dhcp_client, 1);
1994
0
        if (!client)
1995
0
                return -ENOMEM;
1996
0
1997
0
        *client = (sd_dhcp_client) {
1998
0
                .n_ref = 1,
1999
0
                .state = DHCP_STATE_INIT,
2000
0
                .ifindex = -1,
2001
0
                .fd = -1,
2002
0
                .mtu = DHCP_DEFAULT_MIN_SIZE,
2003
0
                .port = DHCP_PORT_CLIENT,
2004
0
                .anonymize = !!anonymize,
2005
0
                .max_attempts = (uint64_t) -1,
2006
0
        };
2007
0
        /* NOTE: this could be moved to a function. */
2008
0
        if (anonymize) {
2009
0
                client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
2010
0
                client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
2011
0
        } else {
2012
0
                client->req_opts_size = ELEMENTSOF(default_req_opts);
2013
0
                client->req_opts = memdup(default_req_opts, client->req_opts_size);
2014
0
        }
2015
0
        if (!client->req_opts)
2016
0
                return -ENOMEM;
2017
0
2018
0
        *ret = TAKE_PTR(client);
2019
0
2020
0
        return 0;
2021
0
}