Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/dumpon/dumpon.c
39477 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1980, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include <sys/param.h>
33
#include <sys/capsicum.h>
34
#include <sys/disk.h>
35
#include <sys/socket.h>
36
#include <sys/sysctl.h>
37
#include <sys/wait.h>
38
39
#include <assert.h>
40
#include <capsicum_helpers.h>
41
#include <err.h>
42
#include <errno.h>
43
#include <fcntl.h>
44
#include <ifaddrs.h>
45
#include <netdb.h>
46
#include <paths.h>
47
#include <stdbool.h>
48
#include <stdint.h>
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <sysexits.h>
53
#include <unistd.h>
54
55
#include <arpa/inet.h>
56
57
#include <net/if.h>
58
#include <net/if_dl.h>
59
#include <net/route.h>
60
61
#include <netinet/in.h>
62
#include <netinet/netdump/netdump.h>
63
64
#ifdef HAVE_CRYPTO
65
#include <openssl/err.h>
66
#include <openssl/pem.h>
67
#include <openssl/rand.h>
68
#include <openssl/rsa.h>
69
#endif
70
71
static int verbose;
72
73
static _Noreturn void
74
usage(void)
75
{
76
fprintf(stderr,
77
"usage: dumpon [-i index] [-r] [-v] [-k <pubkey>] [-Zz] <device>\n"
78
" dumpon [-i index] [-r] [-v] [-k <pubkey>] [-Zz]\n"
79
" [-g <gateway>] -s <server> -c <client> <iface>\n"
80
" dumpon [-v] off\n"
81
" dumpon [-v] -l\n");
82
exit(EX_USAGE);
83
}
84
85
/*
86
* Look for a default route on the specified interface.
87
*/
88
static char *
89
find_gateway(const char *ifname)
90
{
91
struct ifaddrs *ifa, *ifap;
92
struct rt_msghdr *rtm;
93
struct sockaddr *sa;
94
struct sockaddr_dl *sdl;
95
struct sockaddr_in *dst, *mask, *gw;
96
char *buf, *next, *ret;
97
size_t sz;
98
int error, i, ifindex, mib[7];
99
100
/* First look up the interface index. */
101
if (getifaddrs(&ifap) != 0)
102
err(EX_OSERR, "getifaddrs");
103
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
104
if (ifa->ifa_addr->sa_family != AF_LINK)
105
continue;
106
if (strcmp(ifa->ifa_name, ifname) == 0) {
107
sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
108
ifindex = sdl->sdl_index;
109
break;
110
}
111
}
112
if (ifa == NULL)
113
errx(1, "couldn't find interface index for '%s'", ifname);
114
freeifaddrs(ifap);
115
116
/* Now get the IPv4 routing table. */
117
mib[0] = CTL_NET;
118
mib[1] = PF_ROUTE;
119
mib[2] = 0;
120
mib[3] = AF_INET;
121
mib[4] = NET_RT_DUMP;
122
mib[5] = 0;
123
mib[6] = -1; /* FIB */
124
125
for (;;) {
126
if (sysctl(mib, nitems(mib), NULL, &sz, NULL, 0) != 0)
127
err(EX_OSERR, "sysctl(NET_RT_DUMP)");
128
buf = malloc(sz);
129
error = sysctl(mib, nitems(mib), buf, &sz, NULL, 0);
130
if (error == 0)
131
break;
132
if (errno != ENOMEM)
133
err(EX_OSERR, "sysctl(NET_RT_DUMP)");
134
free(buf);
135
}
136
137
ret = NULL;
138
for (next = buf; next < buf + sz; next += rtm->rtm_msglen) {
139
rtm = (struct rt_msghdr *)(void *)next;
140
if (rtm->rtm_version != RTM_VERSION)
141
continue;
142
if ((rtm->rtm_flags & RTF_GATEWAY) == 0 ||
143
rtm->rtm_index != ifindex)
144
continue;
145
146
dst = gw = mask = NULL;
147
sa = (struct sockaddr *)(rtm + 1);
148
for (i = 0; i < RTAX_MAX; i++) {
149
if ((rtm->rtm_addrs & (1 << i)) != 0) {
150
switch (i) {
151
case RTAX_DST:
152
dst = (void *)sa;
153
break;
154
case RTAX_GATEWAY:
155
gw = (void *)sa;
156
break;
157
case RTAX_NETMASK:
158
mask = (void *)sa;
159
break;
160
}
161
}
162
sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
163
}
164
165
if (dst->sin_addr.s_addr == INADDR_ANY &&
166
mask->sin_addr.s_addr == 0) {
167
ret = inet_ntoa(gw->sin_addr);
168
break;
169
}
170
}
171
free(buf);
172
return (ret);
173
}
174
175
static void
176
check_link_status(const char *ifname)
177
{
178
struct ifaddrs *ifap, *ifa;
179
180
if (getifaddrs(&ifap) != 0)
181
err(EX_OSERR, "getifaddrs");
182
183
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
184
if (strcmp(ifname, ifa->ifa_name) != 0)
185
continue;
186
if ((ifa->ifa_flags & IFF_UP) == 0) {
187
warnx("warning: %s's link is down", ifname);
188
}
189
break;
190
}
191
freeifaddrs(ifap);
192
}
193
194
static void
195
check_size(int fd, const char *fn)
196
{
197
int name[] = { CTL_HW, HW_PHYSMEM };
198
size_t namelen = nitems(name);
199
unsigned long physmem;
200
size_t len;
201
off_t mediasize;
202
int minidump;
203
204
len = sizeof(minidump);
205
if (sysctlbyname("debug.minidump", &minidump, &len, NULL, 0) == 0 &&
206
minidump == 1)
207
return;
208
len = sizeof(physmem);
209
if (sysctl(name, namelen, &physmem, &len, NULL, 0) != 0)
210
err(EX_OSERR, "can't get memory size");
211
if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0)
212
err(EX_OSERR, "%s: can't get size", fn);
213
if ((uintmax_t)mediasize < (uintmax_t)physmem)
214
errx(EX_IOERR, "%s is smaller than physical memory", fn);
215
}
216
217
#ifdef HAVE_CRYPTO
218
static void
219
_genkey(const char *pubkeyfile, struct diocskerneldump_arg *kdap)
220
{
221
FILE *fp;
222
RSA *pubkey;
223
224
assert(pubkeyfile != NULL);
225
assert(kdap != NULL);
226
227
fp = NULL;
228
pubkey = NULL;
229
230
fp = fopen(pubkeyfile, "r");
231
if (fp == NULL)
232
err(1, "Unable to open %s", pubkeyfile);
233
234
/*
235
* Obsolescent OpenSSL only knows about /dev/random, and needs to
236
* pre-seed before entering cap mode. For whatever reason,
237
* RSA_pub_encrypt uses the internal PRNG.
238
*/
239
#if OPENSSL_VERSION_NUMBER < 0x10100000L
240
{
241
unsigned char c[1];
242
RAND_bytes(c, 1);
243
}
244
#endif
245
246
if (caph_enter() < 0)
247
err(1, "Unable to enter capability mode");
248
249
pubkey = RSA_new();
250
if (pubkey == NULL) {
251
errx(1, "Unable to allocate an RSA structure: %s",
252
ERR_error_string(ERR_get_error(), NULL));
253
}
254
255
pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL);
256
fclose(fp);
257
fp = NULL;
258
if (pubkey == NULL)
259
errx(1, "Unable to read data from %s: %s", pubkeyfile,
260
ERR_error_string(ERR_get_error(), NULL));
261
262
/*
263
* RSA keys under ~1024 bits are trivially factorable (2018). OpenSSL
264
* provides an API for RSA keys to estimate the symmetric-cipher
265
* "equivalent" bits of security (defined in NIST SP800-57), which as
266
* of this writing equates a 2048-bit RSA key to 112 symmetric cipher
267
* bits.
268
*
269
* Use this API as a seatbelt to avoid suggesting to users that their
270
* privacy is protected by encryption when the key size is insufficient
271
* to prevent compromise via factoring.
272
*
273
* Future work: Sanity check for weak 'e', and sanity check for absence
274
* of 'd' (i.e., the supplied key is a public key rather than a full
275
* keypair).
276
*/
277
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
278
if (RSA_security_bits(pubkey) < 112)
279
#else
280
if (RSA_size(pubkey) * 8 < 2048)
281
#endif
282
errx(1, "Small RSA keys (you provided: %db) can be "
283
"factored cheaply. Please generate a larger key.",
284
RSA_size(pubkey) * 8);
285
286
kdap->kda_encryptedkeysize = RSA_size(pubkey);
287
if (kdap->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) {
288
errx(1, "Public key has to be at most %db long.",
289
8 * KERNELDUMP_ENCKEY_MAX_SIZE);
290
}
291
292
kdap->kda_encryptedkey = calloc(1, kdap->kda_encryptedkeysize);
293
if (kdap->kda_encryptedkey == NULL)
294
err(1, "Unable to allocate encrypted key");
295
296
/*
297
* If no cipher was specified, choose a reasonable default.
298
*/
299
if (kdap->kda_encryption == KERNELDUMP_ENC_NONE)
300
kdap->kda_encryption = KERNELDUMP_ENC_CHACHA20;
301
else if (kdap->kda_encryption == KERNELDUMP_ENC_AES_256_CBC &&
302
kdap->kda_compression != KERNELDUMP_COMP_NONE)
303
errx(EX_USAGE, "Unpadded AES256-CBC mode cannot be used "
304
"with compression.");
305
306
arc4random_buf(kdap->kda_key, sizeof(kdap->kda_key));
307
if (RSA_public_encrypt(sizeof(kdap->kda_key), kdap->kda_key,
308
kdap->kda_encryptedkey, pubkey,
309
RSA_PKCS1_OAEP_PADDING) != (int)kdap->kda_encryptedkeysize) {
310
errx(1, "Unable to encrypt the one-time key: %s",
311
ERR_error_string(ERR_get_error(), NULL));
312
}
313
RSA_free(pubkey);
314
}
315
316
/*
317
* Run genkey() in a child so it can use capability mode without affecting
318
* the rest of the runtime.
319
*/
320
static void
321
genkey(const char *pubkeyfile, struct diocskerneldump_arg *kdap)
322
{
323
pid_t pid;
324
int error, filedes[2], status;
325
ssize_t bytes;
326
327
if (pipe2(filedes, O_CLOEXEC) != 0)
328
err(1, "pipe");
329
pid = fork();
330
switch (pid) {
331
case -1:
332
err(1, "fork");
333
break;
334
case 0:
335
close(filedes[0]);
336
_genkey(pubkeyfile, kdap);
337
/* Write the new kdap back to the parent. */
338
bytes = write(filedes[1], kdap, sizeof(*kdap));
339
if (bytes != sizeof(*kdap))
340
err(1, "genkey pipe write");
341
bytes = write(filedes[1], kdap->kda_encryptedkey,
342
kdap->kda_encryptedkeysize);
343
if (bytes != (ssize_t)kdap->kda_encryptedkeysize)
344
err(1, "genkey pipe write kda_encryptedkey");
345
_exit(0);
346
}
347
close(filedes[1]);
348
/* Read in the child's genkey() result into kdap. */
349
bytes = read(filedes[0], kdap, sizeof(*kdap));
350
if (bytes != sizeof(*kdap))
351
errx(1, "genkey pipe read");
352
if (kdap->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE)
353
errx(1, "Public key has to be at most %db long.",
354
8 * KERNELDUMP_ENCKEY_MAX_SIZE);
355
kdap->kda_encryptedkey = calloc(1, kdap->kda_encryptedkeysize);
356
if (kdap->kda_encryptedkey == NULL)
357
err(1, "Unable to allocate encrypted key");
358
bytes = read(filedes[0], kdap->kda_encryptedkey,
359
kdap->kda_encryptedkeysize);
360
if (bytes != (ssize_t)kdap->kda_encryptedkeysize)
361
errx(1, "genkey pipe read kda_encryptedkey");
362
error = waitpid(pid, &status, WEXITED);
363
if (error == -1)
364
err(1, "waitpid");
365
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
366
errx(1, "genkey child exited with status %d",
367
WEXITSTATUS(status));
368
else if (WIFSIGNALED(status))
369
errx(1, "genkey child exited with signal %d",
370
WTERMSIG(status));
371
close(filedes[0]);
372
}
373
#endif
374
375
static void
376
listdumpdev(void)
377
{
378
static char ip[200];
379
380
char dumpdev[PATH_MAX];
381
struct diocskerneldump_arg ndconf;
382
size_t len;
383
const char *sysctlname = "kern.shutdown.dumpdevname";
384
int fd;
385
386
len = sizeof(dumpdev);
387
if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) {
388
if (errno == ENOMEM) {
389
err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n",
390
sysctlname);
391
} else {
392
err(EX_OSERR, "Sysctl get '%s'\n", sysctlname);
393
}
394
}
395
if (strlen(dumpdev) == 0)
396
(void)strlcpy(dumpdev, _PATH_DEVNULL, sizeof(dumpdev));
397
398
if (verbose) {
399
char *ctx, *dd;
400
unsigned idx;
401
402
printf("kernel dumps on priority: device\n");
403
idx = 0;
404
ctx = dumpdev;
405
while ((dd = strsep(&ctx, ",")) != NULL)
406
printf("%u: %s\n", idx++, dd);
407
} else
408
printf("%s\n", dumpdev);
409
410
/* If netdump is enabled, print the configuration parameters. */
411
if (verbose) {
412
fd = open(_PATH_NETDUMP, O_RDONLY);
413
if (fd < 0) {
414
if (errno != ENOENT)
415
err(EX_OSERR, "opening %s", _PATH_NETDUMP);
416
return;
417
}
418
if (ioctl(fd, DIOCGKERNELDUMP, &ndconf) != 0) {
419
if (errno != ENXIO)
420
err(EX_OSERR, "ioctl(DIOCGKERNELDUMP)");
421
(void)close(fd);
422
return;
423
}
424
425
printf("server address: %s\n",
426
inet_ntop(ndconf.kda_af, &ndconf.kda_server, ip,
427
sizeof(ip)));
428
printf("client address: %s\n",
429
inet_ntop(ndconf.kda_af, &ndconf.kda_client, ip,
430
sizeof(ip)));
431
printf("gateway address: %s\n",
432
inet_ntop(ndconf.kda_af, &ndconf.kda_gateway, ip,
433
sizeof(ip)));
434
(void)close(fd);
435
}
436
}
437
438
static int
439
opendumpdev(const char *arg, char *dumpdev)
440
{
441
int fd, i;
442
443
if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
444
strlcpy(dumpdev, arg, PATH_MAX);
445
else {
446
i = snprintf(dumpdev, PATH_MAX, "%s%s", _PATH_DEV, arg);
447
if (i < 0)
448
err(EX_OSERR, "%s", arg);
449
if (i >= PATH_MAX)
450
errc(EX_DATAERR, EINVAL, "%s", arg);
451
}
452
453
fd = open(dumpdev, O_RDONLY);
454
if (fd < 0)
455
err(EX_OSFILE, "%s", dumpdev);
456
return (fd);
457
}
458
459
int
460
main(int argc, char *argv[])
461
{
462
char dumpdev[PATH_MAX];
463
struct diocskerneldump_arg ndconf, *kdap;
464
struct addrinfo hints, *res;
465
const char *dev, *pubkeyfile, *server, *client, *gateway;
466
int ch, error, fd;
467
bool gzip, list, netdump, zstd, insert, rflag;
468
uint8_t ins_idx;
469
#ifdef HAVE_CRYPTO
470
int cipher = KERNELDUMP_ENC_NONE;
471
#endif
472
473
gzip = list = netdump = zstd = insert = rflag = false;
474
kdap = NULL;
475
pubkeyfile = NULL;
476
server = client = gateway = NULL;
477
ins_idx = KDA_APPEND;
478
479
while ((ch = getopt(argc, argv, "C:c:g:i:k:lrs:vZz")) != -1)
480
switch ((char)ch) {
481
case 'C':
482
#ifdef HAVE_CRYPTO
483
if (strcasecmp(optarg, "chacha") == 0 ||
484
strcasecmp(optarg, "chacha20") == 0)
485
cipher = KERNELDUMP_ENC_CHACHA20;
486
else if (strcasecmp(optarg, "aes-cbc") == 0 ||
487
strcasecmp(optarg, "aes256-cbc") == 0)
488
cipher = KERNELDUMP_ENC_AES_256_CBC;
489
else
490
errx(EX_USAGE, "Unrecognized cipher algorithm "
491
"'%s'", optarg);
492
break;
493
#else
494
errx(EX_USAGE,
495
"Built without crypto support, -C is unhandled.");
496
break;
497
#endif
498
case 'c':
499
client = optarg;
500
break;
501
case 'g':
502
gateway = optarg;
503
break;
504
case 'i':
505
{
506
int i;
507
508
i = atoi(optarg);
509
if (i < 0 || i >= KDA_APPEND - 1)
510
errx(EX_USAGE,
511
"-i index must be between zero and %d.",
512
(int)KDA_APPEND - 2);
513
insert = true;
514
ins_idx = i;
515
}
516
break;
517
case 'k':
518
pubkeyfile = optarg;
519
break;
520
case 'l':
521
list = true;
522
break;
523
case 'r':
524
rflag = true;
525
break;
526
case 's':
527
server = optarg;
528
break;
529
case 'v':
530
verbose = 1;
531
break;
532
case 'Z':
533
zstd = true;
534
break;
535
case 'z':
536
gzip = true;
537
break;
538
default:
539
usage();
540
}
541
542
if (gzip && zstd)
543
errx(EX_USAGE, "The -z and -Z options are mutually exclusive.");
544
545
if (insert && rflag)
546
errx(EX_USAGE, "The -i and -r options are mutually exclusive.");
547
548
argc -= optind;
549
argv += optind;
550
551
if (list) {
552
listdumpdev();
553
exit(EX_OK);
554
}
555
556
if (argc != 1)
557
usage();
558
559
#ifdef HAVE_CRYPTO
560
if (cipher != KERNELDUMP_ENC_NONE && pubkeyfile == NULL) {
561
errx(EX_USAGE, "-C option requires a public key file.");
562
} else if (pubkeyfile != NULL) {
563
#if OPENSSL_VERSION_NUMBER < 0x10100000L
564
ERR_load_crypto_strings();
565
#else
566
if (!OPENSSL_init_crypto(0, NULL))
567
errx(EX_UNAVAILABLE, "Unable to initialize OpenSSL");
568
#endif
569
}
570
#else
571
if (pubkeyfile != NULL)
572
errx(EX_UNAVAILABLE,"Unable to use the public key."
573
" Recompile dumpon with OpenSSL support.");
574
#endif
575
576
if (server != NULL && client != NULL) {
577
dev = _PATH_NETDUMP;
578
netdump = true;
579
} else if (server == NULL && client == NULL && argc > 0) {
580
if (strcmp(argv[0], "off") == 0) {
581
rflag = true;
582
dev = _PATH_DEVNULL;
583
} else
584
dev = argv[0];
585
netdump = false;
586
587
if (strcmp(dev, _PATH_DEVNULL) == 0) {
588
/*
589
* Netdump has its own configuration tracking that
590
* is not removed when using /dev/null.
591
*/
592
fd = open(_PATH_NETDUMP, O_RDONLY);
593
if (fd != -1) {
594
bzero(&ndconf, sizeof(ndconf));
595
ndconf.kda_index = KDA_REMOVE_ALL;
596
ndconf.kda_af = AF_INET;
597
error = ioctl(fd, DIOCSKERNELDUMP, &ndconf);
598
if (error != 0)
599
err(1, "ioctl(%s, DIOCSKERNELDUMP)",
600
_PATH_NETDUMP);
601
close(fd);
602
}
603
}
604
} else
605
usage();
606
607
fd = opendumpdev(dev, dumpdev);
608
if (!netdump && !gzip && !zstd && !rflag)
609
check_size(fd, dumpdev);
610
611
kdap = &ndconf;
612
bzero(kdap, sizeof(*kdap));
613
614
if (rflag)
615
kdap->kda_index = KDA_REMOVE;
616
else
617
kdap->kda_index = ins_idx;
618
619
kdap->kda_compression = KERNELDUMP_COMP_NONE;
620
if (zstd)
621
kdap->kda_compression = KERNELDUMP_COMP_ZSTD;
622
else if (gzip)
623
kdap->kda_compression = KERNELDUMP_COMP_GZIP;
624
625
if (netdump) {
626
memset(&hints, 0, sizeof(hints));
627
hints.ai_family = AF_INET;
628
hints.ai_protocol = IPPROTO_UDP;
629
res = NULL;
630
error = getaddrinfo(server, NULL, &hints, &res);
631
if (error != 0) {
632
if (error == EAI_SYSTEM)
633
err(EX_OSERR, "%s", gai_strerror(error));
634
errx(EX_NOHOST, "%s", gai_strerror(error));
635
}
636
server = inet_ntoa(
637
((struct sockaddr_in *)(void *)res->ai_addr)->sin_addr);
638
freeaddrinfo(res);
639
640
if (strlcpy(ndconf.kda_iface, argv[0],
641
sizeof(ndconf.kda_iface)) >= sizeof(ndconf.kda_iface))
642
errx(EX_USAGE, "invalid interface name '%s'", argv[0]);
643
if (inet_aton(server, &ndconf.kda_server.in4) == 0)
644
errx(EX_USAGE, "invalid server address '%s'", server);
645
if (inet_aton(client, &ndconf.kda_client.in4) == 0)
646
errx(EX_USAGE, "invalid client address '%s'", client);
647
648
if (gateway == NULL) {
649
gateway = find_gateway(argv[0]);
650
if (gateway == NULL) {
651
if (verbose)
652
printf(
653
"failed to look up gateway for %s\n",
654
server);
655
gateway = server;
656
}
657
}
658
if (inet_aton(gateway, &ndconf.kda_gateway.in4) == 0)
659
errx(EX_USAGE, "invalid gateway address '%s'", gateway);
660
ndconf.kda_af = AF_INET;
661
}
662
663
#ifdef HAVE_CRYPTO
664
if (pubkeyfile != NULL) {
665
kdap->kda_encryption = cipher;
666
genkey(pubkeyfile, kdap);
667
}
668
#endif
669
error = ioctl(fd, DIOCSKERNELDUMP, kdap);
670
if (error != 0)
671
error = errno;
672
if (error == EINVAL && (gzip || zstd)) {
673
/* Retry without compression in case kernel lacks support. */
674
kdap->kda_compression = KERNELDUMP_COMP_NONE;
675
error = ioctl(fd, DIOCSKERNELDUMP, kdap);
676
if (error == 0)
677
warnx("Compression disabled; kernel may lack gzip or zstd support.");
678
else
679
error = errno;
680
}
681
/* Emit a warning if the user configured a downed interface. */
682
if (error == 0 && netdump)
683
check_link_status(kdap->kda_iface);
684
explicit_bzero(kdap->kda_encryptedkey, kdap->kda_encryptedkeysize);
685
free(kdap->kda_encryptedkey);
686
explicit_bzero(kdap, sizeof(*kdap));
687
if (error != 0) {
688
if (netdump) {
689
/*
690
* Be slightly less user-hostile for some common
691
* errors, especially as users don't have any great
692
* discoverability into which NICs support netdump.
693
*/
694
if (error == ENODEV)
695
errx(EX_OSERR, "Unable to configure netdump "
696
"because the interface driver does not yet "
697
"support netdump.");
698
}
699
errc(EX_OSERR, error, "ioctl(DIOCSKERNELDUMP)");
700
}
701
702
if (verbose)
703
listdumpdev();
704
705
exit(EX_OK);
706
}
707
708