• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 17281840010

27 Aug 2025 01:33PM UTC coverage: 72.231% (-0.001%) from 72.232%
17281840010

push

github

yuwata
test: ensure that reload updates DNSSEC and DNSOverTLS on link scopes

302510 of 418810 relevant lines covered (72.23%)

652751.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.46
/src/resolve/resolvectl.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <getopt.h>
4
#include <locale.h>
5
#include <net/if.h>
6

7
#include "sd-bus.h"
8
#include "sd-daemon.h"
9
#include "sd-event.h"
10
#include "sd-json.h"
11
#include "sd-netlink.h"
12
#include "sd-varlink.h"
13

14
#include "af-list.h"
15
#include "alloc-util.h"
16
#include "argv-util.h"
17
#include "build.h"
18
#include "bus-common-errors.h"
19
#include "bus-error.h"
20
#include "bus-locator.h"
21
#include "bus-map-properties.h"
22
#include "bus-message-util.h"
23
#include "bus-util.h"
24
#include "dns-domain.h"
25
#include "errno-list.h"
26
#include "errno-util.h"
27
#include "escape.h"
28
#include "format-ifname.h"
29
#include "format-table.h"
30
#include "hostname-util.h"
31
#include "json-util.h"
32
#include "main-func.h"
33
#include "missing-network.h"
34
#include "netlink-util.h"
35
#include "openssl-util.h"
36
#include "pager.h"
37
#include "parse-argument.h"
38
#include "parse-util.h"
39
#include "polkit-agent.h"
40
#include "pretty-print.h"
41
#include "resolvconf-compat.h"
42
#include "resolve-util.h"
43
#include "resolvectl.h"
44
#include "resolved-def.h"
45
#include "resolved-dns-packet.h"
46
#include "resolved-dns-rr.h"
47
#include "resolved-util.h"
48
#include "socket-netlink.h"
49
#include "sort-util.h"
50
#include "stdio-util.h"
51
#include "string-table.h"
52
#include "string-util.h"
53
#include "strv.h"
54
#include "terminal-util.h"
55
#include "time-util.h"
56
#include "utf8.h"
57
#include "varlink-util.h"
58
#include "verb-log-control.h"
59
#include "verbs.h"
60

61
static int arg_family = AF_UNSPEC;
62
static int arg_ifindex = 0;
63
static char *arg_ifname = NULL;
64
static uint16_t arg_type = 0;
65
static uint16_t arg_class = 0;
66
static bool arg_legend = true;
67
static uint64_t arg_flags = 0;
68
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
69
static PagerFlags arg_pager_flags = 0;
70
bool arg_ifindex_permissive = false; /* If true, don't generate an error if the specified interface index doesn't exist */
71
static const char *arg_service_family = NULL;
72
static bool arg_ask_password = true;
73

74
typedef enum RawType {
75
        RAW_NONE,
76
        RAW_PAYLOAD,
77
        RAW_PACKET,
78
} RawType;
79
static RawType arg_raw = RAW_NONE;
80

81
/* Used by compat interfaces: systemd-resolve and resolvconf. */
82
ExecutionMode arg_mode = MODE_RESOLVE_HOST;
83
char **arg_set_dns = NULL;
84
char **arg_set_domain = NULL;
85
bool arg_disable_default_route = false;
86
static const char *arg_set_llmnr = NULL;
87
static const char *arg_set_mdns = NULL;
88
static const char *arg_set_dns_over_tls = NULL;
89
static const char *arg_set_dnssec = NULL;
90
static char **arg_set_nta = NULL;
91

92
STATIC_DESTRUCTOR_REGISTER(arg_ifname, freep);
232✔
93
STATIC_DESTRUCTOR_REGISTER(arg_set_dns, strv_freep);
232✔
94
STATIC_DESTRUCTOR_REGISTER(arg_set_domain, strv_freep);
232✔
95
STATIC_DESTRUCTOR_REGISTER(arg_set_nta, strv_freep);
232✔
96

97
typedef enum StatusMode {
98
        STATUS_ALL,
99
        STATUS_DNS,
100
        STATUS_DOMAIN,
101
        STATUS_DEFAULT_ROUTE,
102
        STATUS_LLMNR,
103
        STATUS_MDNS,
104
        STATUS_PRIVATE,
105
        STATUS_DNSSEC,
106
        STATUS_NTA,
107
} StatusMode;
108

109
typedef struct InterfaceInfo {
110
        int index;
111
        const char *name;
112
} InterfaceInfo;
113

114
static int acquire_bus(sd_bus **ret) {
223✔
115
        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
223✔
116
        int r;
223✔
117

118
        assert(ret);
223✔
119

120
        r = sd_bus_open_system(&bus);
223✔
121
        if (r < 0)
223✔
122
                return log_error_errno(r, "sd_bus_open_system: %m");
×
123

124
        (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
223✔
125

126
        *ret = TAKE_PTR(bus);
223✔
127
        return 0;
223✔
128
}
129

130
static int interface_info_compare(const InterfaceInfo *a, const InterfaceInfo *b) {
13✔
131
        int r;
13✔
132

133
        r = CMP(a->index, b->index);
13✔
134
        if (r != 0)
×
135
                return r;
13✔
136

137
        return strcmp_ptr(a->name, b->name);
×
138
}
139

140
int ifname_mangle_full(const char *s, bool drop_protocol_specifier) {
165✔
141
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
165✔
142
        _cleanup_strv_free_ char **found = NULL;
165✔
143
        int r;
165✔
144

145
        assert(s);
165✔
146

147
        if (drop_protocol_specifier) {
165✔
148
                _cleanup_free_ char *buf = NULL;
11✔
149
                int ifindex_longest_name = -ENODEV;
11✔
150

151
                /* When invoked as resolvconf, drop the protocol specifier(s) at the end. */
152

153
                buf = strdup(s);
11✔
154
                if (!buf)
11✔
155
                        return log_oom();
×
156

157
                for (;;) {
27✔
158
                        r = rtnl_resolve_interface(&rtnl, buf);
19✔
159
                        if (r > 0) {
19✔
160
                                if (ifindex_longest_name <= 0)
13✔
161
                                        ifindex_longest_name = r;
11✔
162

163
                                r = strv_extend(&found, buf);
13✔
164
                                if (r < 0)
13✔
165
                                        return log_oom();
×
166
                        }
167

168
                        char *dot = strrchr(buf, '.');
19✔
169
                        if (!dot)
19✔
170
                                break;
171

172
                        *dot = '\0';
8✔
173
                }
174

175
                unsigned n = strv_length(found);
11✔
176
                if (n > 1) {
11✔
177
                        _cleanup_free_ char *joined = NULL;
2✔
178

179
                        joined = strv_join(found, ", ");
2✔
180
                        log_warning("Found multiple interfaces (%s) matching with '%s'. Using '%s' (ifindex=%i).",
2✔
181
                                    strna(joined), s, found[0], ifindex_longest_name);
182

183
                } else if (n == 1) {
9✔
184
                        const char *proto;
9✔
185

186
                        proto = ASSERT_PTR(startswith(s, found[0]));
9✔
187
                        if (!isempty(proto))
9✔
188
                                log_info("Dropped protocol specifier '%s' from '%s'. Using '%s' (ifindex=%i).",
1✔
189
                                         proto, s, found[0], ifindex_longest_name);
190
                }
191

192
                r = ifindex_longest_name;
11✔
193
        } else
194
                r = rtnl_resolve_interface(&rtnl, s);
154✔
195
        if (r < 0) {
165✔
196
                if (ERRNO_IS_DEVICE_ABSENT(r) && arg_ifindex_permissive) {
×
197
                        log_debug_errno(r, "Interface '%s' not found, but -f specified, ignoring: %m", s);
×
198
                        return 0; /* done */
×
199
                }
200
                return log_error_errno(r, "Failed to resolve interface \"%s\": %m", s);
×
201
        }
202

203
        if (arg_ifindex > 0 && arg_ifindex != r)
165✔
204
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified multiple different interfaces. Refusing.");
×
205

206
        arg_ifindex = r;
165✔
207
        return free_and_strdup_warn(&arg_ifname, found ? found[0] : s); /* found */
165✔
208
}
209

210
static void print_source(uint64_t flags, usec_t rtt) {
39✔
211
        if (!arg_legend)
39✔
212
                return;
5✔
213

214
        if (sd_json_format_enabled(arg_json_format_flags))
36✔
215
                return;
216

217
        if (flags == 0)
34✔
218
                return;
219

220
        printf("\n%s-- Information acquired via", ansi_grey());
34✔
221

222
        printf(" protocol%s%s%s%s%s",
34✔
223
               flags & SD_RESOLVED_DNS ? " DNS" :"",
34✔
224
               flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
34✔
225
               flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
34✔
226
               flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
34✔
227
               flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
34✔
228

229
        printf(" in %s.%s\n"
102✔
230
               "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n",
231
               FORMAT_TIMESPAN(rtt, 100),
34✔
232
               ansi_normal(),
233
               ansi_grey(),
234
               yes_no(flags & SD_RESOLVED_AUTHENTICATED),
34✔
235
               yes_no(flags & SD_RESOLVED_CONFIDENTIAL),
34✔
236
               ansi_normal());
237

238
        if ((flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)) != 0)
34✔
239
                printf("%s-- Data from:%s%s%s%s%s%s\n",
68✔
240
                       ansi_grey(),
241
                       FLAGS_SET(flags, SD_RESOLVED_SYNTHETIC) ? " synthetic" : "",
34✔
242
                       FLAGS_SET(flags, SD_RESOLVED_FROM_CACHE) ? " cache" : "",
34✔
243
                       FLAGS_SET(flags, SD_RESOLVED_FROM_ZONE) ? " zone" : "",
34✔
244
                       FLAGS_SET(flags, SD_RESOLVED_FROM_TRUST_ANCHOR) ? " trust-anchor" : "",
34✔
245
                       FLAGS_SET(flags, SD_RESOLVED_FROM_NETWORK) ? " network" : "",
34✔
246
                       ansi_normal());
247
}
248

249
static void print_ifindex_comment(int printed_so_far, int ifindex) {
57✔
250
        char ifname[IF_NAMESIZE];
57✔
251
        int r;
57✔
252

253
        if (ifindex <= 0)
57✔
254
                return;
2✔
255

256
        r = format_ifname(ifindex, ifname);
55✔
257
        if (r < 0)
55✔
258
                return (void) log_warning_errno(r, "Failed to resolve interface name for index %i, ignoring: %m", ifindex);
×
259

260
        printf("%*s%s-- link: %s%s",
110✔
261
               60 > printed_so_far ? 60 - printed_so_far : 0, " ", /* Align comment to the 60th column */
262
               ansi_grey(), ifname, ansi_normal());
263
}
264

265
static int resolve_host_error(const char *name, int r, const sd_bus_error *error) {
8✔
266
        if (sd_bus_error_has_name(error, BUS_ERROR_DNS_NXDOMAIN))
8✔
267
                return log_error_errno(r, "%s: %s", name, bus_error_message(error, r));
1✔
268

269
        return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(error, r));
7✔
270
}
271

272
static int resolve_host(sd_bus *bus, const char *name) {
27✔
273
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
54✔
274
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
27✔
275
        const char *canonical = NULL;
27✔
276
        unsigned c = 0;
27✔
277
        uint64_t flags;
27✔
278
        usec_t ts;
27✔
279
        int r;
27✔
280

281
        assert(name);
27✔
282

283
        if (sd_json_format_enabled(arg_json_format_flags))
27✔
284
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type=A or --type=AAAA to acquire address record information in JSON format.");
×
285

286
        log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
27✔
287

288
        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
27✔
289
        if (r < 0)
27✔
290
                return bus_log_create_error(r);
×
291

292
        r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
27✔
293
        if (r < 0)
27✔
294
                return bus_log_create_error(r);
×
295

296
        ts = now(CLOCK_MONOTONIC);
27✔
297

298
        r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
27✔
299
        if (r < 0)
27✔
300
                return resolve_host_error(name, r, &error);
8✔
301

302
        ts = now(CLOCK_MONOTONIC) - ts;
19✔
303

304
        r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
19✔
305
        if (r < 0)
19✔
306
                return bus_log_parse_error(r);
×
307

308
        while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
56✔
309
                _cleanup_free_ char *pretty = NULL;
37✔
310
                int ifindex, family, k;
37✔
311
                union in_addr_union a;
37✔
312

313
                assert_cc(sizeof(int) == sizeof(int32_t));
37✔
314

315
                r = sd_bus_message_read(reply, "i", &ifindex);
37✔
316
                if (r < 0)
37✔
317
                        return bus_log_parse_error(r);
×
318

319
                sd_bus_error_free(&error);
37✔
320
                r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
37✔
321
                if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
37✔
322
                        return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
×
323

324
                r = sd_bus_message_exit_container(reply);
37✔
325
                if (r < 0)
37✔
326
                        return bus_log_parse_error(r);
×
327

328
                if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
37✔
329
                        log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
×
330
                        continue;
×
331
                }
332

333
                r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
37✔
334
                if (r < 0)
37✔
335
                        return log_error_errno(r, "Failed to print address for %s: %m", name);
×
336

337
                k = printf("%*s%s %s%s%s",
111✔
338
                           (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
37✔
339
                           ansi_highlight(), pretty, ansi_normal());
340

341
                print_ifindex_comment(k, ifindex);
37✔
342
                fputc('\n', stdout);
37✔
343

344
                c++;
37✔
345
        }
346
        if (r < 0)
19✔
347
                return bus_log_parse_error(r);
×
348

349
        r = sd_bus_message_exit_container(reply);
19✔
350
        if (r < 0)
19✔
351
                return bus_log_parse_error(r);
×
352

353
        r = sd_bus_message_read(reply, "st", &canonical, &flags);
19✔
354
        if (r < 0)
19✔
355
                return bus_log_parse_error(r);
×
356

357
        if (!streq(name, canonical))
19✔
358
                printf("%*s%s (%s)\n",
×
359
                       (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
×
360
                       canonical);
361

362
        if (c == 0)
19✔
363
                return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
×
364
                                       "%s: no addresses found", name);
365

366
        print_source(flags, ts);
19✔
367

368
        return 0;
369
}
370

371
static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
2✔
372
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
4✔
373
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
374
        _cleanup_free_ char *pretty = NULL;
2✔
375
        uint64_t flags;
2✔
376
        unsigned c = 0;
2✔
377
        usec_t ts;
2✔
378
        int r;
2✔
379

380
        assert(bus);
2✔
381
        assert(IN_SET(family, AF_INET, AF_INET6));
2✔
382
        assert(address);
2✔
383

384
        if (sd_json_format_enabled(arg_json_format_flags))
2✔
385
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
×
386

387
        if (ifindex <= 0)
2✔
388
                ifindex = arg_ifindex;
2✔
389

390
        r = in_addr_ifindex_to_string(family, address, ifindex, &pretty);
2✔
391
        if (r < 0)
2✔
392
                return log_oom();
×
393

394
        log_debug("Resolving %s.", pretty);
2✔
395

396
        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
2✔
397
        if (r < 0)
2✔
398
                return bus_log_create_error(r);
×
399

400
        r = sd_bus_message_append(req, "ii", ifindex, family);
2✔
401
        if (r < 0)
2✔
402
                return bus_log_create_error(r);
×
403

404
        r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
2✔
405
        if (r < 0)
2✔
406
                return bus_log_create_error(r);
×
407

408
        r = sd_bus_message_append(req, "t", arg_flags);
2✔
409
        if (r < 0)
2✔
410
                return bus_log_create_error(r);
×
411

412
        ts = now(CLOCK_MONOTONIC);
2✔
413

414
        r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
2✔
415
        if (r < 0)
2✔
416
                return log_error_errno(r, "%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
×
417

418
        ts = now(CLOCK_MONOTONIC) - ts;
2✔
419

420
        r = sd_bus_message_enter_container(reply, 'a', "(is)");
2✔
421
        if (r < 0)
2✔
422
                return bus_log_create_error(r);
×
423

424
        while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
4✔
425
                const char *n;
2✔
426
                int k;
2✔
427

428
                assert_cc(sizeof(int) == sizeof(int32_t));
2✔
429

430
                r = sd_bus_message_read(reply, "is", &ifindex, &n);
2✔
431
                if (r < 0)
2✔
432
                        return r;
×
433

434
                r = sd_bus_message_exit_container(reply);
2✔
435
                if (r < 0)
2✔
436
                        return r;
437

438
                k = printf("%*s%s %s%s%s",
6✔
439
                           (int) strlen(pretty), c == 0 ? pretty : "",
2✔
440
                           c == 0 ? ":" : " ",
441
                           ansi_highlight(), n, ansi_normal());
442

443
                print_ifindex_comment(k, ifindex);
2✔
444
                fputc('\n', stdout);
2✔
445

446
                c++;
2✔
447
        }
448
        if (r < 0)
2✔
449
                return bus_log_parse_error(r);
×
450

451
        r = sd_bus_message_exit_container(reply);
2✔
452
        if (r < 0)
2✔
453
                return bus_log_parse_error(r);
×
454

455
        r = sd_bus_message_read(reply, "t", &flags);
2✔
456
        if (r < 0)
2✔
457
                return bus_log_parse_error(r);
×
458

459
        if (c == 0)
2✔
460
                return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
×
461
                                       "%s: no names found", pretty);
462

463
        print_source(flags, ts);
2✔
464

465
        return 0;
466
}
467

468
static int output_rr_packet(const void *d, size_t l, int ifindex) {
12✔
469
        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
12✔
470
        int r;
12✔
471

472
        assert(d || l == 0);
12✔
473

474
        r = dns_resource_record_new_from_raw(&rr, d, l);
12✔
475
        if (r < 0)
12✔
476
                return log_error_errno(r, "Failed to parse RR: %m");
×
477

478
        if (sd_json_format_enabled(arg_json_format_flags)) {
12✔
479
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
2✔
480
                r = dns_resource_record_to_json(rr, &j);
2✔
481
                if (r < 0)
2✔
482
                        return log_error_errno(r, "Failed to convert RR to JSON: %m");
×
483

484
                if (!j)
2✔
485
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "JSON formatting for records of type %s (%u) not available.", dns_type_to_string(rr->key->type), rr->key->type);
×
486

487
                r = sd_json_variant_dump(j, arg_json_format_flags, NULL, NULL);
2✔
488
                if (r < 0)
2✔
489
                        return r;
490

491
        } else if (arg_raw == RAW_PAYLOAD) {
10✔
492
                const void *data;
×
493
                ssize_t k;
×
494

495
                k = dns_resource_record_payload(rr, &data);
×
496
                if (k == -EINVAL)
×
497
                        return log_error_errno(k, "Dumping of binary payload not available for RRs of this type: %s", dns_type_to_string(rr->key->type));
×
498
                if (k < 0)
×
499
                        return log_error_errno(k, "Cannot dump RR: %m");
×
500
                fwrite(data, 1, k, stdout);
×
501
        } else {
502
                const char *s;
10✔
503
                int k;
10✔
504

505
                s = dns_resource_record_to_string(rr);
10✔
506
                if (!s)
10✔
507
                        return log_oom();
×
508

509
                k = printf("%s", s);
10✔
510
                print_ifindex_comment(k, ifindex);
10✔
511
                fputc('\n', stdout);
10✔
512
        }
513

514
        return 0;
515
}
516

517
static int idna_candidate(const char *name, char **ret) {
18✔
518
        _cleanup_free_ char *idnafied = NULL;
18✔
519
        int r;
18✔
520

521
        assert(name);
18✔
522
        assert(ret);
18✔
523

524
        r = dns_name_apply_idna(name, &idnafied);
18✔
525
        if (r < 0)
18✔
526
                return log_error_errno(r, "Failed to apply IDNA to name '%s': %m", name);
×
527
        if (r > 0 && !streq(name, idnafied)) {
18✔
528
                *ret = TAKE_PTR(idnafied);
×
529
                return true;
×
530
        }
531

532
        *ret = NULL;
18✔
533
        return false;
18✔
534
}
535

536
static bool single_label_nonsynthetic(const char *name) {
18✔
537
        _cleanup_free_ char *first_label = NULL;
18✔
538
        int r;
18✔
539

540
        if (!dns_name_is_single_label(name))
18✔
541
                return false;
542

543
        if (is_localhost(name) ||
16✔
544
            is_gateway_hostname(name) ||
14✔
545
            is_outbound_hostname(name) ||
14✔
546
            is_dns_stub_hostname(name) ||
14✔
547
            is_dns_proxy_stub_hostname(name))
7✔
548
                return false;
549

550
        r = resolve_system_hostname(NULL, &first_label);
7✔
551
        if (r < 0) {
7✔
552
                log_warning_errno(r, "Failed to determine the hostname: %m");
×
553
                return false;
×
554
        }
555

556
        return !streq(name, first_label);
7✔
557
}
558

559
static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
18✔
560
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
36✔
561
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
562
        _cleanup_free_ char *idnafied = NULL;
18✔
563
        bool needs_authentication = false;
18✔
564
        unsigned n = 0;
18✔
565
        uint64_t flags;
18✔
566
        usec_t ts;
18✔
567
        int r;
18✔
568

569
        assert(name);
18✔
570

571
        log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname);
18✔
572

573
        if (dns_name_dot_suffixed(name) == 0 && single_label_nonsynthetic(name))
18✔
574
                log_notice("(Note that search domains are not appended when --type= is specified. "
7✔
575
                           "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)");
576

577
        r = idna_candidate(name, &idnafied);
18✔
578
        if (r < 0)
18✔
579
                return r;
580
        if (r > 0)
18✔
581
                log_notice("(Note that IDNA translation is not applied when --type= is specified. "
×
582
                           "Please specify translated domain names — i.e. '%s' — when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.",
583
                           idnafied);
584

585
        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord");
18✔
586
        if (r < 0)
18✔
587
                return bus_log_create_error(r);
×
588

589
        r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
18✔
590
        if (r < 0)
18✔
591
                return bus_log_create_error(r);
×
592

593
        ts = now(CLOCK_MONOTONIC);
18✔
594

595
        r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
18✔
596
        if (r < 0) {
18✔
597
                if (warn_missing || r != -ENXIO)
6✔
598
                        log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
6✔
599
                return r;
6✔
600
        }
601

602
        ts = now(CLOCK_MONOTONIC) - ts;
12✔
603

604
        r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
12✔
605
        if (r < 0)
12✔
606
                return bus_log_parse_error(r);
×
607

608
        while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
24✔
609
                uint16_t c, t;
12✔
610
                int ifindex;
12✔
611
                const void *d;
12✔
612
                size_t l;
12✔
613

614
                assert_cc(sizeof(int) == sizeof(int32_t));
12✔
615

616
                r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
12✔
617
                if (r < 0)
12✔
618
                        return bus_log_parse_error(r);
×
619

620
                r = sd_bus_message_read_array(reply, 'y', &d, &l);
12✔
621
                if (r < 0)
12✔
622
                        return bus_log_parse_error(r);
×
623

624
                r = sd_bus_message_exit_container(reply);
12✔
625
                if (r < 0)
12✔
626
                        return bus_log_parse_error(r);
×
627

628
                if (arg_raw == RAW_PACKET) {
12✔
629
                        uint64_t u64 = htole64(l);
×
630

631
                        fwrite(&u64, sizeof(u64), 1, stdout);
×
632
                        fwrite(d, 1, l, stdout);
×
633
                } else {
634
                        r = output_rr_packet(d, l, ifindex);
12✔
635
                        if (r < 0)
12✔
636
                                return r;
637
                }
638

639
                if (dns_type_needs_authentication(t))
12✔
640
                        needs_authentication = true;
1✔
641

642
                n++;
12✔
643
        }
644
        if (r < 0)
12✔
645
                return bus_log_parse_error(r);
×
646

647
        r = sd_bus_message_exit_container(reply);
12✔
648
        if (r < 0)
12✔
649
                return bus_log_parse_error(r);
×
650

651
        r = sd_bus_message_read(reply, "t", &flags);
12✔
652
        if (r < 0)
12✔
653
                return bus_log_parse_error(r);
×
654

655
        if (n == 0) {
12✔
656
                if (warn_missing)
×
657
                        log_error("%s: no records found", name);
×
658
                return -ESRCH;
×
659
        }
660

661
        print_source(flags, ts);
12✔
662

663
        if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
12✔
664
                fflush(stdout);
×
665

666
                fprintf(stderr, "\n%s"
×
667
                       "WARNING: The resources shown contain cryptographic key data which could not be\n"
668
                       "         authenticated. It is not suitable to authenticate any communication.\n"
669
                       "         This is usually indication that DNSSEC authentication was not enabled\n"
670
                       "         or is not available for the selected protocol or DNS servers.%s\n",
671
                       ansi_highlight_red(),
672
                       ansi_normal());
673
        }
674

675
        return 0;
676
}
677

678
static int resolve_rfc4501(sd_bus *bus, const char *name) {
×
679
        uint16_t type = 0, class = 0;
×
680
        const char *p, *q, *n;
×
681
        int r;
×
682

683
        assert(bus);
×
684
        assert(name);
×
685
        assert(startswith(name, "dns:"));
×
686

687
        /* Parse RFC 4501 dns: URIs */
688

689
        p = name + 4;
×
690

691
        if (p[0] == '/') {
×
692
                const char *e;
×
693

694
                if (p[1] != '/')
×
695
                        goto invalid;
×
696

697
                e = strchr(p + 2, '/');
×
698
                if (!e)
×
699
                        goto invalid;
×
700

701
                if (e != p + 2)
×
702
                        log_warning("DNS authority specification not supported; ignoring specified authority.");
×
703

704
                p = e + 1;
×
705
        }
706

707
        q = strchr(p, '?');
×
708
        if (q) {
×
709
                n = strndupa_safe(p, q - p);
×
710
                q++;
×
711

712
                for (;;) {
×
713
                        const char *f;
×
714

715
                        f = startswith_no_case(q, "class=");
×
716
                        if (f) {
×
717
                                _cleanup_free_ char *t = NULL;
×
718
                                const char *e;
×
719

720
                                if (class != 0)
×
721
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
722
                                                               "DNS class specified twice.");
723

724
                                e = strchrnul(f, ';');
×
725
                                t = strndup(f, e - f);
×
726
                                if (!t)
×
727
                                        return log_oom();
×
728

729
                                r = dns_class_from_string(t);
×
730
                                if (r < 0)
×
731
                                        return log_error_errno(r, "Unknown DNS class %s.", t);
×
732

733
                                class = r;
×
734

735
                                if (*e == ';') {
×
736
                                        q = e + 1;
×
737
                                        continue;
×
738
                                }
739

740
                                break;
×
741
                        }
742

743
                        f = startswith_no_case(q, "type=");
×
744
                        if (f) {
×
745
                                _cleanup_free_ char *t = NULL;
×
746
                                const char *e;
×
747

748
                                if (type != 0)
×
749
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
750
                                                               "DNS type specified twice.");
751

752
                                e = strchrnul(f, ';');
×
753
                                t = strndup(f, e - f);
×
754
                                if (!t)
×
755
                                        return log_oom();
×
756

757
                                r = dns_type_from_string(t);
×
758
                                if (r < 0)
×
759
                                        return log_error_errno(r, "Unknown DNS type %s: %m", t);
×
760

761
                                type = r;
×
762

763
                                if (*e == ';') {
×
764
                                        q = e + 1;
×
765
                                        continue;
×
766
                                }
767

768
                                break;
×
769
                        }
770

771
                        goto invalid;
×
772
                }
773
        } else
774
                n = p;
775

776
        if (class == 0)
×
777
                class = arg_class ?: DNS_CLASS_IN;
×
778
        if (type == 0)
×
779
                type = arg_type ?: DNS_TYPE_A;
×
780

781
        return resolve_record(bus, n, class, type, true);
×
782

783
invalid:
×
784
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
785
                               "Invalid DNS URI: %s", name);
786
}
787

788
static int verb_query(int argc, char **argv, void *userdata) {
46✔
789
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
46✔
790
        int ret = 0, r;
46✔
791

792
        r = acquire_bus(&bus);
46✔
793
        if (r < 0)
46✔
794
                return r;
795

796
        if (arg_type != 0)
46✔
797
                STRV_FOREACH(p, strv_skip(argv, 1))
34✔
798
                        RET_GATHER(ret, resolve_record(bus, *p, arg_class, arg_type, true));
17✔
799

800
        else
801
                STRV_FOREACH(p, strv_skip(argv, 1)) {
58✔
802
                        if (startswith(*p, "dns:"))
29✔
803
                                RET_GATHER(ret, resolve_rfc4501(bus, *p));
×
804
                        else {
805
                                int family, ifindex;
29✔
806
                                union in_addr_union a;
29✔
807

808
                                r = in_addr_ifindex_from_string_auto(*p, &family, &a, &ifindex);
29✔
809
                                if (r >= 0)
29✔
810
                                        RET_GATHER(ret, resolve_address(bus, family, &a, ifindex));
2✔
811
                                else
812
                                        RET_GATHER(ret, resolve_host(bus, *p));
27✔
813
                        }
814
                }
815

816
        return ret;
817
}
818

819
static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
9✔
820
        const char *canonical_name, *canonical_type, *canonical_domain;
9✔
821
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
18✔
822
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
9✔
823
        size_t indent, sz;
9✔
824
        uint64_t flags;
9✔
825
        const char *p;
9✔
826
        unsigned c;
9✔
827
        usec_t ts;
9✔
828
        int r;
9✔
829

830
        assert(bus);
9✔
831
        assert(domain);
9✔
832

833
        name = empty_to_null(name);
9✔
834
        type = empty_to_null(type);
9✔
835

836
        if (name)
9✔
837
                log_debug("Resolving service \"%s\" of type %s in %s (family %s, interface %s).", name, type, domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
×
838
        else if (type)
9✔
839
                log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
9✔
840
        else
841
                log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
×
842

843
        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveService");
9✔
844
        if (r < 0)
9✔
845
                return bus_log_create_error(r);
×
846

847
        r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
9✔
848
        if (r < 0)
9✔
849
                return bus_log_create_error(r);
×
850

851
        ts = now(CLOCK_MONOTONIC);
9✔
852

853
        r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
9✔
854
        if (r < 0)
9✔
855
                return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
3✔
856

857
        ts = now(CLOCK_MONOTONIC) - ts;
6✔
858

859
        r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
6✔
860
        if (r < 0)
6✔
861
                return bus_log_parse_error(r);
×
862

863
        indent =
12✔
864
                (name ? strlen(name) + 1 : 0) +
6✔
865
                (type ? strlen(type) + 1 : 0) +
6✔
866
                strlen(domain) + 2;
6✔
867

868
        c = 0;
6✔
869
        while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
12✔
870
                uint16_t priority, weight, port;
6✔
871
                const char *hostname, *canonical;
6✔
872

873
                r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
6✔
874
                if (r < 0)
6✔
875
                        return bus_log_parse_error(r);
×
876

877
                if (name)
6✔
878
                        printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
×
879
                if (type)
6✔
880
                        printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
6✔
881

882
                printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
6✔
883
                       (int) strlen(domain), c == 0 ? domain : "",
6✔
884
                       c == 0 ? ":" : " ",
885
                       hostname, port,
886
                       priority, weight);
887

888
                r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
6✔
889
                if (r < 0)
6✔
890
                        return bus_log_parse_error(r);
×
891

892
                while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
14✔
893
                        _cleanup_free_ char *pretty = NULL;
8✔
894
                        int ifindex, family, k;
8✔
895
                        union in_addr_union a;
8✔
896

897
                        assert_cc(sizeof(int) == sizeof(int32_t));
8✔
898

899
                        r = sd_bus_message_read(reply, "i", &ifindex);
8✔
900
                        if (r < 0)
8✔
901
                                return bus_log_parse_error(r);
×
902

903
                        sd_bus_error_free(&error);
8✔
904
                        r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
8✔
905
                        if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
8✔
906
                                return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
×
907

908
                        r = sd_bus_message_exit_container(reply);
8✔
909
                        if (r < 0)
8✔
910
                                return bus_log_parse_error(r);
×
911

912
                        if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
8✔
913
                                log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
×
914
                                continue;
×
915
                        }
916

917
                        r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
8✔
918
                        if (r < 0)
8✔
919
                                return log_error_errno(r, "Failed to print address for %s: %m", name);
×
920

921
                        k = printf("%*s%s", (int) indent, "", pretty);
8✔
922
                        print_ifindex_comment(k, ifindex);
8✔
923
                        fputc('\n', stdout);
8✔
924
                }
925
                if (r < 0)
6✔
926
                        return bus_log_parse_error(r);
×
927

928
                r = sd_bus_message_exit_container(reply);
6✔
929
                if (r < 0)
6✔
930
                        return bus_log_parse_error(r);
×
931

932
                r = sd_bus_message_read(reply, "s", &canonical);
6✔
933
                if (r < 0)
6✔
934
                        return bus_log_parse_error(r);
×
935

936
                if (!streq(hostname, canonical))
6✔
937
                        printf("%*s(%s)\n", (int) indent, "", canonical);
×
938

939
                r = sd_bus_message_exit_container(reply);
6✔
940
                if (r < 0)
6✔
941
                        return bus_log_parse_error(r);
×
942

943
                c++;
6✔
944
        }
945
        if (r < 0)
6✔
946
                return bus_log_parse_error(r);
×
947

948
        r = sd_bus_message_exit_container(reply);
6✔
949
        if (r < 0)
6✔
950
                return bus_log_parse_error(r);
×
951

952
        r = sd_bus_message_enter_container(reply, 'a', "ay");
6✔
953
        if (r < 0)
6✔
954
                return bus_log_parse_error(r);
×
955

956
        while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
9✔
957
                _cleanup_free_ char *escaped = NULL;
3✔
958

959
                escaped = cescape_length(p, sz);
3✔
960
                if (!escaped)
3✔
961
                        return log_oom();
×
962

963
                printf("%*s%s\n", (int) indent, "", escaped);
3✔
964
        }
965
        if (r < 0)
6✔
966
                return bus_log_parse_error(r);
×
967

968
        r = sd_bus_message_exit_container(reply);
6✔
969
        if (r < 0)
6✔
970
                return bus_log_parse_error(r);
×
971

972
        r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
6✔
973
        if (r < 0)
6✔
974
                return bus_log_parse_error(r);
×
975

976
        canonical_name = empty_to_null(canonical_name);
12✔
977
        canonical_type = empty_to_null(canonical_type);
6✔
978

979
        if (!streq_ptr(name, canonical_name) ||
6✔
980
            !streq_ptr(type, canonical_type) ||
6✔
981
            !streq_ptr(domain, canonical_domain)) {
6✔
982

983
                printf("%*s(", (int) indent, "");
×
984

985
                if (canonical_name)
×
986
                        printf("%s/", canonical_name);
×
987
                if (canonical_type)
×
988
                        printf("%s/", canonical_type);
×
989

990
                printf("%s)\n", canonical_domain);
×
991
        }
992

993
        print_source(flags, ts);
6✔
994

995
        return 0;
996
}
997

998
static int verb_service(int argc, char **argv, void *userdata) {
9✔
999
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
9✔
1000
        int r;
9✔
1001

1002
        r = acquire_bus(&bus);
9✔
1003
        if (r < 0)
9✔
1004
                return r;
1005

1006
        if (sd_json_format_enabled(arg_json_format_flags))
9✔
1007
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
×
1008

1009
        if (argc == 2)
9✔
1010
                return resolve_service(bus, NULL, NULL, argv[1]);
×
1011
        else if (argc == 3)
9✔
1012
                return resolve_service(bus, NULL, argv[1], argv[2]);
9✔
1013
        else
1014
                return resolve_service(bus, argv[1], argv[2], argv[3]);
×
1015
}
1016

1017
static int resolve_openpgp(sd_bus *bus, const char *address) {
1✔
1018
        const char *domain, *full;
1✔
1019
        int r;
1✔
1020
        _cleanup_free_ char *hashed = NULL;
1✔
1021

1022
        assert(bus);
1✔
1023
        assert(address);
1✔
1024

1025
        domain = strrchr(address, '@');
1✔
1026
        if (!domain)
1✔
1027
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1028
                                       "Address does not contain '@': \"%s\"", address);
1029
        if (domain == address || domain[1] == '\0')
1✔
1030
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1031
                                       "Address starts or ends with '@': \"%s\"", address);
1032
        domain++;
1✔
1033

1034
        r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
1✔
1035
        if (r < 0)
1✔
1036
                return log_error_errno(r, "Hashing failed: %m");
×
1037

1038
        strshorten(hashed, 56);
1✔
1039

1040
        full = strjoina(hashed, "._openpgpkey.", domain);
7✔
1041
        log_debug("Looking up \"%s\".", full);
1✔
1042

1043
        r = resolve_record(bus, full,
1✔
1044
                           arg_class ?: DNS_CLASS_IN,
1✔
1045
                           arg_type ?: DNS_TYPE_OPENPGPKEY, false);
1✔
1046

1047
        if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */
1✔
1048
              hashed = mfree(hashed);
×
1049
              r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
×
1050
              if (r < 0)
×
1051
                    return log_error_errno(r, "Hashing failed: %m");
×
1052

1053
              full = strjoina(hashed, "._openpgpkey.", domain);
×
1054
              log_debug("Looking up \"%s\".", full);
×
1055

1056
              return resolve_record(bus, full,
×
1057
                                    arg_class ?: DNS_CLASS_IN,
×
1058
                                    arg_type ?: DNS_TYPE_OPENPGPKEY, true);
×
1059
        }
1060

1061
        return r;
1062
}
1063

1064
static int verb_openpgp(int argc, char **argv, void *userdata) {
1✔
1065
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1✔
1066
        int r, ret = 0;
1✔
1067

1068
        r = acquire_bus(&bus);
1✔
1069
        if (r < 0)
1✔
1070
                return r;
1071

1072
        if (sd_json_format_enabled(arg_json_format_flags))
1✔
1073
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
×
1074

1075
        STRV_FOREACH(p, strv_skip(argv, 1))
2✔
1076
                RET_GATHER(ret, resolve_openpgp(bus, *p));
1✔
1077

1078
        return ret;
1079
}
1080

1081
static int resolve_tlsa(sd_bus *bus, const char *family, const char *address) {
×
1082
        const char *port;
×
1083
        uint16_t port_num = 443;
×
1084
        _cleanup_free_ char *full = NULL;
×
1085
        int r;
×
1086

1087
        assert(bus);
×
1088
        assert(address);
×
1089

1090
        port = strrchr(address, ':');
×
1091
        if (port) {
×
1092
                r = parse_ip_port(port + 1, &port_num);
×
1093
                if (r < 0)
×
1094
                        return log_error_errno(r, "Invalid port \"%s\".", port + 1);
×
1095

1096
                address = strndupa_safe(address, port - address);
×
1097
        }
1098

1099
        r = asprintf(&full, "_%u._%s.%s",
×
1100
                     port_num,
1101
                     family,
1102
                     address);
1103
        if (r < 0)
×
1104
                return log_oom();
×
1105

1106
        log_debug("Looking up \"%s\".", full);
×
1107

1108
        return resolve_record(bus, full,
×
1109
                              arg_class ?: DNS_CLASS_IN,
×
1110
                              arg_type ?: DNS_TYPE_TLSA, true);
×
1111
}
1112

1113
static bool service_family_is_valid(const char *s) {
×
1114
        return STR_IN_SET(s, "tcp", "udp", "sctp");
×
1115
}
1116

1117
static int verb_tlsa(int argc, char **argv, void *userdata) {
×
1118
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
×
1119
        const char *family = "tcp";
×
1120
        char **args;
×
1121
        int r, ret = 0;
×
1122

1123
        assert(argc >= 2);
×
1124

1125
        r = acquire_bus(&bus);
×
1126
        if (r < 0)
×
1127
                return r;
1128

1129
        if (sd_json_format_enabled(arg_json_format_flags))
×
1130
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
×
1131

1132
        if (service_family_is_valid(argv[1])) {
×
1133
                family = argv[1];
×
1134
                args = strv_skip(argv, 2);
×
1135
        } else
1136
                args = strv_skip(argv, 1);
×
1137

1138
        STRV_FOREACH(p, args)
×
1139
                RET_GATHER(ret, resolve_tlsa(bus, family, *p));
×
1140

1141
        return ret;
1142
}
1143

1144
static int show_statistics(int argc, char **argv, void *userdata) {
3✔
1145
        _cleanup_(table_unrefp) Table *table = NULL;
×
1146
        sd_json_variant *reply = NULL;
3✔
1147
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
3✔
1148
        int r;
3✔
1149

1150
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
3✔
1151

1152
        r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3✔
1153
        if (r < 0)
3✔
1154
                return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
×
1155

1156
        r = varlink_callbo_and_log(
3✔
1157
                        vl,
1158
                        "io.systemd.Resolve.Monitor.DumpStatistics",
1159
                        &reply,
1160
                        SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
1161
        if (r < 0)
3✔
1162
                return r;
1163

1164
        if (sd_json_format_enabled(arg_json_format_flags))
3✔
1165
                return sd_json_variant_dump(reply, arg_json_format_flags, NULL, NULL);
2✔
1166

1167
        struct statistics {
1✔
1168
                sd_json_variant *transactions;
1169
                sd_json_variant *cache;
1170
                sd_json_variant *dnssec;
1171
        } statistics;
1172

1173
        static const sd_json_dispatch_field statistics_dispatch_table[] = {
1✔
1174
                { "transactions", SD_JSON_VARIANT_OBJECT, sd_json_dispatch_variant_noref, offsetof(struct statistics, transactions), SD_JSON_MANDATORY },
1175
                { "cache",        SD_JSON_VARIANT_OBJECT, sd_json_dispatch_variant_noref, offsetof(struct statistics, cache),        SD_JSON_MANDATORY },
1176
                { "dnssec",       SD_JSON_VARIANT_OBJECT, sd_json_dispatch_variant_noref, offsetof(struct statistics, dnssec),       SD_JSON_MANDATORY },
1177
                {},
1178
        };
1179

1180
        r = sd_json_dispatch(reply, statistics_dispatch_table, SD_JSON_LOG, &statistics);
1✔
1181
        if (r < 0)
1✔
1182
                return r;
1183

1184
        struct transactions {
1✔
1185
                uint64_t n_current_transactions;
1186
                uint64_t n_transactions_total;
1187
                uint64_t n_timeouts_total;
1188
                uint64_t n_timeouts_served_stale_total;
1189
                uint64_t n_failure_responses_total;
1190
                uint64_t n_failure_responses_served_stale_total;
1191
        } transactions;
1192

1193
        static const sd_json_dispatch_field transactions_dispatch_table[] = {
1✔
1194
                { "currentTransactions",             _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct transactions, n_current_transactions),                 SD_JSON_MANDATORY },
1195
                { "totalTransactions",               _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct transactions, n_transactions_total),                   SD_JSON_MANDATORY },
1196
                { "totalTimeouts",                   _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct transactions, n_timeouts_total),                       SD_JSON_MANDATORY },
1197
                { "totalTimeoutsServedStale",        _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct transactions, n_timeouts_served_stale_total),          SD_JSON_MANDATORY },
1198
                { "totalFailedResponses",            _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct transactions, n_failure_responses_total),              SD_JSON_MANDATORY },
1199
                { "totalFailedResponsesServedStale", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct transactions, n_failure_responses_served_stale_total), SD_JSON_MANDATORY },
1200
                {},
1201
        };
1202

1203
        r = sd_json_dispatch(statistics.transactions, transactions_dispatch_table, SD_JSON_LOG, &transactions);
1✔
1204
        if (r < 0)
1✔
1205
                return r;
1206

1207
        struct cache {
1✔
1208
                uint64_t cache_size;
1209
                uint64_t n_cache_hit;
1210
                uint64_t n_cache_miss;
1211
        } cache;
1212

1213
        static const sd_json_dispatch_field cache_dispatch_table[] = {
1✔
1214
                { "size",   _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct cache, cache_size),   SD_JSON_MANDATORY },
1215
                { "hits",   _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct cache, n_cache_hit),  SD_JSON_MANDATORY },
1216
                { "misses", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct cache, n_cache_miss), SD_JSON_MANDATORY },
1217
                {},
1218
        };
1219

1220
        r = sd_json_dispatch(statistics.cache, cache_dispatch_table, SD_JSON_LOG, &cache);
1✔
1221
        if (r < 0)
1✔
1222
                return r;
1223

1224
        struct dnsssec {
1✔
1225
                uint64_t n_dnssec_secure;
1226
                uint64_t n_dnssec_insecure;
1227
                uint64_t n_dnssec_bogus;
1228
                uint64_t n_dnssec_indeterminate;
1229
        } dnsssec;
1230

1231
        static const sd_json_dispatch_field dnssec_dispatch_table[] = {
1✔
1232
                { "secure",        _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct dnsssec, n_dnssec_secure),        SD_JSON_MANDATORY },
1233
                { "insecure",      _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct dnsssec, n_dnssec_insecure),      SD_JSON_MANDATORY },
1234
                { "bogus",         _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct dnsssec, n_dnssec_bogus),         SD_JSON_MANDATORY },
1235
                { "indeterminate", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(struct dnsssec, n_dnssec_indeterminate), SD_JSON_MANDATORY },
1236
                {},
1237
        };
1238

1239
        r = sd_json_dispatch(statistics.dnssec, dnssec_dispatch_table, SD_JSON_LOG, &dnsssec);
1✔
1240
        if (r < 0)
1✔
1241
                return r;
1242

1243
        table = table_new_vertical();
1✔
1244
        if (!table)
1✔
1245
                return log_oom();
×
1246

1247
        r = table_add_many(table,
5✔
1248
                           TABLE_STRING, "Transactions",
1249
                           TABLE_SET_COLOR, ansi_highlight(),
1250
                           TABLE_SET_ALIGN_PERCENT, 0,
1251
                           TABLE_EMPTY,
1252
                           TABLE_FIELD, "Current Transactions",
1253
                           TABLE_SET_ALIGN_PERCENT, 100,
1254
                           TABLE_UINT64, transactions.n_current_transactions,
1255
                           TABLE_SET_ALIGN_PERCENT, 100,
1256
                           TABLE_FIELD, "Total Transactions",
1257
                           TABLE_UINT64, transactions.n_transactions_total,
1258
                           TABLE_EMPTY, TABLE_EMPTY,
1259
                           TABLE_STRING, "Cache",
1260
                           TABLE_SET_COLOR, ansi_highlight(),
1261
                           TABLE_SET_ALIGN_PERCENT, 0,
1262
                           TABLE_EMPTY,
1263
                           TABLE_FIELD, "Current Cache Size",
1264
                           TABLE_SET_ALIGN_PERCENT, 100,
1265
                           TABLE_UINT64, cache.cache_size,
1266
                           TABLE_FIELD, "Cache Hits",
1267
                           TABLE_UINT64, cache.n_cache_hit,
1268
                           TABLE_FIELD, "Cache Misses",
1269
                           TABLE_UINT64, cache.n_cache_miss,
1270
                           TABLE_EMPTY, TABLE_EMPTY,
1271
                           TABLE_STRING, "Failure Transactions",
1272
                           TABLE_SET_COLOR, ansi_highlight(),
1273
                           TABLE_SET_ALIGN_PERCENT, 0,
1274
                           TABLE_EMPTY,
1275
                           TABLE_FIELD, "Total Timeouts",
1276
                           TABLE_SET_ALIGN_PERCENT, 100,
1277
                           TABLE_UINT64, transactions.n_timeouts_total,
1278
                           TABLE_FIELD, "Total Timeouts (Stale Data Served)",
1279
                           TABLE_UINT64, transactions.n_timeouts_served_stale_total,
1280
                           TABLE_FIELD, "Total Failure Responses",
1281
                           TABLE_UINT64, transactions.n_failure_responses_total,
1282
                           TABLE_FIELD, "Total Failure Responses (Stale Data Served)",
1283
                           TABLE_UINT64, transactions.n_failure_responses_served_stale_total,
1284
                           TABLE_EMPTY, TABLE_EMPTY,
1285
                           TABLE_STRING, "DNSSEC Verdicts",
1286
                           TABLE_SET_COLOR, ansi_highlight(),
1287
                           TABLE_SET_ALIGN_PERCENT, 0,
1288
                           TABLE_EMPTY,
1289
                           TABLE_FIELD, "Secure",
1290
                           TABLE_SET_ALIGN_PERCENT, 100,
1291
                           TABLE_UINT64, dnsssec.n_dnssec_secure,
1292
                           TABLE_FIELD, "Insecure",
1293
                           TABLE_UINT64, dnsssec.n_dnssec_insecure,
1294
                           TABLE_FIELD, "Bogus",
1295
                           TABLE_UINT64, dnsssec.n_dnssec_bogus,
1296
                           TABLE_FIELD, "Indeterminate",
1297
                           TABLE_UINT64, dnsssec.n_dnssec_indeterminate
1298
                          );
1299
        if (r < 0)
1✔
1300
                return table_log_add_error(r);
×
1301

1302
        r = table_print(table, NULL);
1✔
1303
        if (r < 0)
1✔
1304
                return table_log_print_error(r);
×
1305

1306
        return 0;
1307
}
1308

1309
static int reset_statistics(int argc, char **argv, void *userdata) {
3✔
1310
        sd_json_variant *reply = NULL;
3✔
1311
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
3✔
1312
        int r;
3✔
1313

1314
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
3✔
1315

1316
        r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3✔
1317
        if (r < 0)
3✔
1318
                return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
×
1319

1320
        r = varlink_callbo_and_log(
3✔
1321
                        vl,
1322
                        "io.systemd.Resolve.Monitor.ResetStatistics",
1323
                        &reply,
1324
                        SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
1325
        if (r < 0)
3✔
1326
                return r;
1327

1328
        if (sd_json_format_enabled(arg_json_format_flags))
3✔
1329
                return sd_json_variant_dump(reply, arg_json_format_flags, NULL, NULL);
2✔
1330

1331
        return 0;
1332
}
1333

1334
static int flush_caches(int argc, char **argv, void *userdata) {
5✔
1335
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
5✔
1336
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5✔
1337
        int r;
5✔
1338

1339
        r = acquire_bus(&bus);
5✔
1340
        if (r < 0)
5✔
1341
                return r;
1342

1343
        r = bus_call_method(bus, bus_resolve_mgr, "FlushCaches", &error, NULL, NULL);
5✔
1344
        if (r < 0)
5✔
1345
                return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
×
1346

1347
        return 0;
1348
}
1349

1350
static int reset_server_features(int argc, char **argv, void *userdata) {
×
1351
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
×
1352
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1353
        int r;
×
1354

1355
        r = acquire_bus(&bus);
×
1356
        if (r < 0)
×
1357
                return r;
1358

1359
        r = bus_call_method(bus, bus_resolve_mgr, "ResetServerFeatures", &error, NULL, NULL);
×
1360
        if (r < 0)
×
1361
                return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
×
1362

1363
        return 0;
1364
}
1365

1366
typedef enum {
1367
        READ_DNS_WITH_IFINDEX = 1 << 0, /* read "ifindex" reply that also carries an interface index */
1368
        READ_DNS_EXTENDED     = 1 << 1, /* read "extended" reply, i.e. with port number and server name */
1369
        READ_DNS_ONLY_GLOBAL  = 1 << 2, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
1370
} ReadDNSFlag;
1371

1372
static const char *dns_server_property_signature(ReadDNSFlag flags) {
844✔
1373
        switch (flags & (READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED)) {
844✔
1374

1375
        case 0:
1376
                return "iay";
1377

1378
        case READ_DNS_WITH_IFINDEX:
45✔
1379
                return "iiay";
45✔
1380

1381
        case READ_DNS_EXTENDED:
375✔
1382
                return "iayqs";
375✔
1383

1384
        case READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED:
49✔
1385
                return "iiayqs";
49✔
1386

1387
        default:
×
1388
                assert_not_reached();
×
1389
        }
1390
}
1391

1392
static int read_dns_server_one(sd_bus_message *m, ReadDNSFlag flags, char **ret) {
649✔
1393
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1394
        _cleanup_free_ char *pretty = NULL;
649✔
1395
        union in_addr_union a;
649✔
1396
        const char *name = NULL;
649✔
1397
        int32_t ifindex = 0;
649✔
1398
        int family, r;
649✔
1399
        uint16_t port = 0;
649✔
1400

1401
        assert(m);
649✔
1402
        assert(ret);
649✔
1403

1404
        r = sd_bus_message_enter_container(
649✔
1405
                        m,
1406
                        'r',
1407
                        dns_server_property_signature(flags));
1408
        if (r <= 0)
649✔
1409
                return r;
1410

1411
        if (FLAGS_SET(flags, READ_DNS_WITH_IFINDEX)) {
426✔
1412
                r = sd_bus_message_read(m, "i", &ifindex);
64✔
1413
                if (r < 0)
64✔
1414
                        return r;
1415
        }
1416

1417
        r = bus_message_read_in_addr_auto(m, &error, &family, &a);
426✔
1418
        if (r < 0) {
426✔
1419
                if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
197✔
1420
                        /* CurrentDNSServer provides AF_UNSPEC when no current server assigned. */
1421
                        log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, r));
197✔
1422

1423
                        for (;;) {
592✔
1424
                                r = sd_bus_message_skip(m, NULL);
592✔
1425
                                if (r == -ENXIO) /* End of the container */
592✔
1426
                                        break;
1427
                                if (r < 0)
395✔
1428
                                        return r;
1429
                        }
1430

1431
                        r = sd_bus_message_exit_container(m);
197✔
1432
                        if (r < 0)
197✔
1433
                                return r;
1434

1435
                        *ret = NULL;
197✔
1436
                        return 1;
197✔
1437
                }
1438

1439
                return r;
1440
        }
1441

1442
        if (FLAGS_SET(flags, READ_DNS_EXTENDED)) {
229✔
1443
                r = sd_bus_message_read(m, "qs", &port, &name);
115✔
1444
                if (r < 0)
115✔
1445
                        return r;
1446
        }
1447

1448
        r = sd_bus_message_exit_container(m);
229✔
1449
        if (r < 0)
229✔
1450
                return r;
1451

1452
        if (FLAGS_SET(flags, READ_DNS_ONLY_GLOBAL) && ifindex > 0 && ifindex != LOOPBACK_IFINDEX) {
229✔
1453
                /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */
1454
                *ret = NULL;
16✔
1455
                return 1;
16✔
1456
        }
1457

1458
        r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty);
213✔
1459
        if (r < 0)
213✔
1460
                return r;
1461

1462
        *ret = TAKE_PTR(pretty);
213✔
1463
        return 1;
213✔
1464
}
1465

1466
static int map_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, ReadDNSFlag flags, sd_bus_error *error, void *userdata) {
195✔
1467
        char ***l = ASSERT_PTR(userdata);
195✔
1468
        int r;
195✔
1469

1470
        assert(bus);
195✔
1471
        assert(member);
195✔
1472
        assert(m);
195✔
1473

1474
        const char *sig = strjoina("(", dns_server_property_signature(flags), ")");
1,365✔
1475

1476
        r = sd_bus_message_enter_container(m, 'a', sig);
195✔
1477
        if (r < 0)
195✔
1478
                return r;
1479

1480
        for (;;) {
364✔
1481
                _cleanup_free_ char *pretty = NULL;
169✔
1482

1483
                r = read_dns_server_one(m, flags, &pretty);
364✔
1484
                if (r < 0)
364✔
1485
                        return r;
1486
                if (r == 0)
364✔
1487
                        break;
1488

1489
                if (isempty(pretty))
169✔
1490
                        continue;
×
1491

1492
                r = strv_consume(l, TAKE_PTR(pretty));
169✔
1493
                if (r < 0)
169✔
1494
                        return r;
1495
        }
1496

1497
        r = sd_bus_message_exit_container(m);
195✔
1498
        if (r < 0)
195✔
1499
                return r;
×
1500

1501
        return 0;
1502
}
1503

1504
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
97✔
1505
        return map_dns_servers_internal(bus, member, m, /* flags = */ 0, error, userdata);
97✔
1506
}
1507

1508
static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
97✔
1509
        return map_dns_servers_internal(bus, member, m, READ_DNS_EXTENDED, error, userdata);
97✔
1510
}
1511

1512
static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
97✔
1513
        assert(m);
97✔
1514
        assert(userdata);
97✔
1515

1516
        return read_dns_server_one(m, /* flags = */ 0, userdata);
97✔
1517
}
1518

1519
static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
97✔
1520
        assert(m);
97✔
1521
        assert(userdata);
97✔
1522

1523
        return read_dns_server_one(m, READ_DNS_EXTENDED, userdata);
97✔
1524
}
1525

1526
static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
135✔
1527
        _cleanup_free_ char *str = NULL;
270✔
1528
        int ifindex, route_only, r;
135✔
1529
        const char *domain;
135✔
1530

1531
        assert(m);
135✔
1532
        assert(ret);
135✔
1533

1534
        if (with_ifindex)
135✔
1535
                r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only);
7✔
1536
        else
1537
                r = sd_bus_message_read(m, "(sb)", &domain, &route_only);
128✔
1538
        if (r <= 0)
135✔
1539
                return r;
1540

1541
        if (with_ifindex && ifindex != 0) {
30✔
1542
                /* only show the global ones here */
1543
                *ret = NULL;
×
1544
                return 1;
×
1545
        }
1546

1547
        if (route_only)
30✔
1548
                str = strjoin("~", domain);
4✔
1549
        else
1550
                str = strdup(domain);
26✔
1551
        if (!str)
30✔
1552
                return -ENOMEM;
1553

1554
        *ret = TAKE_PTR(str);
30✔
1555
        return 1;
30✔
1556
}
1557

1558
static int map_domains_internal(
105✔
1559
                sd_bus *bus,
1560
                const char *member,
1561
                sd_bus_message *m,
1562
                bool with_ifindex,
1563
                sd_bus_error *error,
1564
                void *userdata) {
1565

1566
        char ***l = ASSERT_PTR(userdata);
105✔
1567
        int r;
105✔
1568

1569
        assert(bus);
105✔
1570
        assert(member);
105✔
1571
        assert(m);
105✔
1572

1573
        r = sd_bus_message_enter_container(m, 'a', with_ifindex ? "(isb)" : "(sb)");
203✔
1574
        if (r < 0)
105✔
1575
                return r;
1576

1577
        for (;;) {
135✔
1578
                _cleanup_free_ char *pretty = NULL;
30✔
1579

1580
                r = read_domain_one(m, with_ifindex, &pretty);
135✔
1581
                if (r < 0)
135✔
1582
                        return r;
1583
                if (r == 0)
135✔
1584
                        break;
1585

1586
                if (isempty(pretty))
30✔
1587
                        continue;
×
1588

1589
                r = strv_consume(l, TAKE_PTR(pretty));
30✔
1590
                if (r < 0)
30✔
1591
                        return r;
1592
        }
1593

1594
        r = sd_bus_message_exit_container(m);
105✔
1595
        if (r < 0)
105✔
1596
                return r;
×
1597

1598
        return 0;
1599
}
1600

1601
static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
97✔
1602
        return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata);
97✔
1603
}
1604

1605
static int status_print_strv_full(int ifindex, const char *ifname, const char *delegate_id, char **p) {
61✔
1606
        const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */
61✔
1607
        int pos1, pos2;
61✔
1608

1609
        if (ifname)
61✔
1610
                printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, ifindex, ifname, &pos2, ansi_normal());
118✔
1611
        else if (delegate_id)
2✔
1612
                printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1, delegate_id, &pos2, ansi_normal());
×
1613
        else
1614
                printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal());
4✔
1615

1616
        size_t cols = columns(), position = pos2 - pos1 + 2;
61✔
1617

1618
        STRV_FOREACH(i, p) {
125✔
1619
                size_t our_len = utf8_console_width(*i); /* This returns -1 on invalid utf-8 (which shouldn't happen).
64✔
1620
                                                          * If that happens, we'll just print one item per line. */
1621

1622
                if (position <= indent || size_add(size_add(position, 1), our_len) < cols) {
188✔
1623
                        printf(" %s", *i);
59✔
1624
                        position = size_add(size_add(position, 1), our_len);
123✔
1625
                } else {
1626
                        printf("\n%*s%s", (int) indent, "", *i);
5✔
1627
                        position = size_add(our_len, indent);
69✔
1628
                }
1629
        }
1630

1631
        printf("\n");
61✔
1632

1633
        return 0;
61✔
1634
}
1635

1636
static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
59✔
1637
        return status_print_strv_full(ifindex, ifname, NULL, p);
59✔
1638
}
1639

1640
static int status_print_strv_delegate(const char *delegate_id, char **p) {
×
1641
        return status_print_strv_full(0, NULL, delegate_id, p);
×
1642
}
1643

1644
static int status_print_strv_global(char **p) {
2✔
1645
        return status_print_strv_full(0, NULL, NULL, p);
2✔
1646
}
1647

1648
typedef struct LinkInfo {
1649
        uint64_t scopes_mask;
1650
        const char *llmnr;
1651
        const char *mdns;
1652
        const char *dns_over_tls;
1653
        const char *dnssec;
1654
        char *current_dns;
1655
        char *current_dns_ex;
1656
        char **dns;
1657
        char **dns_ex;
1658
        char **domains;
1659
        char **ntas;
1660
        bool dnssec_supported;
1661
        bool default_route;
1662
} LinkInfo;
1663

1664
typedef struct GlobalInfo {
1665
        char *current_dns;
1666
        char *current_dns_ex;
1667
        char **dns;
1668
        char **dns_ex;
1669
        char **fallback_dns;
1670
        char **fallback_dns_ex;
1671
        char **domains;
1672
        char **ntas;
1673
        const char *llmnr;
1674
        const char *mdns;
1675
        const char *dns_over_tls;
1676
        const char *dnssec;
1677
        const char *resolv_conf_mode;
1678
        bool dnssec_supported;
1679
} GlobalInfo;
1680

1681
static void link_info_done(LinkInfo *p) {
97✔
1682
        assert(p);
97✔
1683

1684
        free(p->current_dns);
97✔
1685
        free(p->current_dns_ex);
97✔
1686
        strv_free(p->dns);
97✔
1687
        strv_free(p->dns_ex);
97✔
1688
        strv_free(p->domains);
97✔
1689
        strv_free(p->ntas);
97✔
1690
}
97✔
1691

1692
static void global_info_done(GlobalInfo *p) {
7✔
1693
        assert(p);
7✔
1694

1695
        free(p->current_dns);
7✔
1696
        free(p->current_dns_ex);
7✔
1697
        strv_free(p->dns);
7✔
1698
        strv_free(p->dns_ex);
7✔
1699
        strv_free(p->fallback_dns);
7✔
1700
        strv_free(p->fallback_dns_ex);
7✔
1701
        strv_free(p->domains);
7✔
1702
        strv_free(p->ntas);
7✔
1703
}
7✔
1704

1705
static int dump_list(Table *table, const char *field, char * const *l) {
45✔
1706
        int r;
45✔
1707

1708
        if (strv_isempty(l))
45✔
1709
                return 0;
1710

1711
        r = table_add_many(table,
10✔
1712
                           TABLE_FIELD, field,
1713
                           TABLE_STRV_WRAPPED, l);
1714
        if (r < 0)
10✔
1715
                return table_log_add_error(r);
×
1716

1717
        return 0;
1718
}
1719

1720
static int strv_extend_extended_bool(char ***strv, const char *name, const char *value) {
57✔
1721
        int r;
57✔
1722

1723
        if (value) {
57✔
1724
                r = parse_boolean(value);
57✔
1725
                if (r >= 0)
57✔
1726
                        return strv_extendf(strv, "%s%s", plus_minus(r), name);
80✔
1727
        }
1728

1729
        return strv_extendf(strv, "%s=%s", name, value ?: "???");
3✔
1730
}
1731

1732
static char** link_protocol_status(const LinkInfo *info) {
14✔
1733
        _cleanup_strv_free_ char **s = NULL;
14✔
1734

1735
        if (strv_extendf(&s, "%sDefaultRoute", plus_minus(info->default_route)) < 0)
24✔
1736
                return NULL;
1737

1738
        if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0)
14✔
1739
                return NULL;
1740

1741
        if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0)
14✔
1742
                return NULL;
1743

1744
        if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0)
14✔
1745
                return NULL;
1746

1747
        if (strv_extendf(&s, "DNSSEC=%s/%s",
14✔
1748
                         info->dnssec ?: "???",
14✔
1749
                         info->dnssec_supported ? "supported" : "unsupported") < 0)
14✔
1750
                return NULL;
1751

1752
        return TAKE_PTR(s);
14✔
1753
}
1754

1755
static char** global_protocol_status(const GlobalInfo *info) {
5✔
1756
        _cleanup_strv_free_ char **s = NULL;
5✔
1757

1758
        if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0)
5✔
1759
                return NULL;
1760

1761
        if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0)
5✔
1762
                return NULL;
1763

1764
        if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0)
5✔
1765
                return NULL;
1766

1767
        if (strv_extendf(&s, "DNSSEC=%s/%s",
5✔
1768
                         info->dnssec ?: "???",
5✔
1769
                         info->dnssec_supported ? "supported" : "unsupported") < 0)
5✔
1770
                return NULL;
1771

1772
        return TAKE_PTR(s);
5✔
1773
}
1774

1775
static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
97✔
1776
        static const struct bus_properties_map property_map[] = {
97✔
1777
                { "ScopesMask",                 "t",        NULL,                           offsetof(LinkInfo, scopes_mask)      },
1778
                { "DNS",                        "a(iay)",   map_link_dns_servers,           offsetof(LinkInfo, dns)              },
1779
                { "DNSEx",                      "a(iayqs)", map_link_dns_servers_ex,        offsetof(LinkInfo, dns_ex)           },
1780
                { "CurrentDNSServer",           "(iay)",    map_link_current_dns_server,    offsetof(LinkInfo, current_dns)      },
1781
                { "CurrentDNSServerEx",         "(iayqs)",  map_link_current_dns_server_ex, offsetof(LinkInfo, current_dns_ex)   },
1782
                { "Domains",                    "a(sb)",    map_link_domains,               offsetof(LinkInfo, domains)          },
1783
                { "DefaultRoute",               "b",        NULL,                           offsetof(LinkInfo, default_route)    },
1784
                { "LLMNR",                      "s",        NULL,                           offsetof(LinkInfo, llmnr)            },
1785
                { "MulticastDNS",               "s",        NULL,                           offsetof(LinkInfo, mdns)             },
1786
                { "DNSOverTLS",                 "s",        NULL,                           offsetof(LinkInfo, dns_over_tls)     },
1787
                { "DNSSEC",                     "s",        NULL,                           offsetof(LinkInfo, dnssec)           },
1788
                { "DNSSECNegativeTrustAnchors", "as",       bus_map_strv_sort,              offsetof(LinkInfo, ntas)             },
1789
                { "DNSSECSupported",            "b",        NULL,                           offsetof(LinkInfo, dnssec_supported) },
1790
                {}
1791
        };
1792
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1793
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
97✔
1794
        _cleanup_(link_info_done) LinkInfo link_info = {};
97✔
1795
        _cleanup_(table_unrefp) Table *table = NULL;
×
1796
        _cleanup_free_ char *p = NULL;
97✔
1797
        char ifi[DECIMAL_STR_MAX(int)], ifname[IF_NAMESIZE];
97✔
1798
        int r;
97✔
1799

1800
        assert(bus);
97✔
1801
        assert(ifindex > 0);
97✔
1802

1803
        if (!name) {
97✔
1804
                r = format_ifname(ifindex, ifname);
77✔
1805
                if (r < 0)
77✔
1806
                        return log_error_errno(r, "Failed to resolve interface name for %i: %m", ifindex);
×
1807

1808
                name = ifname;
1809
        }
1810

1811
        xsprintf(ifi, "%i", ifindex);
97✔
1812
        r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p);
97✔
1813
        if (r < 0)
97✔
1814
                return log_oom();
×
1815

1816
        r = bus_map_all_properties(bus,
97✔
1817
                                   "org.freedesktop.resolve1",
1818
                                   p,
1819
                                   property_map,
1820
                                   BUS_MAP_BOOLEAN_AS_BOOL,
1821
                                   &error,
1822
                                   &m,
1823
                                   &link_info);
1824
        if (r < 0)
97✔
1825
                return log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
×
1826

1827
        pager_open(arg_pager_flags);
97✔
1828

1829
        switch (mode) {
97✔
1830

1831
        case STATUS_DNS:
29✔
1832
                return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns);
29✔
1833

1834
        case STATUS_DOMAIN:
30✔
1835
                return status_print_strv_ifindex(ifindex, name, link_info.domains);
30✔
1836

1837
        case STATUS_NTA:
×
1838
                return status_print_strv_ifindex(ifindex, name, link_info.ntas);
×
1839

1840
        case STATUS_DEFAULT_ROUTE:
2✔
1841
                printf("%sLink %i (%s)%s: %s\n",
4✔
1842
                       ansi_highlight(), ifindex, name, ansi_normal(),
1843
                       yes_no(link_info.default_route));
2✔
1844

1845
                return 0;
1846

1847
        case STATUS_LLMNR:
11✔
1848
                printf("%sLink %i (%s)%s: %s\n",
22✔
1849
                       ansi_highlight(), ifindex, name, ansi_normal(),
1850
                       strna(link_info.llmnr));
1851

1852
                return 0;
1853

1854
        case STATUS_MDNS:
11✔
1855
                printf("%sLink %i (%s)%s: %s\n",
22✔
1856
                       ansi_highlight(), ifindex, name, ansi_normal(),
1857
                       strna(link_info.mdns));
1858

1859
                return 0;
1860

1861
        case STATUS_PRIVATE:
×
1862
                printf("%sLink %i (%s)%s: %s\n",
×
1863
                       ansi_highlight(), ifindex, name, ansi_normal(),
1864
                       strna(link_info.dns_over_tls));
1865

1866
                return 0;
1867

1868
        case STATUS_DNSSEC:
×
1869
                printf("%sLink %i (%s)%s: %s\n",
×
1870
                       ansi_highlight(), ifindex, name, ansi_normal(),
1871
                       strna(link_info.dnssec));
1872

1873
                return 0;
1874

1875
        case STATUS_ALL:
1876
                break;
14✔
1877

1878
        default:
1879
                return 0;
1880
        }
1881

1882
        if (empty_line && *empty_line)
14✔
1883
                fputc('\n', stdout);
14✔
1884

1885
        printf("%sLink %i (%s)%s\n",
28✔
1886
               ansi_highlight(), ifindex, name, ansi_normal());
1887

1888
        table = table_new_vertical();
14✔
1889
        if (!table)
14✔
1890
                return log_oom();
×
1891

1892
        r = table_add_many(table,
14✔
1893
                           TABLE_FIELD, "Current Scopes",
1894
                           TABLE_SET_MINIMUM_WIDTH, 19);
1895
        if (r < 0)
14✔
1896
                return table_log_add_error(r);
×
1897

1898
        if (link_info.scopes_mask == 0)
14✔
1899
                r = table_add_cell(table, NULL, TABLE_STRING, "none");
9✔
1900
        else {
1901
                _cleanup_free_ char *buf = NULL;
5✔
1902
                size_t len;
5✔
1903

1904
                if (asprintf(&buf, "%s%s%s%s%s",
5✔
1905
                             link_info.scopes_mask & SD_RESOLVED_DNS ? "DNS " : "",
5✔
1906
                             link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? "LLMNR/IPv4 " : "",
5✔
1907
                             link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? "LLMNR/IPv6 " : "",
5✔
1908
                             link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4 " : "",
5✔
1909
                             link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6 " : "") < 0)
5✔
1910
                        return log_oom();
×
1911

1912
                len = strlen(buf);
5✔
1913
                assert(len > 0);
5✔
1914
                buf[len - 1] = '\0';
5✔
1915

1916
                r = table_add_cell(table, NULL, TABLE_STRING, buf);
5✔
1917
        }
1918
        if (r < 0)
14✔
1919
                return table_log_add_error(r);
×
1920

1921
        _cleanup_strv_free_ char **pstatus = link_protocol_status(&link_info);
28✔
1922
        if (!pstatus)
14✔
1923
                return log_oom();
×
1924

1925
        r = table_add_many(table,
14✔
1926
                           TABLE_FIELD,       "Protocols",
1927
                           TABLE_STRV_WRAPPED, pstatus);
1928
        if (r < 0)
14✔
1929
                return table_log_add_error(r);
×
1930

1931
        if (link_info.current_dns) {
14✔
1932
                r = table_add_many(table,
2✔
1933
                                   TABLE_FIELD, "Current DNS Server",
1934
                                   TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns);
1935
                if (r < 0)
2✔
1936
                        return table_log_add_error(r);
×
1937
        }
1938

1939
        r = dump_list(table, "DNS Servers", link_info.dns_ex ?: link_info.dns);
14✔
1940
        if (r < 0)
14✔
1941
                return r;
1942

1943
        r = dump_list(table, "DNS Domain", link_info.domains);
14✔
1944
        if (r < 0)
14✔
1945
                return r;
1946

1947
        r = table_add_many(table,
14✔
1948
                           TABLE_FIELD, "Default Route",
1949
                           TABLE_BOOLEAN, link_info.default_route);
1950
        if (r < 0)
14✔
1951
                return table_log_add_error(r);
×
1952

1953
        r = table_print(table, NULL);
14✔
1954
        if (r < 0)
14✔
1955
                return table_log_print_error(r);
×
1956

1957
        if (empty_line)
14✔
1958
                *empty_line = true;
14✔
1959

1960
        return 0;
1961
}
1962

1963
static int map_global_dns_servers_internal(
28✔
1964
                sd_bus *bus,
1965
                const char *member,
1966
                sd_bus_message *m,
1967
                sd_bus_error *error,
1968
                void *userdata,
1969
                ReadDNSFlag flags) {
1970

1971
        char ***l = ASSERT_PTR(userdata);
28✔
1972
        int r;
28✔
1973

1974
        assert(bus);
28✔
1975
        assert(member);
28✔
1976
        assert(m);
28✔
1977

1978
        r = sd_bus_message_enter_container(m, 'a', FLAGS_SET(flags, READ_DNS_EXTENDED) ? "(iiayqs)" : "(iiay)");
42✔
1979
        if (r < 0)
28✔
1980
                return r;
1981

1982
        for (;;) {
76✔
1983
                _cleanup_free_ char *pretty = NULL;
48✔
1984

1985
                r = read_dns_server_one(m, flags, &pretty);
76✔
1986
                if (r < 0)
76✔
1987
                        return r;
1988
                if (r == 0)
76✔
1989
                        break;
1990

1991
                if (isempty(pretty))
48✔
1992
                        continue;
16✔
1993

1994
                r = strv_consume(l, TAKE_PTR(pretty));
32✔
1995
                if (r < 0)
32✔
1996
                        return r;
1997
        }
1998

1999
        r = sd_bus_message_exit_container(m);
28✔
2000
        if (r < 0)
28✔
2001
                return r;
×
2002

2003
        return 0;
2004
}
2005

2006
static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
14✔
2007
        return map_global_dns_servers_internal(bus, member, m, error, userdata, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL);
14✔
2008
}
2009

2010
static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
14✔
2011
        return map_global_dns_servers_internal(bus, member, m, error, userdata, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL | READ_DNS_EXTENDED);
14✔
2012
}
2013

2014
static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
7✔
2015
        return read_dns_server_one(m, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL, userdata);
7✔
2016
}
2017

2018
static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
7✔
2019
        return read_dns_server_one(m, READ_DNS_WITH_IFINDEX | READ_DNS_ONLY_GLOBAL | READ_DNS_EXTENDED, userdata);
7✔
2020
}
2021

2022
static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
7✔
2023
        return map_domains_internal(bus, member, m, /* with_ifindex= */ true, error, userdata);
7✔
2024
}
2025

2026
static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
7✔
2027
        static const struct bus_properties_map property_map[] = {
7✔
2028
                { "DNS",                        "a(iiay)",   map_global_dns_servers,           offsetof(GlobalInfo, dns)              },
2029
                { "DNSEx",                      "a(iiayqs)", map_global_dns_servers_ex,        offsetof(GlobalInfo, dns_ex)           },
2030
                { "FallbackDNS",                "a(iiay)",   map_global_dns_servers,           offsetof(GlobalInfo, fallback_dns)     },
2031
                { "FallbackDNSEx",              "a(iiayqs)", map_global_dns_servers_ex,        offsetof(GlobalInfo, fallback_dns_ex)  },
2032
                { "CurrentDNSServer",           "(iiay)",    map_global_current_dns_server,    offsetof(GlobalInfo, current_dns)      },
2033
                { "CurrentDNSServerEx",         "(iiayqs)",  map_global_current_dns_server_ex, offsetof(GlobalInfo, current_dns_ex)   },
2034
                { "Domains",                    "a(isb)",    map_global_domains,               offsetof(GlobalInfo, domains)          },
2035
                { "DNSSECNegativeTrustAnchors", "as",        bus_map_strv_sort,                offsetof(GlobalInfo, ntas)             },
2036
                { "LLMNR",                      "s",         NULL,                             offsetof(GlobalInfo, llmnr)            },
2037
                { "MulticastDNS",               "s",         NULL,                             offsetof(GlobalInfo, mdns)             },
2038
                { "DNSOverTLS",                 "s",         NULL,                             offsetof(GlobalInfo, dns_over_tls)     },
2039
                { "DNSSEC",                     "s",         NULL,                             offsetof(GlobalInfo, dnssec)           },
2040
                { "DNSSECSupported",            "b",         NULL,                             offsetof(GlobalInfo, dnssec_supported) },
2041
                { "ResolvConfMode",             "s",         NULL,                             offsetof(GlobalInfo, resolv_conf_mode) },
2042
                {}
2043
        };
2044
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2045
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7✔
2046
        _cleanup_(global_info_done) GlobalInfo global_info = {};
7✔
2047
        _cleanup_(table_unrefp) Table *table = NULL;
7✔
2048
        int r;
7✔
2049

2050
        assert(bus);
7✔
2051
        assert(empty_line);
7✔
2052

2053
        r = bus_map_all_properties(bus,
7✔
2054
                                   "org.freedesktop.resolve1",
2055
                                   "/org/freedesktop/resolve1",
2056
                                   property_map,
2057
                                   BUS_MAP_BOOLEAN_AS_BOOL,
2058
                                   &error,
2059
                                   &m,
2060
                                   &global_info);
2061
        if (r < 0)
7✔
2062
                return log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
×
2063

2064
        pager_open(arg_pager_flags);
7✔
2065

2066
        switch (mode) {
7✔
2067

2068
        case STATUS_DNS:
2✔
2069
                return status_print_strv_global(global_info.dns_ex ?: global_info.dns);
2✔
2070

2071
        case STATUS_DOMAIN:
×
2072
                return status_print_strv_global(global_info.domains);
×
2073

2074
        case STATUS_NTA:
×
2075
                return status_print_strv_global(global_info.ntas);
×
2076

2077
        case STATUS_LLMNR:
×
2078
                printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
×
2079
                       strna(global_info.llmnr));
2080

2081
                return 0;
2082

2083
        case STATUS_MDNS:
×
2084
                printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
×
2085
                       strna(global_info.mdns));
2086

2087
                return 0;
2088

2089
        case STATUS_PRIVATE:
×
2090
                printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
×
2091
                       strna(global_info.dns_over_tls));
2092

2093
                return 0;
2094

2095
        case STATUS_DNSSEC:
×
2096
                printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
×
2097
                       strna(global_info.dnssec));
2098

2099
                return 0;
2100

2101
        case STATUS_ALL:
2102
                break;
5✔
2103

2104
        default:
2105
                return 0;
2106
        }
2107

2108
        printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
10✔
2109

2110
        table = table_new_vertical();
5✔
2111
        if (!table)
5✔
2112
                return log_oom();
×
2113

2114
        _cleanup_strv_free_ char **pstatus = global_protocol_status(&global_info);
10✔
2115
        if (!pstatus)
5✔
2116
                return log_oom();
×
2117

2118
        r = table_add_many(table,
5✔
2119
                           TABLE_FIELD,            "Protocols",
2120
                           TABLE_SET_MINIMUM_WIDTH, 19,
2121
                           TABLE_STRV_WRAPPED,      pstatus);
2122
        if (r < 0)
5✔
2123
                return table_log_add_error(r);
×
2124

2125
        if (global_info.resolv_conf_mode) {
5✔
2126
                r = table_add_many(table,
5✔
2127
                                   TABLE_FIELD, "resolv.conf mode",
2128
                                   TABLE_STRING, global_info.resolv_conf_mode);
2129
                if (r < 0)
5✔
2130
                        return table_log_add_error(r);
×
2131
        }
2132

2133
        if (global_info.current_dns) {
5✔
2134
                r = table_add_many(table,
×
2135
                                   TABLE_FIELD, "Current DNS Server",
2136
                                   TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns);
2137
                if (r < 0)
×
2138
                        return table_log_add_error(r);
×
2139
        }
2140

2141
        r = dump_list(table, "DNS Servers", global_info.dns_ex ?: global_info.dns);
5✔
2142
        if (r < 0)
5✔
2143
                return r;
2144

2145
        r = dump_list(table, "Fallback DNS Servers", global_info.fallback_dns_ex ?: global_info.fallback_dns);
5✔
2146
        if (r < 0)
5✔
2147
                return r;
2148

2149
        r = dump_list(table, "DNS Domain", global_info.domains);
5✔
2150
        if (r < 0)
5✔
2151
                return r;
2152

2153
        r = table_print(table, NULL);
5✔
2154
        if (r < 0)
5✔
2155
                return table_log_print_error(r);
×
2156

2157
        *empty_line = true;
5✔
2158

2159
        return 0;
5✔
2160
}
2161

2162
static int status_links(sd_bus *bus, StatusMode mode, bool *empty_line) {
7✔
2163
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
14✔
2164
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
7✔
2165
        int ret = 0, r;
7✔
2166

2167
        assert(bus);
7✔
2168

2169
        r = sd_netlink_open(&rtnl);
7✔
2170
        if (r < 0)
7✔
2171
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
2172

2173
        r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
7✔
2174
        if (r < 0)
7✔
2175
                return rtnl_log_create_error(r);
×
2176

2177
        r = sd_netlink_message_set_request_dump(req, true);
7✔
2178
        if (r < 0)
7✔
2179
                return rtnl_log_create_error(r);
×
2180

2181
        r = sd_netlink_call(rtnl, req, 0, &reply);
7✔
2182
        if (r < 0)
7✔
2183
                return log_error_errno(r, "Failed to enumerate links: %m");
×
2184

2185
        _cleanup_free_ InterfaceInfo *infos = NULL;
7✔
2186
        size_t n_infos = 0;
7✔
2187

2188
        for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
34✔
2189
                const char *name;
27✔
2190
                int ifindex;
27✔
2191
                uint16_t type;
27✔
2192

2193
                r = sd_netlink_message_get_type(i, &type);
27✔
2194
                if (r < 0)
27✔
2195
                        return rtnl_log_parse_error(r);
×
2196

2197
                if (type != RTM_NEWLINK)
27✔
2198
                        continue;
7✔
2199

2200
                r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
27✔
2201
                if (r < 0)
27✔
2202
                        return rtnl_log_parse_error(r);
×
2203

2204
                if (ifindex == LOOPBACK_IFINDEX)
27✔
2205
                        continue;
7✔
2206

2207
                r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
20✔
2208
                if (r < 0)
20✔
2209
                        return rtnl_log_parse_error(r);
×
2210

2211
                if (!GREEDY_REALLOC(infos, n_infos + 1))
20✔
2212
                        return log_oom();
×
2213

2214
                infos[n_infos++] = (InterfaceInfo) { ifindex, name };
20✔
2215
        }
2216

2217
        typesafe_qsort(infos, n_infos, interface_info_compare);
7✔
2218

2219
        FOREACH_ARRAY(info, infos, n_infos)
27✔
2220
                RET_GATHER(ret, status_ifindex(bus, info->index, info->name, mode, empty_line));
20✔
2221

2222
        return ret;
2223
}
2224

2225
typedef struct DelegateInfo {
2226
        char *current_dns;
2227
        char **dns;
2228
        char **domains;
2229
        bool default_route;
2230
} DelegateInfo;
2231

2232
static void delegate_info_done(DelegateInfo *p) {
1✔
2233
        assert(p);
1✔
2234

2235
        free(p->current_dns);
1✔
2236
        strv_free(p->dns);
1✔
2237
        strv_free(p->domains);
1✔
2238
}
1✔
2239

2240
static int map_delegate_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1✔
2241
        return map_dns_servers_internal(bus, member, m, READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED, error, userdata);
1✔
2242
}
2243

2244
static int map_delegate_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1✔
2245
        return read_dns_server_one(m, READ_DNS_WITH_IFINDEX|READ_DNS_EXTENDED, userdata);
1✔
2246
}
2247

2248
static int map_delegate_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1✔
2249
        return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata);
1✔
2250
}
2251

2252
static int status_delegate_one(sd_bus *bus, const char *id, StatusMode mode, bool *empty_line) {
1✔
2253

2254
        static const struct bus_properties_map property_map[] = {
1✔
2255
                { "DNS",              "a(iiayqs)", map_delegate_dns_servers,        offsetof(DelegateInfo, dns)           },
2256
                { "CurrentDNSServer", "(iiayqs)",  map_delegate_current_dns_server, offsetof(DelegateInfo, current_dns)   },
2257
                { "Domains",          "a(sb)",     map_delegate_domains,            offsetof(DelegateInfo, domains)       },
2258
                { "DefaultRoute",     "b",         NULL,                            offsetof(DelegateInfo, default_route) },
2259
                {}
2260
        };
2261

2262
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1✔
2263
        _cleanup_(delegate_info_done) DelegateInfo delegate_info = {};
×
2264
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1✔
2265
        _cleanup_free_ char *p = NULL;
1✔
2266
        int r;
1✔
2267

2268
        assert(bus);
1✔
2269
        assert(id);
1✔
2270

2271
        r = sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", id, &p);
1✔
2272
        if (r < 0)
1✔
2273
                return log_oom();
×
2274

2275
        r = bus_map_all_properties(
1✔
2276
                        bus,
2277
                        "org.freedesktop.resolve1",
2278
                        p,
2279
                        property_map,
2280
                        BUS_MAP_BOOLEAN_AS_BOOL,
2281
                        &error,
2282
                        &m,
2283
                        &delegate_info);
2284
        if (r < 0)
1✔
2285
                return log_error_errno(r, "Failed to get delegate data for %s: %s", id, bus_error_message(&error, r));
×
2286

2287
        pager_open(arg_pager_flags);
1✔
2288

2289
        switch (mode) {
1✔
2290

2291
        case STATUS_DNS:
×
2292
                return status_print_strv_delegate(id, delegate_info.dns);
×
2293

2294
        case STATUS_DOMAIN:
×
2295
                return status_print_strv_delegate(id, delegate_info.domains);
×
2296

2297
        case STATUS_DEFAULT_ROUTE:
×
2298
                printf("%sDelegate %s%s: %s\n",
×
2299
                       ansi_highlight(), id, ansi_normal(),
2300
                       yes_no(delegate_info.default_route));
×
2301

2302
                return 0;
2303

2304
        case STATUS_ALL:
2305
                break;
1✔
2306

2307
        default:
2308
                return 0;
2309
        }
2310

2311
        if (empty_line && *empty_line)
1✔
2312
                fputc('\n', stdout);
1✔
2313

2314
        printf("%sDelegate %s%s\n",
2✔
2315
               ansi_highlight(), id, ansi_normal());
2316

2317
        _cleanup_(table_unrefp) Table *table = table_new_vertical();
2✔
2318
        if (!table)
1✔
2319
                return log_oom();
×
2320

2321
        if (delegate_info.current_dns) {
1✔
2322
                r = table_add_many(table,
×
2323
                                   TABLE_FIELD, "Current DNS Server",
2324
                                   TABLE_STRING, delegate_info.current_dns);
2325
                if (r < 0)
×
2326
                        return table_log_add_error(r);
×
2327
        }
2328

2329
        r = dump_list(table, "DNS Servers", delegate_info.dns);
1✔
2330
        if (r < 0)
1✔
2331
                return r;
2332

2333
        r = dump_list(table, "DNS Domain", delegate_info.domains);
1✔
2334
        if (r < 0)
1✔
2335
                return r;
2336

2337
        r = table_add_many(table,
1✔
2338
                           TABLE_FIELD, "Default Route",
2339
                           TABLE_SET_MINIMUM_WIDTH, 19,
2340
                           TABLE_BOOLEAN, delegate_info.default_route);
2341

2342
        r = table_print(table, NULL);
1✔
2343
        if (r < 0)
1✔
2344
                return table_log_print_error(r);
×
2345

2346
        if (empty_line)
1✔
2347
                *empty_line = true;
1✔
2348

2349
        return 0;
2350
}
2351

2352
static int status_delegates(sd_bus *bus, StatusMode mode, bool *empty_line) {
7✔
2353
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
7✔
2354
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
7✔
2355
        int r, ret = 0;
7✔
2356

2357
        assert(bus);
7✔
2358

2359
        r = bus_call_method(bus, bus_resolve_mgr, "ListDelegates", &error, &reply, NULL);
7✔
2360
        if (r < 0) {
7✔
2361
                if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
×
2362
                        log_debug("Delegates not supported, skipping.");
×
2363
                        return 0;
×
2364
                }
2365
                return log_error_errno(r, "Failed to list delegates: %s", bus_error_message(&error, r));
×
2366
        }
2367

2368
        r = sd_bus_message_enter_container(reply, 'a', "(so)");
7✔
2369
        if (r < 0)
7✔
2370
                return bus_log_parse_error(r);
×
2371

2372
        _cleanup_strv_free_ char **l = NULL;
14✔
2373
        for (;;) {
1✔
2374
                const char *id;
8✔
2375

2376
                r = sd_bus_message_read(reply, "(so)", &id, NULL);
8✔
2377
                if (r < 0)
8✔
2378
                        return bus_log_parse_error(r);
×
2379
                if (r == 0)
8✔
2380
                        break;
2381

2382
                if (strv_extend(&l, id) < 0)
1✔
2383
                        return log_oom();
×
2384
        }
2385

2386
        r = sd_bus_message_exit_container(reply);
7✔
2387
        if (r < 0)
7✔
2388
                return bus_log_parse_error(r);
×
2389

2390
        strv_sort(l);
7✔
2391

2392
        STRV_FOREACH(i, l)
8✔
2393
                RET_GATHER(ret, status_delegate_one(bus, *i, mode, empty_line));
1✔
2394

2395
        return ret;
2396
}
2397

2398
static int status_all(sd_bus *bus, StatusMode mode) {
7✔
2399
        bool empty_line = false;
7✔
2400
        int r;
7✔
2401

2402
        assert(bus);
7✔
2403

2404
        r = status_global(bus, mode, &empty_line);
7✔
2405
        if (r < 0)
7✔
2406
                return r;
7✔
2407

2408
        r = status_links(bus, mode, &empty_line);
7✔
2409
        if (r < 0)
7✔
2410
                return r;
2411

2412
        r = status_delegates(bus, mode, &empty_line);
7✔
2413
        if (r < 0)
7✔
2414
                return r;
×
2415

2416
        return 0;
2417
}
2418

2419
static int verb_status(int argc, char **argv, void *userdata) {
5✔
2420
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
5✔
2421
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
5✔
2422
        bool empty_line = false;
5✔
2423
        int r, ret = 0;
5✔
2424

2425
        r = acquire_bus(&bus);
5✔
2426
        if (r < 0)
5✔
2427
                return r;
2428

2429
        if (argc <= 1)
5✔
2430
                return status_all(bus, STATUS_ALL);
5✔
2431

2432
        STRV_FOREACH(ifname, strv_skip(argv, 1)) {
×
2433
                int ifindex;
×
2434

2435
                ifindex = rtnl_resolve_interface(&rtnl, *ifname);
×
2436
                if (ifindex < 0) {
×
2437
                        log_warning_errno(ifindex, "Failed to resolve interface \"%s\", ignoring: %m", *ifname);
×
2438
                        continue;
×
2439
                }
2440

2441
                RET_GATHER(ret, status_ifindex(bus, ifindex, NULL, STATUS_ALL, &empty_line));
×
2442
        }
2443

2444
        return ret;
2445
}
2446

2447
static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) {
24✔
2448
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
24✔
2449
        int r;
24✔
2450

2451
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
24✔
2452

2453
        r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS");
24✔
2454
        if (r < 0)
24✔
2455
                return bus_log_create_error(r);
×
2456

2457
        r = sd_bus_message_append(req, "i", arg_ifindex);
24✔
2458
        if (r < 0)
24✔
2459
                return bus_log_create_error(r);
×
2460

2461
        r = sd_bus_message_open_container(req, 'a', extended ? "(iayqs)" : "(iay)");
24✔
2462
        if (r < 0)
24✔
2463
                return bus_log_create_error(r);
×
2464

2465
        /* If only argument is the empty string, then call SetLinkDNS() with an
2466
         * empty list, which will clear the list of domains for an interface. */
2467
        if (!strv_equal(dns, STRV_MAKE("")))
24✔
2468
                STRV_FOREACH(p, dns) {
58✔
2469
                        _cleanup_free_ char *name = NULL;
38✔
2470
                        struct in_addr_data data;
38✔
2471
                        uint16_t port;
38✔
2472
                        int ifindex;
38✔
2473

2474
                        r = in_addr_port_ifindex_name_from_string_auto(*p, &data.family, &data.address, &port, &ifindex, &name);
38✔
2475
                        if (r < 0)
38✔
2476
                                return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
×
2477

2478
                        if (ifindex != 0 && ifindex != arg_ifindex)
38✔
2479
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifindex: %i", ifindex);
×
2480

2481
                        r = sd_bus_message_open_container(req, 'r', extended ? "iayqs" : "iay");
38✔
2482
                        if (r < 0)
38✔
2483
                                return bus_log_create_error(r);
×
2484

2485
                        r = sd_bus_message_append(req, "i", data.family);
38✔
2486
                        if (r < 0)
38✔
2487
                                return bus_log_create_error(r);
×
2488

2489
                        r = sd_bus_message_append_array(req, 'y', &data.address, FAMILY_ADDRESS_SIZE(data.family));
38✔
2490
                        if (r < 0)
38✔
2491
                                return bus_log_create_error(r);
×
2492

2493
                        if (extended) {
38✔
2494
                                r = sd_bus_message_append(req, "q", port);
38✔
2495
                                if (r < 0)
38✔
2496
                                        return bus_log_create_error(r);
×
2497

2498
                                r = sd_bus_message_append(req, "s", name);
38✔
2499
                                if (r < 0)
38✔
2500
                                        return bus_log_create_error(r);
×
2501
                        }
2502

2503
                        r = sd_bus_message_close_container(req);
38✔
2504
                        if (r < 0)
38✔
2505
                                return bus_log_create_error(r);
×
2506
                }
2507

2508
        r = sd_bus_message_close_container(req);
24✔
2509
        if (r < 0)
24✔
2510
                return bus_log_create_error(r);
×
2511

2512
        r = sd_bus_call(bus, req, 0, error, NULL);
24✔
2513
        if (r < 0 && extended && sd_bus_error_has_name(error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
24✔
2514
                sd_bus_error_free(error);
×
2515
                return call_dns(bus, dns, locator, error, false);
×
2516
        }
2517
        return r;
2518
}
2519

2520
static int verb_dns(int argc, char **argv, void *userdata) {
44✔
2521
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
44✔
2522
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
44✔
2523
        int r;
44✔
2524

2525
        r = acquire_bus(&bus);
44✔
2526
        if (r < 0)
44✔
2527
                return r;
2528

2529
        if (argc >= 2) {
44✔
2530
                r = ifname_mangle(argv[1]);
42✔
2531
                if (r < 0)
42✔
2532
                        return r;
2533
        }
2534

2535
        if (arg_ifindex <= 0)
44✔
2536
                return status_all(bus, STATUS_DNS);
2✔
2537

2538
        if (argc < 3)
42✔
2539
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
23✔
2540

2541
        char **args = strv_skip(argv, 2);
19✔
2542
        r = call_dns(bus, args, bus_resolve_mgr, &error, true);
19✔
2543
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
19✔
2544
                sd_bus_error_free(&error);
5✔
2545

2546
                r = call_dns(bus, args, bus_network_mgr, &error, true);
5✔
2547
        }
2548
        if (r < 0) {
5✔
2549
                if (arg_ifindex_permissive &&
×
2550
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2551
                        return 0;
2552

2553
                return log_error_errno(r, "Failed to set DNS configuration: %s", bus_error_message(&error, r));
×
2554
        }
2555

2556
        return 0;
2557
}
2558

2559
static int call_domain(sd_bus *bus, char **domain, const BusLocator *locator, sd_bus_error *error) {
20✔
2560
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
20✔
2561
        int r;
20✔
2562

2563
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
20✔
2564

2565
        r = bus_message_new_method_call(bus, &req, locator, "SetLinkDomains");
20✔
2566
        if (r < 0)
20✔
2567
                return bus_log_create_error(r);
×
2568

2569
        r = sd_bus_message_append(req, "i", arg_ifindex);
20✔
2570
        if (r < 0)
20✔
2571
                return bus_log_create_error(r);
×
2572

2573
        r = sd_bus_message_open_container(req, 'a', "(sb)");
20✔
2574
        if (r < 0)
20✔
2575
                return bus_log_create_error(r);
×
2576

2577
        /* If only argument is the empty string, then call SetLinkDomains() with an
2578
         * empty list, which will clear the list of domains for an interface. */
2579
        if (!strv_equal(domain, STRV_MAKE("")))
20✔
2580
                STRV_FOREACH(p, domain) {
25✔
2581
                        const char *n;
15✔
2582

2583
                        n = **p == '~' ? *p + 1 : *p;
15✔
2584

2585
                        r = dns_name_is_valid(n);
15✔
2586
                        if (r < 0)
15✔
2587
                                return log_error_errno(r, "Failed to validate specified domain %s: %m", n);
×
2588
                        if (r == 0)
15✔
2589
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2590
                                                       "Domain not valid: %s",
2591
                                                       n);
2592

2593
                        r = sd_bus_message_append(req, "(sb)", n, **p == '~');
15✔
2594
                        if (r < 0)
15✔
2595
                                return bus_log_create_error(r);
×
2596
                }
2597

2598
        r = sd_bus_message_close_container(req);
20✔
2599
        if (r < 0)
20✔
2600
                return bus_log_create_error(r);
×
2601

2602
        return sd_bus_call(bus, req, 0, error, NULL);
20✔
2603
}
2604

2605
static int verb_domain(int argc, char **argv, void *userdata) {
46✔
2606
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
46✔
2607
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
46✔
2608
        int r;
46✔
2609

2610
        r = acquire_bus(&bus);
46✔
2611
        if (r < 0)
46✔
2612
                return r;
2613

2614
        if (argc >= 2) {
46✔
2615
                r = ifname_mangle(argv[1]);
46✔
2616
                if (r < 0)
46✔
2617
                        return r;
2618
        }
2619

2620
        if (arg_ifindex <= 0)
46✔
2621
                return status_all(bus, STATUS_DOMAIN);
×
2622

2623
        if (argc < 3)
46✔
2624
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL);
30✔
2625

2626
        char **args = strv_skip(argv, 2);
16✔
2627
        r = call_domain(bus, args, bus_resolve_mgr, &error);
16✔
2628
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
16✔
2629
                sd_bus_error_free(&error);
4✔
2630

2631
                r = call_domain(bus, args, bus_network_mgr, &error);
4✔
2632
        }
2633
        if (r < 0) {
4✔
2634
                if (arg_ifindex_permissive &&
×
2635
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2636
                        return 0;
2637

2638
                return log_error_errno(r, "Failed to set domain configuration: %s", bus_error_message(&error, r));
×
2639
        }
2640

2641
        return 0;
2642
}
2643

2644
static int verb_default_route(int argc, char **argv, void *userdata) {
4✔
2645
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
4✔
2646
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4✔
2647
        int r, b;
4✔
2648

2649
        r = acquire_bus(&bus);
4✔
2650
        if (r < 0)
4✔
2651
                return r;
2652

2653
        if (argc >= 2) {
4✔
2654
                r = ifname_mangle(argv[1]);
4✔
2655
                if (r < 0)
4✔
2656
                        return r;
2657
        }
2658

2659
        if (arg_ifindex <= 0)
4✔
2660
                return status_all(bus, STATUS_DEFAULT_ROUTE);
×
2661

2662
        if (argc < 3)
4✔
2663
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_DEFAULT_ROUTE, NULL);
2✔
2664

2665
        b = parse_boolean(argv[2]);
2✔
2666
        if (b < 0)
2✔
2667
                return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]);
×
2668

2669
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
2✔
2670

2671
        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
2✔
2672
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2✔
2673
                sd_bus_error_free(&error);
×
2674

2675
                r = bus_call_method(bus, bus_network_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
×
2676
        }
2677
        if (r < 0) {
×
2678
                if (arg_ifindex_permissive &&
×
2679
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2680
                        return 0;
2681

2682
                return log_error_errno(r, "Failed to set default route configuration: %s", bus_error_message(&error, r));
×
2683
        }
2684

2685
        return 0;
2686
}
2687

2688
static int verb_llmnr(int argc, char **argv, void *userdata) {
22✔
2689
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
22✔
2690
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2691
        _cleanup_free_ char *global_llmnr_support_str = NULL;
22✔
2692
        ResolveSupport global_llmnr_support, llmnr_support;
22✔
2693
        int r;
22✔
2694

2695
        r = acquire_bus(&bus);
22✔
2696
        if (r < 0)
22✔
2697
                return r;
2698

2699
        if (argc >= 2) {
22✔
2700
                r = ifname_mangle(argv[1]);
22✔
2701
                if (r < 0)
22✔
2702
                        return r;
2703
        }
2704

2705
        if (arg_ifindex <= 0)
22✔
2706
                return status_all(bus, STATUS_LLMNR);
×
2707

2708
        if (argc < 3)
22✔
2709
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL);
11✔
2710

2711
        llmnr_support = resolve_support_from_string(argv[2]);
11✔
2712
        if (llmnr_support < 0)
11✔
2713
                return log_error_errno(llmnr_support, "Invalid LLMNR setting: %s", argv[2]);
×
2714

2715
        r = bus_get_property_string(bus, bus_resolve_mgr, "LLMNR", &error, &global_llmnr_support_str);
11✔
2716
        if (r < 0)
11✔
2717
                return log_error_errno(r, "Failed to get the global LLMNR support state: %s", bus_error_message(&error, r));
×
2718

2719
        global_llmnr_support = resolve_support_from_string(global_llmnr_support_str);
11✔
2720
        if (global_llmnr_support < 0)
11✔
2721
                return log_error_errno(global_llmnr_support, "Received invalid global LLMNR setting: %s", global_llmnr_support_str);
×
2722

2723
        if (global_llmnr_support < llmnr_support)
11✔
2724
                log_warning("Setting LLMNR support level \"%s\" for \"%s\", but the global support level is \"%s\".",
3✔
2725
                            argv[2], arg_ifname, global_llmnr_support_str);
2726

2727
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
11✔
2728

2729
        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
11✔
2730
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
11✔
2731
                sd_bus_error_free(&error);
2✔
2732

2733
                r = bus_call_method(bus, bus_network_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
2✔
2734
        }
2735
        if (r < 0) {
2✔
2736
                if (arg_ifindex_permissive &&
×
2737
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2738
                        return 0;
2739

2740
                return log_error_errno(r, "Failed to set LLMNR configuration: %s", bus_error_message(&error, r));
×
2741
        }
2742

2743
        return 0;
2744
}
2745

2746
static int verb_mdns(int argc, char **argv, void *userdata) {
22✔
2747
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
22✔
2748
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2749
        _cleanup_free_ char *global_mdns_support_str = NULL;
22✔
2750
        ResolveSupport global_mdns_support, mdns_support;
22✔
2751
        int r;
22✔
2752

2753
        r = acquire_bus(&bus);
22✔
2754
        if (r < 0)
22✔
2755
                return r;
2756

2757
        if (argc >= 2) {
22✔
2758
                r = ifname_mangle(argv[1]);
22✔
2759
                if (r < 0)
22✔
2760
                        return r;
2761
        }
2762

2763
        if (arg_ifindex <= 0)
22✔
2764
                return status_all(bus, STATUS_MDNS);
×
2765

2766
        if (argc < 3)
22✔
2767
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL);
11✔
2768

2769
        mdns_support = resolve_support_from_string(argv[2]);
11✔
2770
        if (mdns_support < 0)
11✔
2771
                return log_error_errno(mdns_support, "Invalid mDNS setting: %s", argv[2]);
×
2772

2773
        r = bus_get_property_string(bus, bus_resolve_mgr, "MulticastDNS", &error, &global_mdns_support_str);
11✔
2774
        if (r < 0)
11✔
2775
                return log_error_errno(r, "Failed to get the global mDNS support state: %s", bus_error_message(&error, r));
×
2776

2777
        global_mdns_support = resolve_support_from_string(global_mdns_support_str);
11✔
2778
        if (global_mdns_support < 0)
11✔
2779
                return log_error_errno(global_mdns_support, "Received invalid global mDNS setting: %s", global_mdns_support_str);
×
2780

2781
        if (global_mdns_support < mdns_support)
11✔
2782
                log_warning("Setting mDNS support level \"%s\" for \"%s\", but the global support level is \"%s\".",
3✔
2783
                            argv[2], arg_ifname, global_mdns_support_str);
2784

2785
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
11✔
2786

2787
        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkMulticastDNS", &error, NULL, "is", arg_ifindex, argv[2]);
11✔
2788
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
11✔
2789
                sd_bus_error_free(&error);
2✔
2790

2791
                r = bus_call_method(
2✔
2792
                                bus,
2793
                                bus_network_mgr,
2794
                                "SetLinkMulticastDNS",
2795
                                &error,
2796
                                NULL,
2797
                                "is", arg_ifindex, argv[2]);
2798
        }
2799
        if (r < 0) {
2✔
2800
                if (arg_ifindex_permissive &&
×
2801
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2802
                        return 0;
2803

2804
                return log_error_errno(r, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error, r));
×
2805
        }
2806

2807
        return 0;
2808
}
2809

2810
static int verb_dns_over_tls(int argc, char **argv, void *userdata) {
×
2811
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
×
2812
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2813
        int r;
×
2814

2815
        r = acquire_bus(&bus);
×
2816
        if (r < 0)
×
2817
                return r;
2818

2819
        if (argc >= 2) {
×
2820
                r = ifname_mangle(argv[1]);
×
2821
                if (r < 0)
×
2822
                        return r;
2823
        }
2824

2825
        if (arg_ifindex <= 0)
×
2826
                return status_all(bus, STATUS_PRIVATE);
×
2827

2828
        if (argc < 3)
×
2829
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL);
×
2830

2831
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
×
2832

2833
        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSOverTLS", &error, NULL, "is", arg_ifindex, argv[2]);
×
2834
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
×
2835
                sd_bus_error_free(&error);
×
2836

2837
                r = bus_call_method(
×
2838
                                bus,
2839
                                bus_network_mgr,
2840
                                "SetLinkDNSOverTLS",
2841
                                &error,
2842
                                NULL,
2843
                                "is", arg_ifindex, argv[2]);
2844
        }
2845
        if (r < 0) {
×
2846
                if (arg_ifindex_permissive &&
×
2847
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2848
                        return 0;
2849

2850
                return log_error_errno(r, "Failed to set DNSOverTLS configuration: %s", bus_error_message(&error, r));
×
2851
        }
2852

2853
        return 0;
2854
}
2855

2856
static int verb_dnssec(int argc, char **argv, void *userdata) {
1✔
2857
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1✔
2858
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1✔
2859
        int r;
1✔
2860

2861
        r = acquire_bus(&bus);
1✔
2862
        if (r < 0)
1✔
2863
                return r;
2864

2865
        if (argc >= 2) {
1✔
2866
                r = ifname_mangle(argv[1]);
1✔
2867
                if (r < 0)
1✔
2868
                        return r;
2869
        }
2870

2871
        if (arg_ifindex <= 0)
1✔
2872
                return status_all(bus, STATUS_DNSSEC);
×
2873

2874
        if (argc < 3)
1✔
2875
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL);
×
2876

2877
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
1✔
2878

2879
        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
1✔
2880
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
1✔
2881
                sd_bus_error_free(&error);
1✔
2882

2883
                r = bus_call_method(bus, bus_network_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
1✔
2884
        }
2885
        if (r < 0) {
1✔
2886
                if (arg_ifindex_permissive &&
×
2887
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2888
                        return 0;
2889

2890
                return log_error_errno(r, "Failed to set DNSSEC configuration: %s", bus_error_message(&error, r));
×
2891
        }
2892

2893
        return 0;
2894
}
2895

2896
static int call_nta(sd_bus *bus, char **nta, const BusLocator *locator,  sd_bus_error *error) {
×
2897
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
×
2898
        int r;
×
2899

2900
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
×
2901

2902
        r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNSSECNegativeTrustAnchors");
×
2903
        if (r < 0)
×
2904
                return bus_log_create_error(r);
×
2905

2906
        r = sd_bus_message_append(req, "i", arg_ifindex);
×
2907
        if (r < 0)
×
2908
                return bus_log_create_error(r);
×
2909

2910
        r = sd_bus_message_append_strv(req, nta);
×
2911
        if (r < 0)
×
2912
                return bus_log_create_error(r);
×
2913

2914
        return sd_bus_call(bus, req, 0, error, NULL);
×
2915
}
2916

2917
static int verb_nta(int argc, char **argv, void *userdata) {
×
2918
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
×
2919
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2920
        char **args;
×
2921
        bool clear;
×
2922
        int r;
×
2923

2924
        r = acquire_bus(&bus);
×
2925
        if (r < 0)
×
2926
                return r;
2927

2928
        if (argc >= 2) {
×
2929
                r = ifname_mangle(argv[1]);
×
2930
                if (r < 0)
×
2931
                        return r;
2932
        }
2933

2934
        if (arg_ifindex <= 0)
×
2935
                return status_all(bus, STATUS_NTA);
×
2936

2937
        if (argc < 3)
×
2938
                return status_ifindex(bus, arg_ifindex, NULL, STATUS_NTA, NULL);
×
2939

2940
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
×
2941

2942
        /* If only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors()
2943
         * with an empty list, which will clear the list of domains for an interface. */
2944
        args = strv_skip(argv, 2);
×
2945
        clear = strv_equal(args, STRV_MAKE(""));
×
2946

2947
        if (!clear)
×
2948
                STRV_FOREACH(p, args) {
×
2949
                        r = dns_name_is_valid(*p);
×
2950
                        if (r < 0)
×
2951
                                return log_error_errno(r, "Failed to validate specified domain %s: %m", *p);
×
2952
                        if (r == 0)
×
2953
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2954
                                                       "Domain not valid: %s",
2955
                                                       *p);
2956
                }
2957

2958
        r = call_nta(bus, clear ? NULL : args, bus_resolve_mgr, &error);
×
2959
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
×
2960
                sd_bus_error_free(&error);
×
2961

2962
                r = call_nta(bus, clear ? NULL : args, bus_network_mgr, &error);
×
2963
        }
2964
        if (r < 0) {
×
2965
                if (arg_ifindex_permissive &&
×
2966
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
2967
                        return 0;
2968

2969
                return log_error_errno(r, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error, r));
×
2970
        }
2971

2972
        return 0;
2973
}
2974

2975
static int verb_revert_link(int argc, char **argv, void *userdata) {
17✔
2976
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
17✔
2977
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
17✔
2978
        int r;
17✔
2979

2980
        r = acquire_bus(&bus);
17✔
2981
        if (r < 0)
17✔
2982
                return r;
2983

2984
        if (argc >= 2) {
17✔
2985
                r = ifname_mangle(argv[1]);
17✔
2986
                if (r < 0)
17✔
2987
                        return r;
2988
        }
2989

2990
        if (arg_ifindex <= 0)
17✔
2991
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Interface argument required.");
×
2992

2993
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
17✔
2994

2995
        r = bus_call_method(bus, bus_resolve_mgr, "RevertLink", &error, NULL, "i", arg_ifindex);
17✔
2996
        if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
17✔
2997
                sd_bus_error_free(&error);
16✔
2998

2999
                r = bus_call_method(bus, bus_network_mgr, "RevertLinkDNS", &error, NULL, "i", arg_ifindex);
16✔
3000
        }
3001
        if (r < 0) {
16✔
3002
                if (arg_ifindex_permissive &&
×
3003
                    sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
×
3004
                        return 0;
3005

3006
                return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
×
3007
        }
3008

3009
        return 0;
3010
}
3011

3012
static int verb_log_level(int argc, char *argv[], void *userdata) {
1✔
3013
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1✔
3014
        int r;
1✔
3015

3016
        r = acquire_bus(&bus);
1✔
3017
        if (r < 0)
1✔
3018
                return r;
3019

3020
        assert(IN_SET(argc, 1, 2));
1✔
3021

3022
        return verb_log_control_common(bus, "org.freedesktop.resolve1", argv[0], argc == 2 ? argv[1] : NULL);
1✔
3023
}
3024

3025
static int print_question(char prefix, const char *color, sd_json_variant *question) {
270✔
3026
        sd_json_variant *q = NULL;
270✔
3027
        int r;
270✔
3028

3029
        assert(color);
270✔
3030

3031
        JSON_VARIANT_ARRAY_FOREACH(q, question) {
470✔
3032
                _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
200✔
3033
                char buf[DNS_RESOURCE_KEY_STRING_MAX];
200✔
3034

3035
                r = dns_resource_key_from_json(q, &key);
200✔
3036
                if (r < 0) {
200✔
3037
                        log_warning_errno(r, "Received monitor message with invalid question key, ignoring: %m");
×
3038
                        continue;
×
3039
                }
3040

3041
                printf("%s%s %c%s: %s\n",
400✔
3042
                       color,
3043
                       glyph(GLYPH_ARROW_RIGHT),
3044
                       prefix,
3045
                       ansi_normal(),
3046
                       dns_resource_key_to_string(key, buf, sizeof(buf)));
3047
        }
3048

3049
        return 0;
270✔
3050
}
3051

3052
static int print_answer(sd_json_variant *answer) {
135✔
3053
        sd_json_variant *a;
135✔
3054
        int r;
135✔
3055

3056
        JSON_VARIANT_ARRAY_FOREACH(a, answer) {
382✔
3057
                _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
×
3058
                _cleanup_free_ void *d = NULL;
247✔
3059
                sd_json_variant *jraw;
247✔
3060
                const char *s;
247✔
3061
                size_t l;
247✔
3062

3063
                jraw = sd_json_variant_by_key(a, "raw");
247✔
3064
                if (!jraw) {
247✔
3065
                        log_warning("Received monitor answer lacking valid raw data, ignoring.");
×
3066
                        continue;
×
3067
                }
3068

3069
                r = sd_json_variant_unbase64(jraw, &d, &l);
247✔
3070
                if (r < 0) {
247✔
3071
                        log_warning_errno(r, "Failed to undo base64 encoding of monitor answer raw data, ignoring.");
×
3072
                        continue;
×
3073
                }
3074

3075
                r = dns_resource_record_new_from_raw(&rr, d, l);
247✔
3076
                if (r < 0) {
247✔
3077
                        log_warning_errno(r, "Failed to parse monitor answer RR, ignoring: %m");
×
3078
                        continue;
×
3079
                }
3080

3081
                s = dns_resource_record_to_string(rr);
247✔
3082
                if (!s)
247✔
3083
                        return log_oom();
×
3084

3085
                printf("%s%s A%s: %s\n",
494✔
3086
                       ansi_highlight_yellow(),
3087
                       glyph(GLYPH_ARROW_LEFT),
3088
                       ansi_normal(),
3089
                       s);
3090
        }
3091

3092
        return 0;
135✔
3093
}
3094

3095
typedef struct MonitorQueryParams {
3096
        sd_json_variant *question;
3097
        sd_json_variant *answer;
3098
        sd_json_variant *collected_questions;
3099
        int rcode;
3100
        int error;
3101
        int ede_code;
3102
        const char *state;
3103
        const char *result;
3104
        const char *ede_msg;
3105
} MonitorQueryParams;
3106

3107
static void monitor_query_params_done(MonitorQueryParams *p) {
135✔
3108
        assert(p);
135✔
3109

3110
        sd_json_variant_unref(p->question);
135✔
3111
        sd_json_variant_unref(p->answer);
135✔
3112
        sd_json_variant_unref(p->collected_questions);
135✔
3113
}
135✔
3114

3115
static void monitor_query_dump(sd_json_variant *v) {
135✔
3116
        static const sd_json_dispatch_field dispatch_table[] = {
135✔
3117
                { "question",                SD_JSON_VARIANT_ARRAY,         sd_json_dispatch_variant,      offsetof(MonitorQueryParams, question),            SD_JSON_MANDATORY },
3118
                { "answer",                  SD_JSON_VARIANT_ARRAY,         sd_json_dispatch_variant,      offsetof(MonitorQueryParams, answer),              0                 },
3119
                { "collectedQuestions",      SD_JSON_VARIANT_ARRAY,         sd_json_dispatch_variant,      offsetof(MonitorQueryParams, collected_questions), 0                 },
3120
                { "state",                   SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MonitorQueryParams, state),               SD_JSON_MANDATORY },
3121
                { "result",                  SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MonitorQueryParams, result),              0                 },
3122
                { "rcode",                   _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int,          offsetof(MonitorQueryParams, rcode),               0                 },
3123
                { "errno",                   _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int,          offsetof(MonitorQueryParams, error),               0                 },
3124
                { "extendedDNSErrorCode",    _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int,          offsetof(MonitorQueryParams, ede_code),            0                 },
3125
                { "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MonitorQueryParams, ede_msg),             0                 },
3126
                {}
3127
        };
3128

3129
        _cleanup_(monitor_query_params_done) MonitorQueryParams p = {
135✔
3130
                .rcode = -1,
3131
                .ede_code = -1,
3132
        };
3133

3134
        assert(v);
135✔
3135

3136
        if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &p) < 0)
135✔
3137
                return;
×
3138

3139
        /* First show the current question */
3140
        print_question('Q', ansi_highlight_cyan(), p.question);
270✔
3141

3142
        /* And then show the questions that led to this one in case this was a CNAME chain */
3143
        print_question('C', ansi_highlight_grey(), p.collected_questions);
135✔
3144

3145
        printf("%s%s S%s: %s",
270✔
3146
               streq_ptr(p.state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
135✔
3147
               glyph(GLYPH_ARROW_LEFT),
3148
               ansi_normal(),
3149
               streq_ptr(p.state, "errno") ? ERRNO_NAME(p.error) :
135✔
3150
               streq_ptr(p.state, "rcode-failure") ? strna(dns_rcode_to_string(p.rcode)) :
135✔
3151
               strna(p.state));
135✔
3152

3153
        if (!isempty(p.result))
135✔
3154
                printf(": %s", p.result);
3✔
3155

3156
        if (p.ede_code >= 0)
135✔
3157
                printf(" (%s%s%s)",
10✔
3158
                       FORMAT_DNS_EDE_RCODE(p.ede_code),
10✔
3159
                       !isempty(p.ede_msg) ? ": " : "",
16✔
3160
                       strempty(p.ede_msg));
10✔
3161

3162
        puts("");
135✔
3163

3164
        print_answer(p.answer);
135✔
3165
}
3166

3167
static int monitor_reply(
272✔
3168
                sd_varlink *link,
3169
                sd_json_variant *parameters,
3170
                const char *error_id,
3171
                sd_varlink_reply_flags_t flags,
3172
                void *userdata) {
3173

3174
        assert(link);
272✔
3175

3176
        if (error_id) {
272✔
3177
                bool disconnect;
×
3178

3179
                disconnect = streq(error_id, SD_VARLINK_ERROR_DISCONNECTED);
×
3180
                if (disconnect)
×
3181
                        log_info("Disconnected.");
×
3182
                else
3183
                        log_error("Varlink error: %s", error_id);
×
3184

3185
                (void) sd_event_exit(ASSERT_PTR(sd_varlink_get_event(link)), disconnect ? EXIT_SUCCESS : EXIT_FAILURE);
×
3186
                return 0;
×
3187
        }
3188

3189
        if (sd_json_variant_by_key(parameters, "ready")) {
272✔
3190
                /* The first message coming in will just indicate that we are now subscribed. We let our
3191
                 * caller know if they asked for it. Once the caller sees this they should know that we are
3192
                 * not going to miss any queries anymore. */
3193
                (void) sd_notify(/* unset_environment=false */ false, "READY=1");
2✔
3194
                return 0;
2✔
3195
        }
3196

3197
        if (!sd_json_format_enabled(arg_json_format_flags)) {
270✔
3198
                monitor_query_dump(parameters);
135✔
3199
                printf("\n");
135✔
3200
        } else
3201
                sd_json_variant_dump(parameters, arg_json_format_flags, NULL, NULL);
135✔
3202

3203
        fflush(stdout);
270✔
3204

3205
        return 0;
270✔
3206
}
3207

3208
static int verb_monitor(int argc, char *argv[], void *userdata) {
2✔
3209
        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
2✔
3210
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
2✔
3211
        int r, c;
2✔
3212

3213
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
2✔
3214

3215
        r = sd_event_default(&event);
2✔
3216
        if (r < 0)
2✔
3217
                return log_error_errno(r, "Failed to get event loop: %m");
×
3218

3219
        r = sd_event_set_signal_exit(event, true);
2✔
3220
        if (r < 0)
2✔
3221
                return log_error_errno(r, "Failed to enable exit on SIGINT/SIGTERM: %m");
×
3222

3223
        r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
2✔
3224
        if (r < 0)
2✔
3225
                return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
×
3226

3227
        r = sd_varlink_set_relative_timeout(vl, USEC_INFINITY); /* We want the monitor to run basically forever */
2✔
3228
        if (r < 0)
2✔
3229
                return log_error_errno(r, "Failed to set varlink timeout: %m");
×
3230

3231
        r = sd_varlink_attach_event(vl, event, SD_EVENT_PRIORITY_NORMAL);
2✔
3232
        if (r < 0)
2✔
3233
                return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
×
3234

3235
        r = sd_varlink_bind_reply(vl, monitor_reply);
2✔
3236
        if (r < 0)
2✔
3237
                return log_error_errno(r, "Failed to bind reply callback to varlink connection: %m");
×
3238

3239
        r = sd_varlink_observebo(
2✔
3240
                        vl,
3241
                        "io.systemd.Resolve.Monitor.SubscribeQueryResults",
3242
                        SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
3243
        if (r < 0)
2✔
3244
                return log_error_errno(r, "Failed to issue SubscribeQueryResults() varlink call: %m");
×
3245

3246
        r = sd_event_loop(event);
2✔
3247
        if (r < 0)
2✔
3248
                return log_error_errno(r, "Failed to run event loop: %m");
×
3249

3250
        r = sd_event_get_exit_code(event, &c);
2✔
3251
        if (r < 0)
2✔
3252
                return log_error_errno(r, "Failed to get exit code: %m");
×
3253

3254
        return c;
2✔
3255
}
3256

3257
static int dump_cache_item(sd_json_variant *item) {
23✔
3258

3259
        struct item_info {
23✔
3260
                sd_json_variant *key;
3261
                sd_json_variant *rrs;
3262
                const char *type;
3263
                uint64_t until;
3264
        } item_info = {};
23✔
3265

3266
        static const sd_json_dispatch_field dispatch_table[] = {
23✔
3267
                { "key",   SD_JSON_VARIANT_OBJECT,        sd_json_dispatch_variant_noref, offsetof(struct item_info, key),   SD_JSON_MANDATORY },
3268
                { "rrs",   SD_JSON_VARIANT_ARRAY,         sd_json_dispatch_variant_noref, offsetof(struct item_info, rrs),   0                 },
3269
                { "type",  SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct item_info, type),  0                 },
3270
                { "until", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,        offsetof(struct item_info, until), 0                 },
3271
                {},
3272
        };
3273

3274
        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
23✔
3275
        int r, c = 0;
23✔
3276

3277
        r = sd_json_dispatch(item, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &item_info);
23✔
3278
        if (r < 0)
23✔
3279
                return r;
3280

3281
        r = dns_resource_key_from_json(item_info.key, &k);
23✔
3282
        if (r < 0)
23✔
3283
                return log_error_errno(r, "Failed to turn JSON data to resource key: %m");
×
3284

3285
        if (item_info.type)
23✔
3286
                printf("%s %s%s%s\n", DNS_RESOURCE_KEY_TO_STRING(k), ansi_highlight_red(), item_info.type, ansi_normal());
27✔
3287
        else {
3288
                sd_json_variant *i;
14✔
3289

3290
                JSON_VARIANT_ARRAY_FOREACH(i, item_info.rrs) {
29✔
3291
                        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
×
3292
                        _cleanup_free_ void *data = NULL;
15✔
3293
                        sd_json_variant *raw;
15✔
3294
                        size_t size;
15✔
3295

3296
                        raw = sd_json_variant_by_key(i, "raw");
15✔
3297
                        if (!raw)
15✔
3298
                                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "raw field missing from RR JSON data.");
×
3299

3300
                        r = sd_json_variant_unbase64(raw, &data, &size);
15✔
3301
                        if (r < 0)
15✔
3302
                                return log_error_errno(r, "Unable to decode raw RR JSON data: %m");
×
3303

3304
                        r = dns_resource_record_new_from_raw(&rr, data, size);
15✔
3305
                        if (r < 0)
15✔
3306
                                return log_error_errno(r, "Failed to parse DNS data: %m");
×
3307

3308
                        printf("%s\n", dns_resource_record_to_string(rr));
15✔
3309
                        c++;
15✔
3310
                }
3311
        }
3312

3313
        return c;
3314
}
3315

3316
static int dump_cache_scope(sd_json_variant *scope) {
2✔
3317

3318
        struct scope_info {
2✔
3319
                const char *protocol;
3320
                int family;
3321
                int ifindex;
3322
                const char *ifname;
3323
                sd_json_variant *cache;
3324
                const char *dnssec_mode;
3325
                const char *dns_over_tls_mode;
3326
        } scope_info = {
2✔
3327
                .family = AF_UNSPEC,
3328
        };
3329
        sd_json_variant *i;
2✔
3330
        int r, c = 0;
2✔
3331

3332
        static const sd_json_dispatch_field dispatch_table[] = {
2✔
3333
                { "protocol",     SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct scope_info, protocol),          SD_JSON_MANDATORY },
3334
                { "family",       _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int,           offsetof(struct scope_info, family),            0                 },
3335
                { "ifindex",      _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex,          offsetof(struct scope_info, ifindex),           SD_JSON_RELAX     },
3336
                { "ifname",       SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct scope_info, ifname),            0                 },
3337
                { "cache",        SD_JSON_VARIANT_ARRAY,         sd_json_dispatch_variant_noref, offsetof(struct scope_info, cache),             SD_JSON_MANDATORY },
3338
                { "dnssec",       SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct scope_info, dnssec_mode),       0                 },
3339
                { "dnsOverTLS",   SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct scope_info, dns_over_tls_mode), 0                 },
3340
                {},
3341
        };
3342

3343
        r = sd_json_dispatch(scope, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &scope_info);
2✔
3344
        if (r < 0)
2✔
3345
                return r;
2✔
3346

3347
        printf("%sScope protocol=%s", ansi_underline(), scope_info.protocol);
4✔
3348

3349
        if (scope_info.family != AF_UNSPEC)
2✔
3350
                printf(" family=%s", af_to_name(scope_info.family));
×
3351

3352
        if (scope_info.ifindex > 0)
2✔
3353
                printf(" ifindex=%i", scope_info.ifindex);
1✔
3354
        if (scope_info.ifname)
2✔
3355
                printf(" ifname=%s", scope_info.ifname);
1✔
3356

3357
        if (dns_protocol_from_string(scope_info.protocol) == DNS_PROTOCOL_DNS) {
2✔
3358
                if (scope_info.dnssec_mode)
2✔
3359
                        printf(" DNSSEC=%s", scope_info.dnssec_mode);
2✔
3360
                if (scope_info.dns_over_tls_mode)
2✔
3361
                        printf(" DNSOverTLS=%s", scope_info.dns_over_tls_mode);
2✔
3362
        }
3363

3364
        printf("%s\n", ansi_normal());
4✔
3365

3366
        JSON_VARIANT_ARRAY_FOREACH(i, scope_info.cache) {
25✔
3367
                r = dump_cache_item(i);
23✔
3368
                if (r < 0)
23✔
3369
                        return r;
×
3370

3371
                c += r;
23✔
3372
        }
3373

3374
        if (c == 0)
2✔
3375
                printf("%sNo entries.%s\n\n", ansi_grey(), ansi_normal());
2✔
3376
        else
3377
                printf("\n");
1✔
3378

3379
        return 0;
3380
}
3381

3382
static int verb_show_cache(int argc, char *argv[], void *userdata) {
7✔
3383
        sd_json_variant *reply = NULL, *d = NULL;
7✔
3384
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
7✔
3385
        int r;
7✔
3386

3387
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
7✔
3388

3389
        r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
7✔
3390
        if (r < 0)
7✔
3391
                return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
×
3392

3393
        r = varlink_callbo_and_log(
7✔
3394
                        vl,
3395
                        "io.systemd.Resolve.Monitor.DumpCache",
3396
                        &reply,
3397
                        SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
3398
        if (r < 0)
7✔
3399
                return r;
3400

3401
        d = sd_json_variant_by_key(reply, "dump");
7✔
3402
        if (!d)
7✔
3403
                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
×
3404
                                       "DumpCache() response is missing 'dump' key.");
3405

3406
        if (!sd_json_variant_is_array(d))
7✔
3407
                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
×
3408
                                       "DumpCache() response 'dump' field not an array");
3409

3410
        if (!sd_json_format_enabled(arg_json_format_flags)) {
7✔
3411
                sd_json_variant *i;
1✔
3412

3413
                JSON_VARIANT_ARRAY_FOREACH(i, d) {
3✔
3414
                        r = dump_cache_scope(i);
2✔
3415
                        if (r < 0)
2✔
3416
                                return r;
×
3417
                }
3418

3419
                return 0;
1✔
3420
        }
3421

3422
        return sd_json_variant_dump(d, arg_json_format_flags, NULL, NULL);
6✔
3423
}
3424

3425
static int dump_server_state(sd_json_variant *server) {
2✔
3426
        _cleanup_(table_unrefp) Table *table = NULL;
2✔
3427
        TableCell *cell;
2✔
3428

3429
        struct server_state {
2✔
3430
                const char *server_name;
3431
                const char *type;
3432
                const char *ifname;
3433
                int ifindex;
3434
                const char *verified_feature_level;
3435
                const char *possible_feature_level;
3436
                const char *dnssec_mode;
3437
                bool dnssec_supported;
3438
                size_t received_udp_fragment_max;
3439
                uint64_t n_failed_udp;
3440
                uint64_t n_failed_tcp;
3441
                bool packet_truncated;
3442
                bool packet_bad_opt;
3443
                bool packet_rrsig_missing;
3444
                bool packet_invalid;
3445
                bool packet_do_off;
3446
        } server_state = {
2✔
3447
                .ifindex = -1,
3448
        };
3449

3450
        int r;
2✔
3451

3452
        static const sd_json_dispatch_field dispatch_table[] = {
2✔
3453
                { "Server",                 SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct server_state, server_name),               SD_JSON_MANDATORY },
3454
                { "Type",                   SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct server_state, type),                      SD_JSON_MANDATORY },
3455
                { "Interface",              SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct server_state, ifname),                    0                 },
3456
                { "InterfaceIndex",         _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex,          offsetof(struct server_state, ifindex),                   SD_JSON_RELAX     },
3457
                { "VerifiedFeatureLevel",   SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct server_state, verified_feature_level),    0                 },
3458
                { "PossibleFeatureLevel",   SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct server_state, possible_feature_level),    0                 },
3459
                { "DNSSECMode",             SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string,  offsetof(struct server_state, dnssec_mode),               SD_JSON_MANDATORY },
3460
                { "DNSSECSupported",        SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool,       offsetof(struct server_state, dnssec_supported),          SD_JSON_MANDATORY },
3461
                { "ReceivedUDPFragmentMax", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,        offsetof(struct server_state, received_udp_fragment_max), SD_JSON_MANDATORY },
3462
                { "FailedUDPAttempts",      _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,        offsetof(struct server_state, n_failed_udp),              SD_JSON_MANDATORY },
3463
                { "FailedTCPAttempts",      _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,        offsetof(struct server_state, n_failed_tcp),              SD_JSON_MANDATORY },
3464
                { "PacketTruncated",        SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool,       offsetof(struct server_state, packet_truncated),          SD_JSON_MANDATORY },
3465
                { "PacketBadOpt",           SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool,       offsetof(struct server_state, packet_bad_opt),            SD_JSON_MANDATORY },
3466
                { "PacketRRSIGMissing",     SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool,       offsetof(struct server_state, packet_rrsig_missing),      SD_JSON_MANDATORY },
3467
                { "PacketInvalid",          SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool,       offsetof(struct server_state, packet_invalid),            SD_JSON_MANDATORY },
3468
                { "PacketDoOff",            SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_stdbool,       offsetof(struct server_state, packet_do_off),             SD_JSON_MANDATORY },
3469
                {},
3470
        };
3471

3472
        r = sd_json_dispatch(server, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &server_state);
2✔
3473
        if (r < 0)
2✔
3474
                return r;
3475

3476
        table = table_new_vertical();
2✔
3477
        if (!table)
2✔
3478
                return log_oom();
×
3479

3480
        assert_se(cell = table_get_cell(table, 0, 0));
2✔
3481
        (void) table_set_ellipsize_percent(table, cell, 100);
2✔
3482
        (void) table_set_align_percent(table, cell, 0);
2✔
3483

3484
        r = table_add_cell_stringf(table, NULL, "Server: %s", server_state.server_name);
2✔
3485
        if (r < 0)
2✔
3486
                return table_log_add_error(r);
×
3487

3488
        r = table_add_many(table,
2✔
3489
                           TABLE_EMPTY,
3490
                           TABLE_FIELD, "Type",
3491
                           TABLE_SET_ALIGN_PERCENT, 100,
3492
                           TABLE_STRING, server_state.type);
3493
        if (r < 0)
2✔
3494
                return table_log_add_error(r);
×
3495

3496
        if (server_state.ifname) {
2✔
3497
                r = table_add_many(table,
2✔
3498
                                   TABLE_FIELD, "Interface",
3499
                                   TABLE_STRING, server_state.ifname);
3500
                if (r < 0)
2✔
3501
                        return table_log_add_error(r);
×
3502
        }
3503

3504
        if (server_state.ifindex >= 0) {
2✔
3505
                r = table_add_many(table,
2✔
3506
                                   TABLE_FIELD, "Interface Index",
3507
                                   TABLE_INT, server_state.ifindex);
3508
                if (r < 0)
2✔
3509
                        return table_log_add_error(r);
×
3510
        }
3511

3512
        if (server_state.verified_feature_level) {
2✔
3513
                r = table_add_many(table,
2✔
3514
                                   TABLE_FIELD, "Verified feature level",
3515
                                   TABLE_STRING, server_state.verified_feature_level);
3516
                if (r < 0)
2✔
3517
                        return table_log_add_error(r);
×
3518
        }
3519

3520
        if (server_state.possible_feature_level) {
2✔
3521
                r = table_add_many(table,
2✔
3522
                                   TABLE_FIELD, "Possible feature level",
3523
                                   TABLE_STRING, server_state.possible_feature_level);
3524
                if (r < 0)
2✔
3525
                        return table_log_add_error(r);
×
3526
        }
3527

3528
        r = table_add_many(table,
12✔
3529
                           TABLE_FIELD, "DNSSEC Mode",
3530
                           TABLE_STRING, server_state.dnssec_mode,
3531
                           TABLE_FIELD, "DNSSEC Supported",
3532
                           TABLE_STRING, yes_no(server_state.dnssec_supported),
3533
                           TABLE_FIELD, "Maximum UDP fragment size received",
3534
                           TABLE_UINT64, server_state.received_udp_fragment_max,
3535
                           TABLE_FIELD, "Failed UDP attempts",
3536
                           TABLE_UINT64, server_state.n_failed_udp,
3537
                           TABLE_FIELD, "Failed TCP attempts",
3538
                           TABLE_UINT64, server_state.n_failed_tcp,
3539
                           TABLE_FIELD, "Seen truncated packet",
3540
                           TABLE_STRING, yes_no(server_state.packet_truncated),
3541
                           TABLE_FIELD, "Seen OPT RR getting lost",
3542
                           TABLE_STRING, yes_no(server_state.packet_bad_opt),
3543
                           TABLE_FIELD, "Seen RRSIG RR missing",
3544
                           TABLE_STRING, yes_no(server_state.packet_rrsig_missing),
3545
                           TABLE_FIELD, "Seen invalid packet",
3546
                           TABLE_STRING, yes_no(server_state.packet_invalid),
3547
                           TABLE_FIELD, "Server dropped DO flag",
3548
                           TABLE_STRING, yes_no(server_state.packet_do_off),
3549
                           TABLE_SET_ALIGN_PERCENT, 0,
3550
                           TABLE_EMPTY, TABLE_EMPTY);
3551

3552
        if (r < 0)
2✔
3553
                return table_log_add_error(r);
×
3554

3555
        r = table_print(table, NULL);
2✔
3556
        if (r < 0)
2✔
3557
                return table_log_print_error(r);
×
3558

3559
        return 0;
3560
}
3561

3562
static int verb_show_server_state(int argc, char *argv[], void *userdata) {
3✔
3563
        sd_json_variant *reply = NULL, *d = NULL;
3✔
3564
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
3✔
3565
        int r;
3✔
3566

3567
        (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
3✔
3568

3569
        r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3✔
3570
        if (r < 0)
3✔
3571
                return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
×
3572

3573
        r = varlink_callbo_and_log(
3✔
3574
                        vl,
3575
                        "io.systemd.Resolve.Monitor.DumpServerState",
3576
                        &reply,
3577
                        SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
3578
        if (r < 0)
3✔
3579
                return r;
3580

3581
        d = sd_json_variant_by_key(reply, "dump");
3✔
3582
        if (!d)
3✔
3583
                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
×
3584
                                       "DumpCache() response is missing 'dump' key.");
3585

3586
        if (!sd_json_variant_is_array(d))
3✔
3587
                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
×
3588
                                       "DumpCache() response 'dump' field not an array");
3589

3590
        if (!sd_json_format_enabled(arg_json_format_flags)) {
3✔
3591
                sd_json_variant *i;
1✔
3592

3593
                JSON_VARIANT_ARRAY_FOREACH(i, d) {
3✔
3594
                        r = dump_server_state(i);
2✔
3595
                        if (r < 0)
2✔
3596
                                return r;
×
3597
                }
3598

3599
                return 0;
1✔
3600
        }
3601

3602
        return sd_json_variant_dump(d, arg_json_format_flags, NULL, NULL);
2✔
3603
}
3604

3605
static void help_protocol_types(void) {
×
3606
        if (arg_legend)
×
3607
                puts("Known protocol types:");
×
3608
        puts("dns\n"
×
3609
             "llmnr\n"
3610
             "llmnr-ipv4\n"
3611
             "llmnr-ipv6\n"
3612
             "mdns\n"
3613
             "mdns-ipv4\n"
3614
             "mdns-ipv6");
3615
}
×
3616

3617
static void help_dns_types(void) {
×
3618
        if (arg_legend)
×
3619
                puts("Known DNS RR types:");
×
3620

3621
        DUMP_STRING_TABLE(dns_type, int, _DNS_TYPE_MAX);
×
3622
}
×
3623

3624
static void help_dns_classes(void) {
×
3625
        if (arg_legend)
×
3626
                puts("Known DNS RR classes:");
×
3627

3628
        DUMP_STRING_TABLE(dns_class, int, _DNS_CLASS_MAX);
×
3629
}
×
3630

3631
static int compat_help(void) {
×
3632
        _cleanup_free_ char *link = NULL;
×
3633
        int r;
×
3634

3635
        r = terminal_urlify_man("resolvectl", "1", &link);
×
3636
        if (r < 0)
×
3637
                return log_oom();
×
3638

3639
        pager_open(arg_pager_flags);
×
3640

3641
        printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
×
3642
               "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
3643
               "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
3644
               "%1$s [OPTIONS...] --statistics\n"
3645
               "%1$s [OPTIONS...] --reset-statistics\n"
3646
               "\n"
3647
               "%2$sResolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%3$s\n\n"
3648
               "  -h --help                 Show this help\n"
3649
               "     --version              Show package version\n"
3650
               "     --no-pager             Do not pipe output into a pager\n"
3651
               "  -4                        Resolve IPv4 addresses\n"
3652
               "  -6                        Resolve IPv6 addresses\n"
3653
               "  -i --interface=INTERFACE  Look on interface\n"
3654
               "  -p --protocol=PROTO|help  Look via protocol\n"
3655
               "  -t --type=TYPE|help       Query RR with DNS type\n"
3656
               "  -c --class=CLASS|help     Query RR with DNS class\n"
3657
               "     --service              Resolve service (SRV)\n"
3658
               "     --service-address=BOOL Resolve address for services (default: yes)\n"
3659
               "     --service-txt=BOOL     Resolve TXT records for services (default: yes)\n"
3660
               "     --openpgp              Query OpenPGP public key\n"
3661
               "     --tlsa                 Query TLS public key\n"
3662
               "     --cname=BOOL           Follow CNAME redirects (default: yes)\n"
3663
               "     --search=BOOL          Use search domains for single-label names\n"
3664
               "                                                              (default: yes)\n"
3665
               "     --raw[=payload|packet] Dump the answer as binary data\n"
3666
               "     --legend=BOOL          Print headers and additional info (default: yes)\n"
3667
               "     --statistics           Show resolver statistics\n"
3668
               "     --reset-statistics     Reset resolver statistics\n"
3669
               "     --status               Show link and server status\n"
3670
               "     --flush-caches         Flush all local DNS caches\n"
3671
               "     --reset-server-features\n"
3672
               "                            Forget learnt DNS server feature levels\n"
3673
               "     --set-dns=SERVER       Set per-interface DNS server address\n"
3674
               "     --set-domain=DOMAIN    Set per-interface search domain\n"
3675
               "     --set-llmnr=MODE       Set per-interface LLMNR mode\n"
3676
               "     --set-mdns=MODE        Set per-interface MulticastDNS mode\n"
3677
               "     --set-dnsovertls=MODE  Set per-interface DNS-over-TLS mode\n"
3678
               "     --set-dnssec=MODE      Set per-interface DNSSEC mode\n"
3679
               "     --set-nta=DOMAIN       Set per-interface DNSSEC NTA\n"
3680
               "     --revert               Revert per-interface configuration\n"
3681
               "\nSee the %4$s for details.\n",
3682
               program_invocation_short_name,
3683
               ansi_highlight(),
3684
               ansi_normal(),
3685
               link);
3686

3687
        return 0;
3688
}
3689

3690
static int native_help(void) {
×
3691
        _cleanup_free_ char *link = NULL;
×
3692
        int r;
×
3693

3694
        r = terminal_urlify_man("resolvectl", "1", &link);
×
3695
        if (r < 0)
×
3696
                return log_oom();
×
3697

3698
        pager_open(arg_pager_flags);
×
3699

3700
        printf("%1$s [OPTIONS...] COMMAND ...\n"
×
3701
               "\n"
3702
               "%5$sSend control commands to the network name resolution manager, or%6$s\n"
3703
               "%5$sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%6$s\n"
3704
               "\n%3$sCommands:%4$s\n"
3705
               "  query HOSTNAME|ADDRESS...    Resolve domain names, IPv4 and IPv6 addresses\n"
3706
               "  service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
3707
               "  openpgp EMAIL@DOMAIN...      Query OpenPGP public key\n"
3708
               "  tlsa DOMAIN[:PORT]...        Query TLS public key\n"
3709
               "  status [LINK...]             Show link and server status\n"
3710
               "  statistics                   Show resolver statistics\n"
3711
               "  reset-statistics             Reset resolver statistics\n"
3712
               "  flush-caches                 Flush all local DNS caches\n"
3713
               "  reset-server-features        Forget learnt DNS server feature levels\n"
3714
               "  monitor                      Monitor DNS queries\n"
3715
               "  show-cache                   Show cache contents\n"
3716
               "  show-server-state            Show servers state\n"
3717
               "  dns [LINK [SERVER...]]       Get/set per-interface DNS server address\n"
3718
               "  domain [LINK [DOMAIN...]]    Get/set per-interface search domain\n"
3719
               "  default-route [LINK [BOOL]]  Get/set per-interface default route flag\n"
3720
               "  llmnr [LINK [MODE]]          Get/set per-interface LLMNR mode\n"
3721
               "  mdns [LINK [MODE]]           Get/set per-interface MulticastDNS mode\n"
3722
               "  dnsovertls [LINK [MODE]]     Get/set per-interface DNS-over-TLS mode\n"
3723
               "  dnssec [LINK [MODE]]         Get/set per-interface DNSSEC mode\n"
3724
               "  nta [LINK [DOMAIN...]]       Get/set per-interface DNSSEC NTA\n"
3725
               "  revert LINK                  Revert per-interface configuration\n"
3726
               "  log-level [LEVEL]            Get/set logging threshold for systemd-resolved\n"
3727
               "\n%3$sOptions:%4$s\n"
3728
               "  -h --help                    Show this help\n"
3729
               "     --version                 Show package version\n"
3730
               "     --no-pager                Do not pipe output into a pager\n"
3731
               "     --no-ask-password         Do not prompt for password\n"
3732
               "  -4                           Resolve IPv4 addresses\n"
3733
               "  -6                           Resolve IPv6 addresses\n"
3734
               "  -i --interface=INTERFACE     Look on interface\n"
3735
               "  -p --protocol=PROTO|help     Look via protocol\n"
3736
               "  -t --type=TYPE|help          Query RR with DNS type\n"
3737
               "  -c --class=CLASS|help        Query RR with DNS class\n"
3738
               "     --service-address=BOOL    Resolve address for services (default: yes)\n"
3739
               "     --service-txt=BOOL        Resolve TXT records for services (default: yes)\n"
3740
               "     --cname=BOOL              Follow CNAME redirects (default: yes)\n"
3741
               "     --validate=BOOL           Allow DNSSEC validation (default: yes)\n"
3742
               "     --synthesize=BOOL         Allow synthetic response (default: yes)\n"
3743
               "     --cache=BOOL              Allow response from cache (default: yes)\n"
3744
               "     --stale-data=BOOL         Allow response from cache with stale data (default: yes)\n"
3745
               "     --relax-single-label=BOOL Allow single label lookups to go upstream (default: no)\n"
3746
               "     --zone=BOOL               Allow response from locally registered mDNS/LLMNR\n"
3747
               "                               records (default: yes)\n"
3748
               "     --trust-anchor=BOOL       Allow response from local trust anchor (default:\n"
3749
               "                               yes)\n"
3750
               "     --network=BOOL            Allow response from network (default: yes)\n"
3751
               "     --search=BOOL             Use search domains for single-label names (default:\n"
3752
               "                               yes)\n"
3753
               "     --raw[=payload|packet]    Dump the answer as binary data\n"
3754
               "     --legend=BOOL             Print headers and additional info (default: yes)\n"
3755
               "     --json=MODE               Output as JSON\n"
3756
               "  -j                           Same as --json=pretty on tty, --json=short\n"
3757
               "                               otherwise\n"
3758
               "\nSee the %2$s for details.\n",
3759
               program_invocation_short_name,
3760
               link,
3761
               ansi_underline(),
3762
               ansi_normal(),
3763
               ansi_highlight(),
3764
               ansi_normal());
3765

3766
        return 0;
3767
}
3768

3769
static int verb_help(int argc, char **argv, void *userdata) {
×
3770
        return native_help();
×
3771
}
3772

3773
static int compat_parse_argv(int argc, char *argv[]) {
×
3774
        enum {
×
3775
                ARG_VERSION = 0x100,
3776
                ARG_LEGEND,
3777
                ARG_SERVICE,
3778
                ARG_CNAME,
3779
                ARG_SERVICE_ADDRESS,
3780
                ARG_SERVICE_TXT,
3781
                ARG_OPENPGP,
3782
                ARG_TLSA,
3783
                ARG_RAW,
3784
                ARG_SEARCH,
3785
                ARG_STATISTICS,
3786
                ARG_RESET_STATISTICS,
3787
                ARG_STATUS,
3788
                ARG_FLUSH_CACHES,
3789
                ARG_RESET_SERVER_FEATURES,
3790
                ARG_NO_PAGER,
3791
                ARG_SET_DNS,
3792
                ARG_SET_DOMAIN,
3793
                ARG_SET_LLMNR,
3794
                ARG_SET_MDNS,
3795
                ARG_SET_DNS_OVER_TLS,
3796
                ARG_SET_DNSSEC,
3797
                ARG_SET_NTA,
3798
                ARG_REVERT_LINK,
3799
        };
3800

3801
        static const struct option options[] = {
×
3802
                { "help",                  no_argument,       NULL, 'h'                       },
3803
                { "version",               no_argument,       NULL, ARG_VERSION               },
3804
                { "type",                  required_argument, NULL, 't'                       },
3805
                { "class",                 required_argument, NULL, 'c'                       },
3806
                { "legend",                required_argument, NULL, ARG_LEGEND                },
3807
                { "interface",             required_argument, NULL, 'i'                       },
3808
                { "protocol",              required_argument, NULL, 'p'                       },
3809
                { "cname",                 required_argument, NULL, ARG_CNAME                 },
3810
                { "service",               no_argument,       NULL, ARG_SERVICE               },
3811
                { "service-address",       required_argument, NULL, ARG_SERVICE_ADDRESS       },
3812
                { "service-txt",           required_argument, NULL, ARG_SERVICE_TXT           },
3813
                { "openpgp",               no_argument,       NULL, ARG_OPENPGP               },
3814
                { "tlsa",                  optional_argument, NULL, ARG_TLSA                  },
3815
                { "raw",                   optional_argument, NULL, ARG_RAW                   },
3816
                { "search",                required_argument, NULL, ARG_SEARCH                },
3817
                { "statistics",            no_argument,       NULL, ARG_STATISTICS,           },
3818
                { "reset-statistics",      no_argument,       NULL, ARG_RESET_STATISTICS      },
3819
                { "status",                no_argument,       NULL, ARG_STATUS                },
3820
                { "flush-caches",          no_argument,       NULL, ARG_FLUSH_CACHES          },
3821
                { "reset-server-features", no_argument,       NULL, ARG_RESET_SERVER_FEATURES },
3822
                { "no-pager",              no_argument,       NULL, ARG_NO_PAGER              },
3823
                { "set-dns",               required_argument, NULL, ARG_SET_DNS               },
3824
                { "set-domain",            required_argument, NULL, ARG_SET_DOMAIN            },
3825
                { "set-llmnr",             required_argument, NULL, ARG_SET_LLMNR             },
3826
                { "set-mdns",              required_argument, NULL, ARG_SET_MDNS              },
3827
                { "set-dnsovertls",        required_argument, NULL, ARG_SET_DNS_OVER_TLS      },
3828
                { "set-dnssec",            required_argument, NULL, ARG_SET_DNSSEC            },
3829
                { "set-nta",               required_argument, NULL, ARG_SET_NTA               },
3830
                { "revert",                no_argument,       NULL, ARG_REVERT_LINK           },
3831
                {}
3832
        };
3833

3834
        int c, r;
×
3835

3836
        assert(argc >= 0);
×
3837
        assert(argv);
×
3838

3839
        while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
×
3840
                switch (c) {
×
3841

3842
                case 'h':
×
3843
                        return compat_help();
×
3844

3845
                case ARG_VERSION:
×
3846
                        return version();
×
3847

3848
                case '4':
×
3849
                        arg_family = AF_INET;
×
3850
                        break;
×
3851

3852
                case '6':
×
3853
                        arg_family = AF_INET6;
×
3854
                        break;
×
3855

3856
                case 'i':
×
3857
                        r = ifname_mangle(optarg);
×
3858
                        if (r < 0)
×
3859
                                return r;
3860
                        break;
3861

3862
                case 't':
×
3863
                        if (streq(optarg, "help")) {
×
3864
                                help_dns_types();
×
3865
                                return 0;
×
3866
                        }
3867

3868
                        r = dns_type_from_string(optarg);
×
3869
                        if (r < 0)
×
3870
                                return log_error_errno(r, "Failed to parse RR record type %s: %m", optarg);
×
3871

3872
                        arg_type = (uint16_t) r;
×
3873
                        assert((int) arg_type == r);
×
3874

3875
                        arg_mode = MODE_RESOLVE_RECORD;
×
3876
                        break;
×
3877

3878
                case 'c':
×
3879
                        if (streq(optarg, "help")) {
×
3880
                                help_dns_classes();
×
3881
                                return 0;
×
3882
                        }
3883

3884
                        r = dns_class_from_string(optarg);
×
3885
                        if (r < 0)
×
3886
                                return log_error_errno(r, "Failed to parse RR record class %s: %m", optarg);
×
3887

3888
                        arg_class = (uint16_t) r;
×
3889
                        assert((int) arg_class == r);
×
3890

3891
                        break;
3892

3893
                case ARG_LEGEND:
×
3894
                        r = parse_boolean_argument("--legend=", optarg, &arg_legend);
×
3895
                        if (r < 0)
×
3896
                                return r;
3897
                        break;
3898

3899
                case 'p':
×
3900
                        if (streq(optarg, "help")) {
×
3901
                                help_protocol_types();
×
3902
                                return 0;
×
3903
                        } else if (streq(optarg, "dns"))
×
3904
                                arg_flags |= SD_RESOLVED_DNS;
×
3905
                        else if (streq(optarg, "llmnr"))
×
3906
                                arg_flags |= SD_RESOLVED_LLMNR;
×
3907
                        else if (streq(optarg, "llmnr-ipv4"))
×
3908
                                arg_flags |= SD_RESOLVED_LLMNR_IPV4;
×
3909
                        else if (streq(optarg, "llmnr-ipv6"))
×
3910
                                arg_flags |= SD_RESOLVED_LLMNR_IPV6;
×
3911
                        else if (streq(optarg, "mdns"))
×
3912
                                arg_flags |= SD_RESOLVED_MDNS;
×
3913
                        else if (streq(optarg, "mdns-ipv4"))
×
3914
                                arg_flags |= SD_RESOLVED_MDNS_IPV4;
×
3915
                        else if (streq(optarg, "mdns-ipv6"))
×
3916
                                arg_flags |= SD_RESOLVED_MDNS_IPV6;
×
3917
                        else
3918
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
3919
                                                       "Unknown protocol specifier: %s", optarg);
3920

3921
                        break;
3922

3923
                case ARG_SERVICE:
×
3924
                        arg_mode = MODE_RESOLVE_SERVICE;
×
3925
                        break;
×
3926

3927
                case ARG_OPENPGP:
×
3928
                        arg_mode = MODE_RESOLVE_OPENPGP;
×
3929
                        break;
×
3930

3931
                case ARG_TLSA:
×
3932
                        arg_mode = MODE_RESOLVE_TLSA;
×
3933
                        if (!optarg || service_family_is_valid(optarg))
×
3934
                                arg_service_family = optarg;
×
3935
                        else
3936
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
3937
                                                       "Unknown service family \"%s\".", optarg);
3938
                        break;
×
3939

3940
                case ARG_RAW:
×
3941
                        if (on_tty())
×
3942
                                return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
×
3943
                                                       "Refusing to write binary data to tty.");
3944

3945
                        if (optarg == NULL || streq(optarg, "payload"))
×
3946
                                arg_raw = RAW_PAYLOAD;
×
3947
                        else if (streq(optarg, "packet"))
×
3948
                                arg_raw = RAW_PACKET;
×
3949
                        else
3950
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
3951
                                                       "Unknown --raw specifier \"%s\".",
3952
                                                       optarg);
3953

3954
                        arg_legend = false;
×
3955
                        break;
×
3956

3957
                case ARG_CNAME:
×
3958
                        r = parse_boolean_argument("--cname=", optarg, NULL);
×
3959
                        if (r < 0)
×
3960
                                return r;
3961
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
×
3962
                        break;
×
3963

3964
                case ARG_SERVICE_ADDRESS:
×
3965
                        r = parse_boolean_argument("--service-address=", optarg, NULL);
×
3966
                        if (r < 0)
×
3967
                                return r;
3968
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
×
3969
                        break;
×
3970

3971
                case ARG_SERVICE_TXT:
×
3972
                        r = parse_boolean_argument("--service-txt=", optarg, NULL);
×
3973
                        if (r < 0)
×
3974
                                return r;
3975
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
×
3976
                        break;
×
3977

3978
                case ARG_SEARCH:
×
3979
                        r = parse_boolean_argument("--search=", optarg, NULL);
×
3980
                        if (r < 0)
×
3981
                                return r;
3982
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
×
3983
                        break;
×
3984

3985
                case ARG_STATISTICS:
×
3986
                        arg_mode = MODE_STATISTICS;
×
3987
                        break;
×
3988

3989
                case ARG_RESET_STATISTICS:
×
3990
                        arg_mode = MODE_RESET_STATISTICS;
×
3991
                        break;
×
3992

3993
                case ARG_FLUSH_CACHES:
×
3994
                        arg_mode = MODE_FLUSH_CACHES;
×
3995
                        break;
×
3996

3997
                case ARG_RESET_SERVER_FEATURES:
×
3998
                        arg_mode = MODE_RESET_SERVER_FEATURES;
×
3999
                        break;
×
4000

4001
                case ARG_STATUS:
×
4002
                        arg_mode = MODE_STATUS;
×
4003
                        break;
×
4004

4005
                case ARG_NO_PAGER:
×
4006
                        arg_pager_flags |= PAGER_DISABLE;
×
4007
                        break;
×
4008

4009
                case ARG_SET_DNS:
×
4010
                        r = strv_extend(&arg_set_dns, optarg);
×
4011
                        if (r < 0)
×
4012
                                return log_oom();
×
4013

4014
                        arg_mode = MODE_SET_LINK;
×
4015
                        break;
×
4016

4017
                case ARG_SET_DOMAIN:
×
4018
                        r = strv_extend(&arg_set_domain, optarg);
×
4019
                        if (r < 0)
×
4020
                                return log_oom();
×
4021

4022
                        arg_mode = MODE_SET_LINK;
×
4023
                        break;
×
4024

4025
                case ARG_SET_LLMNR:
×
4026
                        arg_set_llmnr = optarg;
×
4027
                        arg_mode = MODE_SET_LINK;
×
4028
                        break;
×
4029

4030
                case ARG_SET_MDNS:
×
4031
                        arg_set_mdns = optarg;
×
4032
                        arg_mode = MODE_SET_LINK;
×
4033
                        break;
×
4034

4035
                case ARG_SET_DNS_OVER_TLS:
×
4036
                        arg_set_dns_over_tls = optarg;
×
4037
                        arg_mode = MODE_SET_LINK;
×
4038
                        break;
×
4039

4040
                case ARG_SET_DNSSEC:
×
4041
                        arg_set_dnssec = optarg;
×
4042
                        arg_mode = MODE_SET_LINK;
×
4043
                        break;
×
4044

4045
                case ARG_SET_NTA:
×
4046
                        r = strv_extend(&arg_set_nta, optarg);
×
4047
                        if (r < 0)
×
4048
                                return log_oom();
×
4049

4050
                        arg_mode = MODE_SET_LINK;
×
4051
                        break;
×
4052

4053
                case ARG_REVERT_LINK:
×
4054
                        arg_mode = MODE_REVERT_LINK;
×
4055
                        break;
×
4056

4057
                case '?':
4058
                        return -EINVAL;
4059

4060
                default:
×
4061
                        assert_not_reached();
×
4062
                }
4063

4064
        if (arg_type == 0 && arg_class != 0)
×
4065
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
4066
                                       "--class= may only be used in conjunction with --type=.");
4067

4068
        if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE)
×
4069
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
4070
                                       "--service and --type= may not be combined.");
4071

4072
        if (arg_type != 0 && arg_class == 0)
×
4073
                arg_class = DNS_CLASS_IN;
×
4074

4075
        if (arg_class != 0 && arg_type == 0)
×
4076
                arg_type = DNS_TYPE_A;
×
4077

4078
        if (IN_SET(arg_mode, MODE_SET_LINK, MODE_REVERT_LINK)) {
×
4079

4080
                if (arg_ifindex <= 0)
×
4081
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
4082
                                               "--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
4083
        }
4084

4085
        return 1 /* work to do */;
4086
}
4087

4088
static int native_parse_argv(int argc, char *argv[]) {
221✔
4089
        enum {
221✔
4090
                ARG_VERSION = 0x100,
4091
                ARG_LEGEND,
4092
                ARG_CNAME,
4093
                ARG_VALIDATE,
4094
                ARG_SYNTHESIZE,
4095
                ARG_CACHE,
4096
                ARG_ZONE,
4097
                ARG_TRUST_ANCHOR,
4098
                ARG_NETWORK,
4099
                ARG_SERVICE_ADDRESS,
4100
                ARG_SERVICE_TXT,
4101
                ARG_RAW,
4102
                ARG_SEARCH,
4103
                ARG_NO_PAGER,
4104
                ARG_NO_ASK_PASSWORD,
4105
                ARG_JSON,
4106
                ARG_STALE_DATA,
4107
                ARG_RELAX_SINGLE_LABEL,
4108
        };
4109

4110
        static const struct option options[] = {
221✔
4111
                { "help",                  no_argument,       NULL, 'h'                       },
4112
                { "version",               no_argument,       NULL, ARG_VERSION               },
4113
                { "type",                  required_argument, NULL, 't'                       },
4114
                { "class",                 required_argument, NULL, 'c'                       },
4115
                { "legend",                required_argument, NULL, ARG_LEGEND                },
4116
                { "interface",             required_argument, NULL, 'i'                       },
4117
                { "protocol",              required_argument, NULL, 'p'                       },
4118
                { "cname",                 required_argument, NULL, ARG_CNAME                 },
4119
                { "validate",              required_argument, NULL, ARG_VALIDATE              },
4120
                { "synthesize",            required_argument, NULL, ARG_SYNTHESIZE            },
4121
                { "cache",                 required_argument, NULL, ARG_CACHE                 },
4122
                { "zone",                  required_argument, NULL, ARG_ZONE                  },
4123
                { "trust-anchor",          required_argument, NULL, ARG_TRUST_ANCHOR          },
4124
                { "network",               required_argument, NULL, ARG_NETWORK               },
4125
                { "service-address",       required_argument, NULL, ARG_SERVICE_ADDRESS       },
4126
                { "service-txt",           required_argument, NULL, ARG_SERVICE_TXT           },
4127
                { "raw",                   optional_argument, NULL, ARG_RAW                   },
4128
                { "search",                required_argument, NULL, ARG_SEARCH                },
4129
                { "no-pager",              no_argument,       NULL, ARG_NO_PAGER              },
4130
                { "no-ask-password",       no_argument,       NULL, ARG_NO_ASK_PASSWORD       },
4131
                { "json",                  required_argument, NULL, ARG_JSON                  },
4132
                { "stale-data",            required_argument, NULL, ARG_STALE_DATA            },
4133
                { "relax-single-label",    required_argument, NULL, ARG_RELAX_SINGLE_LABEL    },
4134
                {}
4135
        };
4136

4137
        int c, r;
221✔
4138

4139
        assert(argc >= 0);
221✔
4140
        assert(argv);
221✔
4141

4142
        while ((c = getopt_long(argc, argv, "h46i:t:c:p:j", options, NULL)) >= 0)
256✔
4143
                switch (c) {
35✔
4144

4145
                case 'h':
×
4146
                        return native_help();
×
4147

4148
                case ARG_VERSION:
×
4149
                        return version();
×
4150

4151
                case '4':
×
4152
                        arg_family = AF_INET;
×
4153
                        break;
×
4154

4155
                case '6':
×
4156
                        arg_family = AF_INET6;
×
4157
                        break;
×
4158

4159
                case 'i':
×
4160
                        r = ifname_mangle(optarg);
×
4161
                        if (r < 0)
×
4162
                                return r;
4163
                        break;
4164

4165
                case 't':
17✔
4166
                        if (streq(optarg, "help")) {
17✔
4167
                                help_dns_types();
×
4168
                                return 0;
×
4169
                        }
4170

4171
                        r = dns_type_from_string(optarg);
17✔
4172
                        if (r < 0)
17✔
4173
                                return log_error_errno(r, "Failed to parse RR record type %s: %m", optarg);
×
4174

4175
                        arg_type = (uint16_t) r;
17✔
4176
                        assert((int) arg_type == r);
17✔
4177

4178
                        break;
4179

4180
                case 'c':
×
4181
                        if (streq(optarg, "help")) {
×
4182
                                help_dns_classes();
×
4183
                                return 0;
×
4184
                        }
4185

4186
                        r = dns_class_from_string(optarg);
×
4187
                        if (r < 0)
×
4188
                                return log_error_errno(r, "Failed to parse RR record class %s: %m", optarg);
×
4189

4190
                        arg_class = (uint16_t) r;
×
4191
                        assert((int) arg_class == r);
×
4192

4193
                        break;
4194

4195
                case ARG_LEGEND:
3✔
4196
                        r = parse_boolean_argument("--legend=", optarg, &arg_legend);
3✔
4197
                        if (r < 0)
3✔
4198
                                return r;
4199
                        break;
4200

4201
                case 'p':
×
4202
                        if (streq(optarg, "help")) {
×
4203
                                help_protocol_types();
×
4204
                                return 0;
×
4205
                        } else if (streq(optarg, "dns"))
×
4206
                                arg_flags |= SD_RESOLVED_DNS;
×
4207
                        else if (streq(optarg, "llmnr"))
×
4208
                                arg_flags |= SD_RESOLVED_LLMNR;
×
4209
                        else if (streq(optarg, "llmnr-ipv4"))
×
4210
                                arg_flags |= SD_RESOLVED_LLMNR_IPV4;
×
4211
                        else if (streq(optarg, "llmnr-ipv6"))
×
4212
                                arg_flags |= SD_RESOLVED_LLMNR_IPV6;
×
4213
                        else if (streq(optarg, "mdns"))
×
4214
                                arg_flags |= SD_RESOLVED_MDNS;
×
4215
                        else if (streq(optarg, "mdns-ipv4"))
×
4216
                                arg_flags |= SD_RESOLVED_MDNS_IPV4;
×
4217
                        else if (streq(optarg, "mdns-ipv6"))
×
4218
                                arg_flags |= SD_RESOLVED_MDNS_IPV6;
×
4219
                        else
4220
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
4221
                                                       "Unknown protocol specifier: %s",
4222
                                                       optarg);
4223

4224
                        break;
4225

4226
                case ARG_RAW:
×
4227
                        if (on_tty())
×
4228
                                return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
×
4229
                                                       "Refusing to write binary data to tty.");
4230

4231
                        if (optarg == NULL || streq(optarg, "payload"))
×
4232
                                arg_raw = RAW_PAYLOAD;
×
4233
                        else if (streq(optarg, "packet"))
×
4234
                                arg_raw = RAW_PACKET;
×
4235
                        else
4236
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
4237
                                                       "Unknown --raw specifier \"%s\".",
4238
                                                       optarg);
4239

4240
                        arg_legend = false;
×
4241
                        break;
×
4242

4243
                case ARG_CNAME:
×
4244
                        r = parse_boolean_argument("--cname=", optarg, NULL);
×
4245
                        if (r < 0)
×
4246
                                return r;
4247
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
×
4248
                        break;
×
4249

4250
                case ARG_VALIDATE:
×
4251
                        r = parse_boolean_argument("--validate=", optarg, NULL);
×
4252
                        if (r < 0)
×
4253
                                return r;
4254
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_VALIDATE, r == 0);
×
4255
                        break;
×
4256

4257
                case ARG_SYNTHESIZE:
×
4258
                        r = parse_boolean_argument("--synthesize=", optarg, NULL);
×
4259
                        if (r < 0)
×
4260
                                return r;
4261
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_SYNTHESIZE, r == 0);
×
4262
                        break;
×
4263

4264
                case ARG_CACHE:
×
4265
                        r = parse_boolean_argument("--cache=", optarg, NULL);
×
4266
                        if (r < 0)
×
4267
                                return r;
4268
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_CACHE, r == 0);
×
4269
                        break;
×
4270

4271
                case ARG_STALE_DATA:
×
4272
                        r = parse_boolean_argument("--stale-data=", optarg, NULL);
×
4273
                        if (r < 0)
×
4274
                                return r;
4275
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_STALE, r == 0);
×
4276
                        break;
×
4277

4278
                case ARG_ZONE:
×
4279
                        r = parse_boolean_argument("--zone=", optarg, NULL);
×
4280
                        if (r < 0)
×
4281
                                return r;
4282
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_ZONE, r == 0);
×
4283
                        break;
×
4284

4285
                case ARG_TRUST_ANCHOR:
×
4286
                        r = parse_boolean_argument("--trust-anchor=", optarg, NULL);
×
4287
                        if (r < 0)
×
4288
                                return r;
4289
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_TRUST_ANCHOR, r == 0);
×
4290
                        break;
×
4291

4292
                case ARG_NETWORK:
×
4293
                        r = parse_boolean_argument("--network=", optarg, NULL);
×
4294
                        if (r < 0)
×
4295
                                return r;
4296
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_NETWORK, r == 0);
×
4297
                        break;
×
4298

4299
                case ARG_SERVICE_ADDRESS:
×
4300
                        r = parse_boolean_argument("--service-address=", optarg, NULL);
×
4301
                        if (r < 0)
×
4302
                                return r;
4303
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
×
4304
                        break;
×
4305

4306
                case ARG_SERVICE_TXT:
×
4307
                        r = parse_boolean_argument("--service-txt=", optarg, NULL);
×
4308
                        if (r < 0)
×
4309
                                return r;
4310
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
×
4311
                        break;
×
4312

4313
                case ARG_SEARCH:
×
4314
                        r = parse_boolean_argument("--search=", optarg, NULL);
×
4315
                        if (r < 0)
×
4316
                                return r;
4317
                        SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
×
4318
                        break;
×
4319

4320
                case ARG_RELAX_SINGLE_LABEL:
×
4321
                        r = parse_boolean_argument("--relax-single-label=", optarg, NULL);
×
4322
                        if (r < 0)
×
4323
                                return r;
4324
                        SET_FLAG(arg_flags, SD_RESOLVED_RELAX_SINGLE_LABEL, r > 0);
×
4325
                        break;
×
4326

4327
                case ARG_NO_PAGER:
×
4328
                        arg_pager_flags |= PAGER_DISABLE;
×
4329
                        break;
×
4330

4331
                case ARG_NO_ASK_PASSWORD:
×
4332
                        arg_ask_password = false;
×
4333
                        break;
×
4334

4335
                case ARG_JSON:
15✔
4336
                        r = parse_json_argument(optarg, &arg_json_format_flags);
15✔
4337
                        if (r <= 0)
15✔
4338
                                return r;
4339

4340
                        break;
4341

4342
                case 'j':
×
4343
                        arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
×
4344
                        break;
×
4345

4346
                case '?':
4347
                        return -EINVAL;
4348

4349
                default:
×
4350
                        assert_not_reached();
×
4351
                }
4352

4353
        if (arg_type == 0 && arg_class != 0)
221✔
4354
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
4355
                                       "--class= may only be used in conjunction with --type=.");
4356

4357
        if (arg_type != 0 && arg_class == 0)
221✔
4358
                arg_class = DNS_CLASS_IN;
17✔
4359

4360
        if (arg_class != 0 && arg_type == 0)
221✔
4361
                arg_type = DNS_TYPE_A;
×
4362

4363
        return 1 /* work to do */;
4364
}
4365

4366
static int native_main(int argc, char *argv[]) {
241✔
4367

4368
        static const Verb verbs[] = {
241✔
4369
                { "help",                  VERB_ANY, VERB_ANY, 0,            verb_help             },
4370
                { "status",                VERB_ANY, VERB_ANY, VERB_DEFAULT, verb_status           },
4371
                { "query",                 2,        VERB_ANY, 0,            verb_query            },
4372
                { "service",               2,        4,        0,            verb_service          },
4373
                { "openpgp",               2,        VERB_ANY, 0,            verb_openpgp          },
4374
                { "tlsa",                  2,        VERB_ANY, 0,            verb_tlsa             },
4375
                { "statistics",            VERB_ANY, 1,        0,            show_statistics       },
4376
                { "reset-statistics",      VERB_ANY, 1,        0,            reset_statistics      },
4377
                { "flush-caches",          VERB_ANY, 1,        0,            flush_caches          },
4378
                { "reset-server-features", VERB_ANY, 1,        0,            reset_server_features },
4379
                { "dns",                   VERB_ANY, VERB_ANY, 0,            verb_dns              },
4380
                { "domain",                VERB_ANY, VERB_ANY, 0,            verb_domain           },
4381
                { "default-route",         VERB_ANY, 3,        0,            verb_default_route    },
4382
                { "llmnr",                 VERB_ANY, 3,        0,            verb_llmnr            },
4383
                { "mdns",                  VERB_ANY, 3,        0,            verb_mdns             },
4384
                { "dnsovertls",            VERB_ANY, 3,        0,            verb_dns_over_tls     },
4385
                { "dnssec",                VERB_ANY, 3,        0,            verb_dnssec           },
4386
                { "nta",                   VERB_ANY, VERB_ANY, 0,            verb_nta              },
4387
                { "revert",                VERB_ANY, 2,        0,            verb_revert_link      },
4388
                { "log-level",             VERB_ANY, 2,        0,            verb_log_level        },
4389
                { "monitor",               VERB_ANY, 1,        0,            verb_monitor          },
4390
                { "show-cache",            VERB_ANY, 1,        0,            verb_show_cache       },
4391
                { "show-server-state",     VERB_ANY, 1,        0,            verb_show_server_state},
4392
                {}
4393
        };
4394

4395
        return dispatch_verb(argc, argv, verbs, /* userdata = */ NULL);
241✔
4396
}
4397

4398
static int translate(const char *verb, const char *single_arg, size_t num_args, char **args) {
20✔
4399
        char **fake, **p;
20✔
4400
        size_t num;
20✔
4401

4402
        assert(verb);
20✔
4403
        assert(num_args == 0 || args);
20✔
4404

4405
        num = !!single_arg + num_args + 1;
20✔
4406

4407
        p = fake = newa0(char *, num + 1);
20✔
4408
        *p++ = (char *) verb;
20✔
4409
        if (single_arg)
20✔
4410
                *p++ = (char *) single_arg;
20✔
4411
        FOREACH_ARRAY(arg, args, num_args)
49✔
4412
                *p++ = *arg;
29✔
4413

4414
        optind = 0;
20✔
4415
        return native_main((int) num, fake);
20✔
4416
}
4417

4418
static int compat_main(int argc, char *argv[]) {
10✔
4419
        int r = 0;
10✔
4420

4421
        switch (arg_mode) {
10✔
4422
        case MODE_RESOLVE_HOST:
×
4423
        case MODE_RESOLVE_RECORD:
4424
                return translate("query", NULL, argc - optind, argv + optind);
×
4425

4426
        case MODE_RESOLVE_SERVICE:
×
4427
                return translate("service", NULL, argc - optind, argv + optind);
×
4428

4429
        case MODE_RESOLVE_OPENPGP:
×
4430
                return translate("openpgp", NULL, argc - optind, argv + optind);
×
4431

4432
        case MODE_RESOLVE_TLSA:
×
4433
                return translate("tlsa", arg_service_family, argc - optind, argv + optind);
×
4434

4435
        case MODE_STATISTICS:
×
4436
                return translate("statistics", NULL, 0, NULL);
×
4437

4438
        case MODE_RESET_STATISTICS:
×
4439
                return translate("reset-statistics", NULL, 0, NULL);
×
4440

4441
        case MODE_FLUSH_CACHES:
×
4442
                return translate("flush-caches", NULL, 0, NULL);
×
4443

4444
        case MODE_RESET_SERVER_FEATURES:
×
4445
                return translate("reset-server-features", NULL, 0, NULL);
×
4446

4447
        case MODE_STATUS:
×
4448
                return translate("status", NULL, argc - optind, argv + optind);
×
4449

4450
        case MODE_SET_LINK:
9✔
4451
                assert(arg_ifname);
9✔
4452

4453
                if (arg_disable_default_route) {
9✔
4454
                        r = translate("default-route", arg_ifname, 1, STRV_MAKE("no"));
1✔
4455
                        if (r < 0)
1✔
4456
                                return r;
×
4457
                }
4458

4459
                if (arg_set_dns) {
9✔
4460
                        r = translate("dns", arg_ifname, strv_length(arg_set_dns), arg_set_dns);
9✔
4461
                        if (r < 0)
9✔
4462
                                return r;
4463
                }
4464

4465
                if (arg_set_domain) {
9✔
4466
                        r = translate("domain", arg_ifname, strv_length(arg_set_domain), arg_set_domain);
9✔
4467
                        if (r < 0)
9✔
4468
                                return r;
4469
                }
4470

4471
                if (arg_set_nta) {
9✔
4472
                        r = translate("nta", arg_ifname, strv_length(arg_set_nta), arg_set_nta);
×
4473
                        if (r < 0)
×
4474
                                return r;
4475
                }
4476

4477
                if (arg_set_llmnr) {
9✔
4478
                        r = translate("llmnr", arg_ifname, 1, (char **) &arg_set_llmnr);
×
4479
                        if (r < 0)
×
4480
                                return r;
4481
                }
4482

4483
                if (arg_set_mdns) {
9✔
4484
                        r = translate("mdns", arg_ifname, 1, (char **) &arg_set_mdns);
×
4485
                        if (r < 0)
×
4486
                                return r;
4487
                }
4488

4489
                if (arg_set_dns_over_tls) {
9✔
4490
                        r = translate("dnsovertls", arg_ifname, 1, (char **) &arg_set_dns_over_tls);
×
4491
                        if (r < 0)
×
4492
                                return r;
4493
                }
4494

4495
                if (arg_set_dnssec) {
9✔
4496
                        r = translate("dnssec", arg_ifname, 1, (char **) &arg_set_dnssec);
×
4497
                        if (r < 0)
×
4498
                                return r;
×
4499
                }
4500

4501
                return r;
4502

4503
        case MODE_REVERT_LINK:
1✔
4504
                assert(arg_ifname);
1✔
4505

4506
                return translate("revert", arg_ifname, 0, NULL);
1✔
4507

4508
        case _MODE_INVALID:
×
4509
                assert_not_reached();
×
4510
        }
4511

4512
        return 0;
4513
}
4514

4515
static int run(int argc, char **argv) {
232✔
4516
        bool compat = false;
232✔
4517
        int r;
232✔
4518

4519
        setlocale(LC_ALL, "");
232✔
4520
        log_setup();
232✔
4521

4522
        if (invoked_as(argv, "resolvconf")) {
232✔
4523
                compat = true;
11✔
4524
                r = resolvconf_parse_argv(argc, argv);
11✔
4525
        } else if (invoked_as(argv, "systemd-resolve")) {
221✔
4526
                compat = true;
×
4527
                r = compat_parse_argv(argc, argv);
×
4528
        } else
4529
                r = native_parse_argv(argc, argv);
221✔
4530
        if (r <= 0)
232✔
4531
                return r;
4532

4533
        if (compat)
231✔
4534
                return compat_main(argc, argv);
10✔
4535

4536
        return native_main(argc, argv);
221✔
4537
}
4538

4539
DEFINE_MAIN_FUNCTION(run);
232✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc