xref: /freebsd/sbin/dumpon/dumpon.c (revision 21a8e0b1d5868eeaa75b9024df6c603dc77e8e3c)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
483f9dfabSGarrett Wollman  * Copyright (c) 1980, 1993
583f9dfabSGarrett Wollman  *	The Regents of the University of California.  All rights reserved.
683f9dfabSGarrett Wollman  *
783f9dfabSGarrett Wollman  * Redistribution and use in source and binary forms, with or without
883f9dfabSGarrett Wollman  * modification, are permitted provided that the following conditions
983f9dfabSGarrett Wollman  * are met:
1083f9dfabSGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
1183f9dfabSGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
1283f9dfabSGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
1383f9dfabSGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
1483f9dfabSGarrett Wollman  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1683f9dfabSGarrett Wollman  *    may be used to endorse or promote products derived from this software
1783f9dfabSGarrett Wollman  *    without specific prior written permission.
1883f9dfabSGarrett Wollman  *
1983f9dfabSGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2083f9dfabSGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2183f9dfabSGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2283f9dfabSGarrett Wollman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2383f9dfabSGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2483f9dfabSGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2583f9dfabSGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2683f9dfabSGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2783f9dfabSGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2883f9dfabSGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2983f9dfabSGarrett Wollman  * SUCH DAMAGE.
3083f9dfabSGarrett Wollman  */
3183f9dfabSGarrett Wollman 
32c69284caSDavid E. O'Brien #if 0
3383f9dfabSGarrett Wollman #ifndef lint
348f034b11SPhilippe Charnier static const char copyright[] =
3583f9dfabSGarrett Wollman "@(#) Copyright (c) 1980, 1993\n\
3683f9dfabSGarrett Wollman 	The Regents of the University of California.  All rights reserved.\n";
3783f9dfabSGarrett Wollman #endif /* not lint */
3883f9dfabSGarrett Wollman 
3983f9dfabSGarrett Wollman #ifndef lint
408f034b11SPhilippe Charnier static char sccsid[] = "From: @(#)swapon.c	8.1 (Berkeley) 6/5/93";
4183f9dfabSGarrett Wollman #endif /* not lint */
42c69284caSDavid E. O'Brien #endif
43c69284caSDavid E. O'Brien #include <sys/cdefs.h>
44c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$");
4583f9dfabSGarrett Wollman 
4683f9dfabSGarrett Wollman #include <sys/param.h>
47480f31c2SKonrad Witaszczyk #include <sys/capsicum.h>
482dd527b3SPoul-Henning Kamp #include <sys/disk.h>
490ff40d3dSMark Johnston #include <sys/socket.h>
50c0046e26SDag-Erling Smørgrav #include <sys/sysctl.h>
5183f9dfabSGarrett Wollman 
52480f31c2SKonrad Witaszczyk #include <assert.h>
53c0046e26SDag-Erling Smørgrav #include <err.h>
54f6848434SAlfred Perlstein #include <errno.h>
55c0046e26SDag-Erling Smørgrav #include <fcntl.h>
560ff40d3dSMark Johnston #include <ifaddrs.h>
570ff40d3dSMark Johnston #include <netdb.h>
58c0046e26SDag-Erling Smørgrav #include <paths.h>
59480f31c2SKonrad Witaszczyk #include <stdbool.h>
60c0046e26SDag-Erling Smørgrav #include <stdint.h>
61c0046e26SDag-Erling Smørgrav #include <stdio.h>
62c0046e26SDag-Erling Smørgrav #include <stdlib.h>
63c0046e26SDag-Erling Smørgrav #include <string.h>
64c0046e26SDag-Erling Smørgrav #include <sysexits.h>
65c0046e26SDag-Erling Smørgrav #include <unistd.h>
66c0046e26SDag-Erling Smørgrav 
670ff40d3dSMark Johnston #include <arpa/inet.h>
680ff40d3dSMark Johnston 
690ff40d3dSMark Johnston #include <net/if.h>
700ff40d3dSMark Johnston #include <net/if_dl.h>
710ff40d3dSMark Johnston #include <net/route.h>
720ff40d3dSMark Johnston 
730ff40d3dSMark Johnston #include <netinet/in.h>
740ff40d3dSMark Johnston #include <netinet/netdump/netdump.h>
750ff40d3dSMark Johnston 
76480f31c2SKonrad Witaszczyk #ifdef HAVE_CRYPTO
77480f31c2SKonrad Witaszczyk #include <openssl/err.h>
78480f31c2SKonrad Witaszczyk #include <openssl/pem.h>
79480f31c2SKonrad Witaszczyk #include <openssl/rsa.h>
80480f31c2SKonrad Witaszczyk #endif
81480f31c2SKonrad Witaszczyk 
82c0046e26SDag-Erling Smørgrav static int	verbose;
83c0046e26SDag-Erling Smørgrav 
840ff40d3dSMark Johnston static void _Noreturn
85c0046e26SDag-Erling Smørgrav usage(void)
86c0046e26SDag-Erling Smørgrav {
870ff40d3dSMark Johnston 	fprintf(stderr,
880ff40d3dSMark Johnston     "usage: dumpon [-v] [-k <pubkey>] [-Zz] <device>\n"
890ff40d3dSMark Johnston     "       dumpon [-v] [-k <pubkey>] [-Zz]\n"
900ff40d3dSMark Johnston     "              [-g <gateway>|default] -s <server> -c <client> <iface>\n"
910ff40d3dSMark Johnston     "       dumpon [-v] off\n"
920ff40d3dSMark Johnston     "       dumpon [-v] -l\n");
93c0046e26SDag-Erling Smørgrav 	exit(EX_USAGE);
94c0046e26SDag-Erling Smørgrav }
95c0046e26SDag-Erling Smørgrav 
960ff40d3dSMark Johnston /*
970ff40d3dSMark Johnston  * Look for a default route on the specified interface.
980ff40d3dSMark Johnston  */
990ff40d3dSMark Johnston static char *
1000ff40d3dSMark Johnston find_gateway(const char *ifname)
1010ff40d3dSMark Johnston {
1020ff40d3dSMark Johnston 	struct ifaddrs *ifa, *ifap;
1030ff40d3dSMark Johnston 	struct rt_msghdr *rtm;
1040ff40d3dSMark Johnston 	struct sockaddr *sa;
1050ff40d3dSMark Johnston 	struct sockaddr_dl *sdl;
1060ff40d3dSMark Johnston 	struct sockaddr_in *dst, *mask, *gw;
1070ff40d3dSMark Johnston 	char *buf, *next, *ret;
1080ff40d3dSMark Johnston 	size_t sz;
1090ff40d3dSMark Johnston 	int error, i, ifindex, mib[7];
1100ff40d3dSMark Johnston 
1110ff40d3dSMark Johnston 	ret = NULL;
1120ff40d3dSMark Johnston 
1130ff40d3dSMark Johnston 	/* First look up the interface index. */
1140ff40d3dSMark Johnston 	if (getifaddrs(&ifap) != 0)
1150ff40d3dSMark Johnston 		err(EX_OSERR, "getifaddrs");
1160ff40d3dSMark Johnston 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1170ff40d3dSMark Johnston 		if (ifa->ifa_addr->sa_family != AF_LINK)
1180ff40d3dSMark Johnston 			continue;
1190ff40d3dSMark Johnston 		if (strcmp(ifa->ifa_name, ifname) == 0) {
1200ff40d3dSMark Johnston 			sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
1210ff40d3dSMark Johnston 			ifindex = sdl->sdl_index;
1220ff40d3dSMark Johnston 			break;
1230ff40d3dSMark Johnston 		}
1240ff40d3dSMark Johnston 	}
1250ff40d3dSMark Johnston 	if (ifa == NULL)
1260ff40d3dSMark Johnston 		errx(1, "couldn't find interface index for '%s'", ifname);
1270ff40d3dSMark Johnston 	freeifaddrs(ifap);
1280ff40d3dSMark Johnston 
1290ff40d3dSMark Johnston 	/* Now get the IPv4 routing table. */
1300ff40d3dSMark Johnston 	mib[0] = CTL_NET;
1310ff40d3dSMark Johnston 	mib[1] = PF_ROUTE;
1320ff40d3dSMark Johnston 	mib[2] = 0;
1330ff40d3dSMark Johnston 	mib[3] = AF_INET;
1340ff40d3dSMark Johnston 	mib[4] = NET_RT_DUMP;
1350ff40d3dSMark Johnston 	mib[5] = 0;
1360ff40d3dSMark Johnston 	mib[6] = -1; /* FIB */
1370ff40d3dSMark Johnston 
1380ff40d3dSMark Johnston 	for (;;) {
1390ff40d3dSMark Johnston 		if (sysctl(mib, nitems(mib), NULL, &sz, NULL, 0) != 0)
1400ff40d3dSMark Johnston 			err(EX_OSERR, "sysctl(NET_RT_DUMP)");
1410ff40d3dSMark Johnston 		buf = malloc(sz);
1420ff40d3dSMark Johnston 		error = sysctl(mib, nitems(mib), buf, &sz, NULL, 0);
1430ff40d3dSMark Johnston 		if (error == 0)
1440ff40d3dSMark Johnston 			break;
1450ff40d3dSMark Johnston 		if (errno != ENOMEM)
1460ff40d3dSMark Johnston 			err(EX_OSERR, "sysctl(NET_RT_DUMP)");
1470ff40d3dSMark Johnston 		free(buf);
1480ff40d3dSMark Johnston 	}
1490ff40d3dSMark Johnston 
1500ff40d3dSMark Johnston 	for (next = buf; next < buf + sz; next += rtm->rtm_msglen) {
1510ff40d3dSMark Johnston 		rtm = (struct rt_msghdr *)(void *)next;
1520ff40d3dSMark Johnston 		if (rtm->rtm_version != RTM_VERSION)
1530ff40d3dSMark Johnston 			continue;
1540ff40d3dSMark Johnston 		if ((rtm->rtm_flags & RTF_GATEWAY) == 0 ||
1550ff40d3dSMark Johnston 		    rtm->rtm_index != ifindex)
1560ff40d3dSMark Johnston 			continue;
1570ff40d3dSMark Johnston 
1580ff40d3dSMark Johnston 		dst = gw = mask = NULL;
1590ff40d3dSMark Johnston 		sa = (struct sockaddr *)(rtm + 1);
1600ff40d3dSMark Johnston 		for (i = 0; i < RTAX_MAX; i++) {
1610ff40d3dSMark Johnston 			if ((rtm->rtm_addrs & (1 << i)) != 0) {
1620ff40d3dSMark Johnston 				switch (i) {
1630ff40d3dSMark Johnston 				case RTAX_DST:
1640ff40d3dSMark Johnston 					dst = (void *)sa;
1650ff40d3dSMark Johnston 					break;
1660ff40d3dSMark Johnston 				case RTAX_GATEWAY:
1670ff40d3dSMark Johnston 					gw = (void *)sa;
1680ff40d3dSMark Johnston 					break;
1690ff40d3dSMark Johnston 				case RTAX_NETMASK:
1700ff40d3dSMark Johnston 					mask = (void *)sa;
1710ff40d3dSMark Johnston 					break;
1720ff40d3dSMark Johnston 				}
1730ff40d3dSMark Johnston 			}
1740ff40d3dSMark Johnston 			sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
1750ff40d3dSMark Johnston 		}
1760ff40d3dSMark Johnston 
1770ff40d3dSMark Johnston 		if (dst->sin_addr.s_addr == INADDR_ANY &&
1780ff40d3dSMark Johnston 		    mask->sin_addr.s_addr == 0) {
1790ff40d3dSMark Johnston 			ret = inet_ntoa(gw->sin_addr);
1800ff40d3dSMark Johnston 			break;
1810ff40d3dSMark Johnston 		}
1820ff40d3dSMark Johnston 	}
1830ff40d3dSMark Johnston 	free(buf);
1840ff40d3dSMark Johnston 	return (ret);
1850ff40d3dSMark Johnston }
1860ff40d3dSMark Johnston 
187c0046e26SDag-Erling Smørgrav static void
188c0046e26SDag-Erling Smørgrav check_size(int fd, const char *fn)
189c0046e26SDag-Erling Smørgrav {
190c0046e26SDag-Erling Smørgrav 	int name[] = { CTL_HW, HW_PHYSMEM };
1910bfc2a12SMarcelo Araujo 	size_t namelen = nitems(name);
192c0046e26SDag-Erling Smørgrav 	unsigned long physmem;
193ce893772SPaul Saab 	size_t len;
194c0046e26SDag-Erling Smørgrav 	off_t mediasize;
195ce893772SPaul Saab 	int minidump;
196c0046e26SDag-Erling Smørgrav 
197b54a17cdSJohn Baldwin 	len = sizeof(minidump);
198ce893772SPaul Saab 	if (sysctlbyname("debug.minidump", &minidump, &len, NULL, 0) == 0 &&
199ce893772SPaul Saab 	    minidump == 1)
200ce893772SPaul Saab 		return;
201b54a17cdSJohn Baldwin 	len = sizeof(physmem);
202c0046e26SDag-Erling Smørgrav 	if (sysctl(name, namelen, &physmem, &len, NULL, 0) != 0)
203c0046e26SDag-Erling Smørgrav 		err(EX_OSERR, "can't get memory size");
204c0046e26SDag-Erling Smørgrav 	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0)
205c0046e26SDag-Erling Smørgrav 		err(EX_OSERR, "%s: can't get size", fn);
2069872f15dSDag-Erling Smørgrav 	if ((uintmax_t)mediasize < (uintmax_t)physmem) {
207c0046e26SDag-Erling Smørgrav 		if (verbose)
208c0046e26SDag-Erling Smørgrav 			printf("%s is smaller than physical memory\n", fn);
209c0046e26SDag-Erling Smørgrav 		exit(EX_IOERR);
210c0046e26SDag-Erling Smørgrav 	}
211c0046e26SDag-Erling Smørgrav }
21283f9dfabSGarrett Wollman 
213480f31c2SKonrad Witaszczyk #ifdef HAVE_CRYPTO
214480f31c2SKonrad Witaszczyk static void
2150ff40d3dSMark Johnston genkey(const char *pubkeyfile, struct diocskerneldump_arg *kdap)
216480f31c2SKonrad Witaszczyk {
217480f31c2SKonrad Witaszczyk 	FILE *fp;
218480f31c2SKonrad Witaszczyk 	RSA *pubkey;
219480f31c2SKonrad Witaszczyk 
220480f31c2SKonrad Witaszczyk 	assert(pubkeyfile != NULL);
2210ff40d3dSMark Johnston 	assert(kdap != NULL);
222480f31c2SKonrad Witaszczyk 
223480f31c2SKonrad Witaszczyk 	fp = NULL;
224480f31c2SKonrad Witaszczyk 	pubkey = NULL;
225480f31c2SKonrad Witaszczyk 
226480f31c2SKonrad Witaszczyk 	fp = fopen(pubkeyfile, "r");
227480f31c2SKonrad Witaszczyk 	if (fp == NULL)
228480f31c2SKonrad Witaszczyk 		err(1, "Unable to open %s", pubkeyfile);
229480f31c2SKonrad Witaszczyk 
230480f31c2SKonrad Witaszczyk 	if (cap_enter() < 0 && errno != ENOSYS)
231480f31c2SKonrad Witaszczyk 		err(1, "Unable to enter capability mode");
232480f31c2SKonrad Witaszczyk 
233480f31c2SKonrad Witaszczyk 	pubkey = RSA_new();
234480f31c2SKonrad Witaszczyk 	if (pubkey == NULL) {
235480f31c2SKonrad Witaszczyk 		errx(1, "Unable to allocate an RSA structure: %s",
236480f31c2SKonrad Witaszczyk 		    ERR_error_string(ERR_get_error(), NULL));
237480f31c2SKonrad Witaszczyk 	}
238480f31c2SKonrad Witaszczyk 
239480f31c2SKonrad Witaszczyk 	pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL);
240480f31c2SKonrad Witaszczyk 	fclose(fp);
241480f31c2SKonrad Witaszczyk 	fp = NULL;
242480f31c2SKonrad Witaszczyk 	if (pubkey == NULL)
243480f31c2SKonrad Witaszczyk 		errx(1, "Unable to read data from %s.", pubkeyfile);
244480f31c2SKonrad Witaszczyk 
2450ff40d3dSMark Johnston 	kdap->kda_encryptedkeysize = RSA_size(pubkey);
2460ff40d3dSMark Johnston 	if (kdap->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) {
247480f31c2SKonrad Witaszczyk 		errx(1, "Public key has to be at most %db long.",
248480f31c2SKonrad Witaszczyk 		    8 * KERNELDUMP_ENCKEY_MAX_SIZE);
249480f31c2SKonrad Witaszczyk 	}
250480f31c2SKonrad Witaszczyk 
2510ff40d3dSMark Johnston 	kdap->kda_encryptedkey = calloc(1, kdap->kda_encryptedkeysize);
2520ff40d3dSMark Johnston 	if (kdap->kda_encryptedkey == NULL)
253480f31c2SKonrad Witaszczyk 		err(1, "Unable to allocate encrypted key");
254480f31c2SKonrad Witaszczyk 
2550ff40d3dSMark Johnston 	kdap->kda_encryption = KERNELDUMP_ENC_AES_256_CBC;
2560ff40d3dSMark Johnston 	arc4random_buf(kdap->kda_key, sizeof(kdap->kda_key));
2570ff40d3dSMark Johnston 	if (RSA_public_encrypt(sizeof(kdap->kda_key), kdap->kda_key,
2580ff40d3dSMark Johnston 	    kdap->kda_encryptedkey, pubkey,
2590ff40d3dSMark Johnston 	    RSA_PKCS1_PADDING) != (int)kdap->kda_encryptedkeysize) {
260480f31c2SKonrad Witaszczyk 		errx(1, "Unable to encrypt the one-time key.");
261480f31c2SKonrad Witaszczyk 	}
262480f31c2SKonrad Witaszczyk 	RSA_free(pubkey);
263480f31c2SKonrad Witaszczyk }
264480f31c2SKonrad Witaszczyk #endif
265480f31c2SKonrad Witaszczyk 
266f6848434SAlfred Perlstein static void
267f6848434SAlfred Perlstein listdumpdev(void)
268f6848434SAlfred Perlstein {
269f6848434SAlfred Perlstein 	char dumpdev[PATH_MAX];
2700ff40d3dSMark Johnston 	struct netdump_conf ndconf;
271f6848434SAlfred Perlstein 	size_t len;
272f6848434SAlfred Perlstein 	const char *sysctlname = "kern.shutdown.dumpdevname";
2730ff40d3dSMark Johnston 	int fd;
274f6848434SAlfred Perlstein 
275f6848434SAlfred Perlstein 	len = sizeof(dumpdev);
276f6848434SAlfred Perlstein 	if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) {
277f6848434SAlfred Perlstein 		if (errno == ENOMEM) {
278f6848434SAlfred Perlstein 			err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n",
279f6848434SAlfred Perlstein 				sysctlname);
280f6848434SAlfred Perlstein 		} else {
281f6848434SAlfred Perlstein 			err(EX_OSERR, "Sysctl get '%s'\n", sysctlname);
282f6848434SAlfred Perlstein 		}
283f6848434SAlfred Perlstein 	}
2840ff40d3dSMark Johnston 	if (strlen(dumpdev) == 0)
2850ff40d3dSMark Johnston 		(void)strlcpy(dumpdev, _PATH_DEVNULL, sizeof(dumpdev));
2860ff40d3dSMark Johnston 
2870ff40d3dSMark Johnston 	if (verbose)
288f6848434SAlfred Perlstein 		printf("kernel dumps on ");
289f6848434SAlfred Perlstein 	printf("%s\n", dumpdev);
2900ff40d3dSMark Johnston 
2910ff40d3dSMark Johnston 	/* If netdump is enabled, print the configuration parameters. */
2920ff40d3dSMark Johnston 	if (verbose) {
2930ff40d3dSMark Johnston 		fd = open(_PATH_NETDUMP, O_RDONLY);
2940ff40d3dSMark Johnston 		if (fd < 0) {
2950ff40d3dSMark Johnston 			if (errno != ENOENT)
2960ff40d3dSMark Johnston 				err(EX_OSERR, "opening %s", _PATH_NETDUMP);
2970ff40d3dSMark Johnston 			return;
298f6848434SAlfred Perlstein 		}
2990ff40d3dSMark Johnston 		if (ioctl(fd, NETDUMPGCONF, &ndconf) != 0) {
3000ff40d3dSMark Johnston 			if (errno != ENXIO)
3010ff40d3dSMark Johnston 				err(EX_OSERR, "ioctl(NETDUMPGCONF)");
3020ff40d3dSMark Johnston 			(void)close(fd);
3030ff40d3dSMark Johnston 			return;
3040ff40d3dSMark Johnston 		}
3050ff40d3dSMark Johnston 
3060ff40d3dSMark Johnston 		printf("server address: %s\n", inet_ntoa(ndconf.ndc_server));
3070ff40d3dSMark Johnston 		printf("client address: %s\n", inet_ntoa(ndconf.ndc_client));
3080ff40d3dSMark Johnston 		printf("gateway address: %s\n", inet_ntoa(ndconf.ndc_gateway));
3090ff40d3dSMark Johnston 		(void)close(fd);
3100ff40d3dSMark Johnston 	}
3110ff40d3dSMark Johnston }
3120ff40d3dSMark Johnston 
3130ff40d3dSMark Johnston static int
3140ff40d3dSMark Johnston opendumpdev(const char *arg, char *dumpdev)
3150ff40d3dSMark Johnston {
3160ff40d3dSMark Johnston 	int fd, i;
3170ff40d3dSMark Johnston 
3180ff40d3dSMark Johnston 	if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
3190ff40d3dSMark Johnston 		strlcpy(dumpdev, arg, PATH_MAX);
3200ff40d3dSMark Johnston 	else {
3210ff40d3dSMark Johnston 		i = snprintf(dumpdev, PATH_MAX, "%s%s", _PATH_DEV, arg);
3220ff40d3dSMark Johnston 		if (i < 0)
3230ff40d3dSMark Johnston 			err(EX_OSERR, "%s", arg);
3240ff40d3dSMark Johnston 		if (i >= PATH_MAX)
3250ff40d3dSMark Johnston 			errc(EX_DATAERR, EINVAL, "%s", arg);
3260ff40d3dSMark Johnston 	}
3270ff40d3dSMark Johnston 
3280ff40d3dSMark Johnston 	fd = open(dumpdev, O_RDONLY);
3290ff40d3dSMark Johnston 	if (fd < 0)
3300ff40d3dSMark Johnston 		err(EX_OSFILE, "%s", dumpdev);
3310ff40d3dSMark Johnston 	return (fd);
332f6848434SAlfred Perlstein }
333f6848434SAlfred Perlstein 
33483f9dfabSGarrett Wollman int
335d1a939c1SWarner Losh main(int argc, char *argv[])
33683f9dfabSGarrett Wollman {
3370ff40d3dSMark Johnston 	char dumpdev[PATH_MAX];
3380ff40d3dSMark Johnston 	struct diocskerneldump_arg _kda, *kdap;
3390ff40d3dSMark Johnston 	struct netdump_conf ndconf;
3400ff40d3dSMark Johnston 	struct addrinfo hints, *res;
3410ff40d3dSMark Johnston 	const char *dev, *pubkeyfile, *server, *client, *gateway;
3420ff40d3dSMark Johnston 	int ch, error, fd;
3430ff40d3dSMark Johnston 	bool enable, gzip, list, netdump, zstd;
34483f9dfabSGarrett Wollman 
3450ff40d3dSMark Johnston 	gzip = list = netdump = zstd = false;
3460ff40d3dSMark Johnston 	kdap = NULL;
347480f31c2SKonrad Witaszczyk 	pubkeyfile = NULL;
3480ff40d3dSMark Johnston 	server = client = gateway = NULL;
349480f31c2SKonrad Witaszczyk 
3500ff40d3dSMark Johnston 	while ((ch = getopt(argc, argv, "c:g:k:ls:vZz")) != -1)
35183f9dfabSGarrett Wollman 		switch ((char)ch) {
3520ff40d3dSMark Johnston 		case 'c':
3530ff40d3dSMark Johnston 			client = optarg;
3540ff40d3dSMark Johnston 			break;
3550ff40d3dSMark Johnston 		case 'g':
3560ff40d3dSMark Johnston 			gateway = optarg;
3570ff40d3dSMark Johnston 			break;
358480f31c2SKonrad Witaszczyk 		case 'k':
359480f31c2SKonrad Witaszczyk 			pubkeyfile = optarg;
360480f31c2SKonrad Witaszczyk 			break;
361f6848434SAlfred Perlstein 		case 'l':
3620ff40d3dSMark Johnston 			list = true;
3630ff40d3dSMark Johnston 			break;
3640ff40d3dSMark Johnston 		case 's':
3650ff40d3dSMark Johnston 			server = optarg;
366f6848434SAlfred Perlstein 			break;
36783f9dfabSGarrett Wollman 		case 'v':
36883f9dfabSGarrett Wollman 			verbose = 1;
36983f9dfabSGarrett Wollman 			break;
3706026dcd7SMark Johnston 		case 'Z':
3716026dcd7SMark Johnston 			zstd = true;
3726026dcd7SMark Johnston 			break;
37364a16434SMark Johnston 		case 'z':
37464a16434SMark Johnston 			gzip = true;
37564a16434SMark Johnston 			break;
37683f9dfabSGarrett Wollman 		default:
37783f9dfabSGarrett Wollman 			usage();
37883f9dfabSGarrett Wollman 		}
379c0046e26SDag-Erling Smørgrav 
3806026dcd7SMark Johnston 	if (gzip && zstd)
3816026dcd7SMark Johnston 		errx(EX_USAGE, "The -z and -Z options are mutually exclusive.");
3826026dcd7SMark Johnston 
383c0046e26SDag-Erling Smørgrav 	argc -= optind;
38483f9dfabSGarrett Wollman 	argv += optind;
38583f9dfabSGarrett Wollman 
3860ff40d3dSMark Johnston 	if (list) {
387f6848434SAlfred Perlstein 		listdumpdev();
388f6848434SAlfred Perlstein 		exit(EX_OK);
389f6848434SAlfred Perlstein 	}
390f6848434SAlfred Perlstein 
391c0046e26SDag-Erling Smørgrav 	if (argc != 1)
39283f9dfabSGarrett Wollman 		usage();
39383f9dfabSGarrett Wollman 
394480f31c2SKonrad Witaszczyk #ifndef HAVE_CRYPTO
3950ff40d3dSMark Johnston 	if (pubkeyfile != NULL)
396*21a8e0b1SSean Bruno 		errx(EX_UNAVAILABLE,"Unable to use the public key."
397*21a8e0b1SSean Bruno 				    " Recompile dumpon with OpenSSL support.");
398480f31c2SKonrad Witaszczyk #endif
399480f31c2SKonrad Witaszczyk 
4000ff40d3dSMark Johnston 	if (server != NULL && client != NULL) {
4010ff40d3dSMark Johnston 		enable = true;
4020ff40d3dSMark Johnston 		dev = _PATH_NETDUMP;
4030ff40d3dSMark Johnston 		netdump = true;
4040ff40d3dSMark Johnston 		kdap = &ndconf.ndc_kda;
4050ff40d3dSMark Johnston 	} else if (server == NULL && client == NULL && argc > 0) {
4060ff40d3dSMark Johnston 		enable = strcmp(argv[0], "off") != 0;
4070ff40d3dSMark Johnston 		dev = enable ? argv[0] : _PATH_DEVNULL;
4080ff40d3dSMark Johnston 		netdump = false;
4090ff40d3dSMark Johnston 		kdap = &_kda;
4100ff40d3dSMark Johnston 	} else
4110ff40d3dSMark Johnston 		usage();
41245a9027dSSteven Hartland 
4130ff40d3dSMark Johnston 	fd = opendumpdev(dev, dumpdev);
4140ff40d3dSMark Johnston 	if (!netdump && !gzip)
41564a16434SMark Johnston 		check_size(fd, dumpdev);
41664a16434SMark Johnston 
4170ff40d3dSMark Johnston 	bzero(kdap, sizeof(*kdap));
4180ff40d3dSMark Johnston 	kdap->kda_enable = 0;
4190ff40d3dSMark Johnston 	if (ioctl(fd, DIOCSKERNELDUMP, kdap) != 0)
4200ff40d3dSMark Johnston 		err(EX_OSERR, "ioctl(DIOCSKERNELDUMP)");
4210ff40d3dSMark Johnston 	if (!enable)
4220ff40d3dSMark Johnston 		exit(EX_OK);
4230ff40d3dSMark Johnston 
4240ff40d3dSMark Johnston 	explicit_bzero(kdap, sizeof(*kdap));
4250ff40d3dSMark Johnston 	kdap->kda_enable = 1;
4260ff40d3dSMark Johnston 	kdap->kda_compression = KERNELDUMP_COMP_NONE;
4270ff40d3dSMark Johnston 	if (zstd)
4280ff40d3dSMark Johnston 		kdap->kda_compression = KERNELDUMP_COMP_ZSTD;
4290ff40d3dSMark Johnston 	else if (gzip)
4300ff40d3dSMark Johnston 		kdap->kda_compression = KERNELDUMP_COMP_GZIP;
4310ff40d3dSMark Johnston 
4320ff40d3dSMark Johnston 	if (netdump) {
4330ff40d3dSMark Johnston 		memset(&hints, 0, sizeof(hints));
4340ff40d3dSMark Johnston 		hints.ai_family = AF_INET;
4350ff40d3dSMark Johnston 		hints.ai_protocol = IPPROTO_UDP;
4360ff40d3dSMark Johnston 		res = NULL;
4370ff40d3dSMark Johnston 		error = getaddrinfo(server, NULL, &hints, &res);
4380ff40d3dSMark Johnston 		if (error != 0)
4390ff40d3dSMark Johnston 			err(1, "%s", gai_strerror(error));
4400ff40d3dSMark Johnston 		if (res == NULL)
4410ff40d3dSMark Johnston 			errx(1, "failed to resolve '%s'", server);
4420ff40d3dSMark Johnston 		server = inet_ntoa(
4430ff40d3dSMark Johnston 		    ((struct sockaddr_in *)(void *)res->ai_addr)->sin_addr);
4440ff40d3dSMark Johnston 		freeaddrinfo(res);
4450ff40d3dSMark Johnston 
4460ff40d3dSMark Johnston 		if (strlcpy(ndconf.ndc_iface, argv[0],
4470ff40d3dSMark Johnston 		    sizeof(ndconf.ndc_iface)) >= sizeof(ndconf.ndc_iface))
4480ff40d3dSMark Johnston 			errx(EX_USAGE, "invalid interface name '%s'", argv[0]);
4490ff40d3dSMark Johnston 		if (inet_aton(server, &ndconf.ndc_server) == 0)
4500ff40d3dSMark Johnston 			errx(EX_USAGE, "invalid server address '%s'", server);
4510ff40d3dSMark Johnston 		if (inet_aton(client, &ndconf.ndc_client) == 0)
4520ff40d3dSMark Johnston 			errx(EX_USAGE, "invalid client address '%s'", client);
4530ff40d3dSMark Johnston 
4540ff40d3dSMark Johnston 		if (gateway == NULL)
4550ff40d3dSMark Johnston 			gateway = server;
4560ff40d3dSMark Johnston 		else if (strcmp(gateway, "default") == 0 &&
4570ff40d3dSMark Johnston 		    (gateway = find_gateway(argv[0])) == NULL)
4580ff40d3dSMark Johnston 			errx(EX_NOHOST,
4590ff40d3dSMark Johnston 			    "failed to look up next-hop router for %s", server);
4600ff40d3dSMark Johnston 		if (inet_aton(gateway, &ndconf.ndc_gateway) == 0)
4610ff40d3dSMark Johnston 			errx(EX_USAGE, "invalid gateway address '%s'", gateway);
462480f31c2SKonrad Witaszczyk 
463480f31c2SKonrad Witaszczyk #ifdef HAVE_CRYPTO
464480f31c2SKonrad Witaszczyk 		if (pubkeyfile != NULL)
4650ff40d3dSMark Johnston 			genkey(pubkeyfile, kdap);
466480f31c2SKonrad Witaszczyk #endif
4670ff40d3dSMark Johnston 		error = ioctl(fd, NETDUMPSCONF, &ndconf);
4680ff40d3dSMark Johnston 		if (error != 0)
4690ff40d3dSMark Johnston 			error = errno;
4700ff40d3dSMark Johnston 		explicit_bzero(kdap->kda_encryptedkey,
4710ff40d3dSMark Johnston 		    kdap->kda_encryptedkeysize);
4720ff40d3dSMark Johnston 		free(kdap->kda_encryptedkey);
4730ff40d3dSMark Johnston 		explicit_bzero(kdap, sizeof(*kdap));
4740ff40d3dSMark Johnston 		if (error != 0)
4750ff40d3dSMark Johnston 			errc(EX_OSERR, error, "ioctl(NETDUMPSCONF)");
47683f9dfabSGarrett Wollman 	} else {
4770ff40d3dSMark Johnston #ifdef HAVE_CRYPTO
4780ff40d3dSMark Johnston 		if (pubkeyfile != NULL)
4790ff40d3dSMark Johnston 			genkey(pubkeyfile, kdap);
4800ff40d3dSMark Johnston #endif
4810ff40d3dSMark Johnston 		error = ioctl(fd, DIOCSKERNELDUMP, kdap);
4820ff40d3dSMark Johnston 		if (error != 0)
4830ff40d3dSMark Johnston 			error = errno;
4840ff40d3dSMark Johnston 		explicit_bzero(kdap->kda_encryptedkey,
4850ff40d3dSMark Johnston 		    kdap->kda_encryptedkeysize);
4860ff40d3dSMark Johnston 		free(kdap->kda_encryptedkey);
4870ff40d3dSMark Johnston 		explicit_bzero(kdap, sizeof(*kdap));
4880ff40d3dSMark Johnston 		if (error != 0)
4890ff40d3dSMark Johnston 			errc(EX_OSERR, error, "ioctl(DIOCSKERNELDUMP)");
49083f9dfabSGarrett Wollman 	}
4910ff40d3dSMark Johnston 	if (verbose)
4920ff40d3dSMark Johnston 		printf("kernel dumps on %s\n", dumpdev);
49383f9dfabSGarrett Wollman 
4940ff40d3dSMark Johnston 	exit(EX_OK);
49583f9dfabSGarrett Wollman }
496