10SN/A/*	$NetBSD: setkey.c,v 1.14 2009/08/06 04:44:43 tteras Exp $	*/
29330SN/A
30SN/A/*	$KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $	*/
40SN/A
50SN/A/*
60SN/A * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
72362SN/A * All rights reserved.
80SN/A *
92362SN/A * Redistribution and use in source and binary forms, with or without
100SN/A * modification, are permitted provided that the following conditions
110SN/A * are met:
120SN/A * 1. Redistributions of source code must retain the above copyright
130SN/A *    notice, this list of conditions and the following disclaimer.
140SN/A * 2. Redistributions in binary form must reproduce the above copyright
150SN/A *    notice, this list of conditions and the following disclaimer in the
160SN/A *    documentation and/or other materials provided with the distribution.
170SN/A * 3. Neither the name of the project nor the names of its contributors
180SN/A *    may be used to endorse or promote products derived from this software
190SN/A *    without specific prior written permission.
200SN/A *
212362SN/A * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
222362SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232362SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
240SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
250SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
260SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
270SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
280SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
290SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
300SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
310SN/A * SUCH DAMAGE.
320SN/A */
330SN/A
340SN/A#ifdef HAVE_CONFIG_H
350SN/A#include "config.h"
360SN/A#endif
370SN/A
380SN/A#include <sys/types.h>
390SN/A#include <sys/param.h>
4017338Smli#include <sys/socket.h>
410SN/A#include <sys/time.h>
420SN/A#include <sys/stat.h>
430SN/A#include <sys/sysctl.h>
440SN/A#include <err.h>
450SN/A#include <netinet/in.h>
460SN/A#include <net/pfkeyv2.h>
470SN/A#include PATH_IPSEC_H
480SN/A
490SN/A#include <stdio.h>
500SN/A#include <stdlib.h>
510SN/A#include <limits.h>
520SN/A#include <string.h>
530SN/A#include <ctype.h>
540SN/A#include <unistd.h>
550SN/A#include <errno.h>
560SN/A#include <netdb.h>
570SN/A#include <fcntl.h>
580SN/A#include <dirent.h>
590SN/A#include <time.h>
601796SN/A
611796SN/A#ifdef HAVE_READLINE
620SN/A#include <readline/readline.h>
631796SN/A#include <readline/history.h>
641796SN/A#endif
651796SN/A
660SN/A#include "config.h"
670SN/A#include "libpfkey.h"
680SN/A#include "package_version.h"
691796SN/A#define extern /* so that variables in extern.h are not extern... */
701959SN/A#include "extern.h"
711796SN/A
721796SN/A#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0')
731796SN/A
741796SN/Avoid usage __P((int));
757365SN/Aint main __P((int, char **));
761796SN/Aint get_supported __P((void));
771796SN/Avoid sendkeyshort __P((u_int));
780SN/Avoid promisc __P((void));
791796SN/Aint postproc __P((struct sadb_msg *, int));
801796SN/Aint verifypriority __P((struct sadb_msg *m));
811796SN/Aint fileproc __P((const char *));
821796SN/Aconst char *numstr __P((int));
830SN/Avoid shortdump_hdr __P((void));
840SN/Avoid shortdump __P((struct sadb_msg *));
850SN/Astatic void printdate __P((void));
860SN/Astatic int32_t gmt2local __P((time_t));
870SN/Avoid stdin_loop __P((void));
880SN/A
890SN/A#define MODE_SCRIPT	1
901796SN/A#define MODE_CMDDUMP	2
911796SN/A#define MODE_CMDFLUSH	3
921796SN/A#define MODE_PROMISC	4
931796SN/A#define MODE_STDIN	5
941796SN/A
951796SN/Aint so;
961796SN/A
971796SN/Aint f_forever = 0;
981796SN/Aint f_all = 0;
991796SN/Aint f_verbose = 0;
1001796SN/Aint f_mode = 0;
1011796SN/Aint f_cmddump = 0;
1021796SN/Aint f_policy = 0;
1031796SN/Aint f_hexdump = 0;
1041796SN/Aint f_tflag = 0;
1057365SN/Aint f_notreally = 0;
1061796SN/Aint f_withports = 0;
1071796SN/A#ifdef HAVE_POLICY_FWD
1081796SN/Aint f_rfcmode = 1;
1090SN/A#define RK_OPTS "rk"
1100SN/A#else
1110SN/Aint f_rkwarn = 0;
1121796SN/A#define RK_OPTS ""
1131796SN/Astatic void rkwarn(void);
1141796SN/Astatic void
1151796SN/Arkwarn(void)
1161796SN/A{
1171796SN/A	if (!f_rkwarn) {
1181959SN/A		f_rkwarn = 1;
1191796SN/A		printf("warning: -r and -k options are not supported in this environment\n");
1201796SN/A	}
1211796SN/A}
1221796SN/A
1231796SN/A#endif
1241796SN/Astatic time_t thiszone;
1251796SN/A
1261796SN/Avoid
1271796SN/Ausage(int only_version)
1281796SN/A{
1291796SN/A	printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL);
1301796SN/A	if (! only_version) {
1311796SN/A		printf("usage: setkey [-v" RK_OPTS "] file ...\n");
1321796SN/A		printf("       setkey [-nv" RK_OPTS "] -c\n");
1330SN/A		printf("       setkey [-nv" RK_OPTS "] -f filename\n");
1340SN/A		printf("       setkey [-Palpv" RK_OPTS "] -D\n");
1351796SN/A		printf("       setkey [-Pv] -F\n");
1361796SN/A		printf("       setkey [-H] -x\n");
1371796SN/A		printf("       setkey [-V] [-h]\n");
1381796SN/A	}
1390SN/A	exit(1);
1400SN/A}
1410SN/A
1420SN/Aint
1431796SN/Amain(argc, argv)
1440SN/A	int argc;
1450SN/A	char **argv;
1460SN/A{
1470SN/A	FILE *fp = stdin;
1481796SN/A	int c;
1491796SN/A
1501796SN/A	if (argc == 1) {
1511796SN/A		usage(0);
1521796SN/A		/* NOTREACHED */
1531796SN/A	}
1541796SN/A
1551959SN/A	thiszone = gmt2local(0);
1561796SN/A
1571796SN/A	while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) {
1581796SN/A		switch (c) {
1591796SN/A		case 'c':
1601796SN/A			f_mode = MODE_STDIN;
1611796SN/A#ifdef HAVE_READLINE
1621796SN/A			/* disable filename completion */
1631796SN/A			rl_bind_key('\t', rl_insert);
1641796SN/A#endif
1651796SN/A			break;
1661796SN/A		case 'f':
1670SN/A			f_mode = MODE_SCRIPT;
1680SN/A			if ((fp = fopen(optarg, "r")) == NULL) {
1691796SN/A				err(1, "fopen");
1701796SN/A				/*NOTREACHED*/
1711796SN/A			}
1721796SN/A			break;
1730SN/A		case 'D':
1740SN/A			f_mode = MODE_CMDDUMP;
1750SN/A			break;
1761796SN/A		case 'F':
1770SN/A			f_mode = MODE_CMDFLUSH;
1780SN/A			break;
1790SN/A		case 'a':
1800SN/A			f_all = 1;
1810SN/A			break;
1820SN/A		case 'l':
1830SN/A			f_forever = 1;
1840SN/A			break;
1850SN/A		case 'n':
1860SN/A			f_notreally = 1;
1870SN/A			break;
1880SN/A#ifdef __NetBSD__
1890SN/A		case 'h':
1900SN/A#endif
1910SN/A		case 'H':
1920SN/A			f_hexdump = 1;
1930SN/A			break;
1940SN/A		case 'x':
1950SN/A			f_mode = MODE_PROMISC;
1960SN/A			f_tflag++;
1970SN/A			break;
1980SN/A		case 'P':
1990SN/A			f_policy = 1;
2000SN/A			break;
2010SN/A		case 'p':
2020SN/A			f_withports = 1;
2030SN/A			break;
2040SN/A		case 'v':
2050SN/A			f_verbose = 1;
2060SN/A			break;
2070SN/A		case 'r':
2080SN/A#ifdef HAVE_POLICY_FWD
2090SN/A			f_rfcmode = 1;
2103897SN/A#else
2113897SN/A			rkwarn();
2123897SN/A#endif
2130SN/A			break;
2140SN/A		case 'k':
2150SN/A#ifdef HAVE_POLICY_FWD
2160SN/A			f_rfcmode = 0;
2170SN/A#else
2180SN/A			rkwarn();
2190SN/A#endif
2200SN/A			break;
2210SN/A		case 'V':
2220SN/A			usage(1);
2230SN/A			break;
2240SN/A			/*NOTREACHED*/
2250SN/A#ifndef __NetBSD__
2260SN/A		case 'h':
2270SN/A#endif
2280SN/A		case '?':
2290SN/A		default:
2300SN/A			usage(0);
2310SN/A			/*NOTREACHED*/
2320SN/A		}
2330SN/A	}
2340SN/A
2350SN/A	argc -= optind;
2360SN/A	argv += optind;
2370SN/A
2380SN/A	if (argc > 0) {
2390SN/A		while (argc--)
2400SN/A			if (fileproc(*argv++) < 0) {
2410SN/A				err(1, "%s", argv[-1]);
2420SN/A				/*NOTREACHED*/
2430SN/A			}
2440SN/A		exit(0);
2450SN/A	}
2460SN/A
2470SN/A	so = pfkey_open();
2480SN/A	if (so < 0) {
2490SN/A		perror("pfkey_open");
2500SN/A		exit(1);
2510SN/A	}
2520SN/A
2530SN/A	switch (f_mode) {
2540SN/A	case MODE_CMDDUMP:
2550SN/A		sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP);
2560SN/A		break;
2571796SN/A	case MODE_CMDFLUSH:
2581796SN/A		sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
2591796SN/A		break;
2601796SN/A	case MODE_SCRIPT:
2611959SN/A		if (get_supported() < 0) {
2621796SN/A			errx(1, "%s", ipsec_strerror());
2631959SN/A			/*NOTREACHED*/
2641959SN/A		}
2651796SN/A		if (parse(&fp))
2661796SN/A			exit (1);
2671796SN/A		break;
2681796SN/A	case MODE_STDIN:
2691796SN/A		if (get_supported() < 0) {
2701796SN/A			errx(1, "%s", ipsec_strerror());
2711796SN/A			/*NOTREACHED*/
2721796SN/A		}
2731796SN/A		stdin_loop();
2741796SN/A		break;
2751796SN/A	case MODE_PROMISC:
2761796SN/A		promisc();
2771796SN/A		/*NOTREACHED*/
2781796SN/A	default:
2791796SN/A		usage(0);
2801796SN/A		/*NOTREACHED*/
2811796SN/A	}
2821796SN/A
2831796SN/A	exit(0);
2841796SN/A}
2850SN/A
286int
287get_supported()
288{
289
290	if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0)
291		return -1;
292
293	if (pfkey_recv_register(so) < 0)
294		return -1;
295
296	return (0);
297}
298
299void
300stdin_loop()
301{
302	char line[1024], *semicolon, *comment;
303	size_t linelen = 0;
304
305	memset (line, 0, sizeof(line));
306
307	parse_init();
308	while (1) {
309#ifdef HAVE_READLINE
310		char *rbuf;
311		rbuf = readline ("");
312		if (! rbuf)
313			break;
314#else
315		char rbuf[1024];
316		rbuf[0] = '\0';
317		if (fgets(rbuf, sizeof(rbuf), stdin) == NULL)
318			break;
319		if (rbuf[strlen(rbuf)-1] == '\n')
320			rbuf[strlen(rbuf)-1] = '\0';
321#endif
322		comment = strchr(rbuf, '#');
323		if (comment)
324			*comment = '\0';
325
326		if (!rbuf[0])
327			continue;
328
329		linelen += snprintf (&line[linelen], sizeof(line) - linelen,
330				     "%s%s", linelen > 0 ? " " : "", rbuf);
331
332		semicolon = strchr(line, ';');
333		while (semicolon) {
334			char saved_char = *++semicolon;
335			*semicolon = '\0';
336#ifdef HAVE_READLINE
337			add_history (line);
338#endif
339
340#ifdef HAVE_PFKEY_POLICY_PRIORITY
341			last_msg_type = -1;  /* invalid message type */
342#endif
343
344			parse_string (line);
345			if (exit_now)
346				return;
347			if (saved_char) {
348				*semicolon = saved_char;
349				linelen = strlen (semicolon);
350				memmove (line, semicolon, linelen + 1);
351				semicolon = strchr(line, ';');
352			}
353			else {
354				semicolon = NULL;
355				linelen = 0;
356			}
357		}
358	}
359}
360
361void
362sendkeyshort(type)
363        u_int type;
364{
365	struct sadb_msg msg;
366
367	msg.sadb_msg_version = PF_KEY_V2;
368	msg.sadb_msg_type = type;
369	msg.sadb_msg_errno = 0;
370	msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
371	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
372	msg.sadb_msg_reserved = 0;
373	msg.sadb_msg_seq = 0;
374	msg.sadb_msg_pid = getpid();
375
376	sendkeymsg((char *)&msg, sizeof(msg));
377
378	return;
379}
380
381void
382promisc()
383{
384	struct sadb_msg msg;
385	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
386	ssize_t l;
387
388	msg.sadb_msg_version = PF_KEY_V2;
389	msg.sadb_msg_type = SADB_X_PROMISC;
390	msg.sadb_msg_errno = 0;
391	msg.sadb_msg_satype = 1;
392	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
393	msg.sadb_msg_reserved = 0;
394	msg.sadb_msg_seq = 0;
395	msg.sadb_msg_pid = getpid();
396
397	if ((l = send(so, &msg, sizeof(msg), 0)) < 0) {
398		err(1, "send");
399		/*NOTREACHED*/
400	}
401
402	while (1) {
403		struct sadb_msg *base;
404
405		if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
406			err(1, "recv");
407			/*NOTREACHED*/
408		}
409
410		if (l != sizeof(*base))
411			continue;
412
413		base = (struct sadb_msg *)rbuf;
414		if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
415				0)) < 0) {
416			err(1, "recv");
417			/*NOTREACHED*/
418		}
419		printdate();
420		if (f_hexdump) {
421			int i;
422			for (i = 0; i < l; i++) {
423				if (i % 16 == 0)
424					printf("%08x: ", i);
425				printf("%02x ", rbuf[i] & 0xff);
426				if (i % 16 == 15)
427					printf("\n");
428			}
429			if (l % 16)
430				printf("\n");
431		}
432		/* adjust base pointer for promisc mode */
433		if (base->sadb_msg_type == SADB_X_PROMISC) {
434			if ((ssize_t)sizeof(*base) < l)
435				base++;
436			else
437				base = NULL;
438		}
439		if (base) {
440			kdebug_sadb(base);
441			printf("\n");
442			fflush(stdout);
443		}
444	}
445}
446
447/* Generate 'spi' array with SPIs matching 'satype', 'srcs', and 'dsts'
448 * Return value is dynamically generated array of SPIs, also number of
449 * SPIs through num_spi pointer.
450 * On any error, set *num_spi to 0 and return NULL.
451 */
452u_int32_t *
453sendkeymsg_spigrep(satype, srcs, dsts, num_spi)
454	unsigned int satype;
455	struct addrinfo *srcs;
456	struct addrinfo *dsts;
457	int *num_spi;
458{
459	struct sadb_msg msg, *m;
460	char *buf;
461	size_t len;
462	ssize_t l;
463	u_char rbuf[1024 * 32];
464	caddr_t mhp[SADB_EXT_MAX + 1];
465	struct sadb_address *saddr;
466	struct sockaddr *s;
467	struct addrinfo *a;
468	struct sadb_sa *sa;
469	u_int32_t *spi = NULL;
470	int max_spi = 0, fail = 0;
471
472	*num_spi = 0;
473
474	if (f_notreally) {
475		return NULL;
476	}
477
478    {
479	struct timeval tv;
480	tv.tv_sec = 1;
481	tv.tv_usec = 0;
482	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
483		perror("setsockopt");
484		return NULL;
485	}
486    }
487
488	msg.sadb_msg_version = PF_KEY_V2;
489	msg.sadb_msg_type = SADB_DUMP;
490	msg.sadb_msg_errno = 0;
491	msg.sadb_msg_satype = satype;
492	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
493	msg.sadb_msg_reserved = 0;
494	msg.sadb_msg_seq = 0;
495	msg.sadb_msg_pid = getpid();
496	buf = (char *)&msg;
497	len = sizeof(msg);
498
499	if (f_verbose) {
500		kdebug_sadb(&msg);
501		printf("\n");
502	}
503	if (f_hexdump) {
504		int i;
505		for (i = 0; i < len; i++) {
506			if (i % 16 == 0)
507				printf("%08x: ", i);
508			printf("%02x ", buf[i] & 0xff);
509			if (i % 16 == 15)
510				printf("\n");
511		}
512		if (len % 16)
513			printf("\n");
514	}
515
516	if ((l = send(so, buf, len, 0)) < 0) {
517		perror("send");
518		return NULL;
519	}
520
521	m = (struct sadb_msg *)rbuf;
522	do {
523		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
524			perror("recv");
525			fail = 1;
526			break;
527		}
528
529		if (PFKEY_UNUNIT64(m->sadb_msg_len) != l) {
530			warnx("invalid keymsg length");
531			fail = 1;
532			break;
533		}
534
535		if (f_verbose) {
536			kdebug_sadb(m);
537			printf("\n");
538		}
539
540		if (m->sadb_msg_type != SADB_DUMP) {
541			warnx("unexpected message type");
542			fail = 1;
543			break;
544		}
545
546		if (m->sadb_msg_errno != 0) {
547			warnx("error encountered");
548			fail = 1;
549			break;
550		}
551
552		/* match satype */
553		if (m->sadb_msg_satype != satype)
554			continue;
555
556		pfkey_align(m, mhp);
557		pfkey_check(mhp);
558
559		/* match src */
560		saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
561		if (saddr == NULL)
562			continue;
563		s = (struct sockaddr *)(saddr + 1);
564		for (a = srcs; a; a = a->ai_next)
565			if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
566				break;
567		if (a == NULL)
568			continue;
569
570		/* match dst */
571		saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
572		if (saddr == NULL)
573			continue;
574		s = (struct sockaddr *)(saddr + 1);
575		for (a = dsts; a; a = a->ai_next)
576			if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
577				break;
578		if (a == NULL)
579			continue;
580
581		if (*num_spi >= max_spi) {
582			max_spi += 512;
583			spi = realloc(spi, max_spi * sizeof(u_int32_t));
584		}
585
586		sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
587		if (sa != NULL)
588			spi[(*num_spi)++] = (u_int32_t)ntohl(sa->sadb_sa_spi);
589
590		m = (struct sadb_msg *)((caddr_t)m + PFKEY_UNUNIT64(m->sadb_msg_len));
591
592		if (f_verbose) {
593			kdebug_sadb(m);
594			printf("\n");
595		}
596
597	} while (m->sadb_msg_seq);
598
599	if (fail) {
600		free(spi);
601		*num_spi = 0;
602		return NULL;
603	}
604
605	return spi;
606}
607
608int
609sendkeymsg(buf, len)
610	char *buf;
611	size_t len;
612{
613	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
614	ssize_t l;
615	struct sadb_msg *msg;
616
617	if (f_notreally) {
618		goto end;
619	}
620
621    {
622	struct timeval tv;
623	tv.tv_sec = 1;
624	tv.tv_usec = 0;
625	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
626		perror("setsockopt");
627		goto end;
628	}
629    }
630
631	if (f_forever)
632		shortdump_hdr();
633again:
634	if (f_verbose) {
635		kdebug_sadb((struct sadb_msg *)buf);
636		printf("\n");
637	}
638	if (f_hexdump) {
639		int i;
640		for (i = 0; i < len; i++) {
641			if (i % 16 == 0)
642				printf("%08x: ", i);
643			printf("%02x ", buf[i] & 0xff);
644			if (i % 16 == 15)
645				printf("\n");
646		}
647		if (len % 16)
648			printf("\n");
649	}
650
651	if ((l = send(so, buf, len, 0)) < 0) {
652		perror("send");
653		goto end;
654	}
655
656	msg = (struct sadb_msg *)rbuf;
657	do {
658		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
659			perror("recv");
660			goto end;
661		}
662
663		if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) {
664			warnx("invalid keymsg length");
665			break;
666		}
667
668		if (f_verbose) {
669			kdebug_sadb(msg);
670			printf("\n");
671		}
672		if (postproc(msg, l) < 0)
673			break;
674	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);
675
676	if (f_forever) {
677		fflush(stdout);
678		sleep(1);
679		goto again;
680	}
681
682end:
683	return (0);
684}
685
686int
687postproc(msg, len)
688	struct sadb_msg *msg;
689	int len;
690{
691#ifdef HAVE_PFKEY_POLICY_PRIORITY
692	static int priority_support_check = 0;
693#endif
694
695	if (msg->sadb_msg_errno != 0) {
696		char inf[80];
697		const char *errmsg = NULL;
698
699		if (f_mode == MODE_SCRIPT)
700			snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
701		else
702			inf[0] = '\0';
703
704		switch (msg->sadb_msg_errno) {
705		case ENOENT:
706			switch (msg->sadb_msg_type) {
707			case SADB_DELETE:
708			case SADB_GET:
709			case SADB_X_SPDDELETE:
710				errmsg = "No entry";
711				break;
712			case SADB_DUMP:
713				errmsg = "No SAD entries";
714				break;
715			case SADB_X_SPDDUMP:
716				errmsg = "No SPD entries";
717				break;
718			}
719			break;
720		default:
721			errmsg = strerror(msg->sadb_msg_errno);
722		}
723		printf("%s%s.\n", inf, errmsg);
724		return (-1);
725	}
726
727	switch (msg->sadb_msg_type) {
728	case SADB_GET:
729		if (f_withports)
730			pfkey_sadump_withports(msg);
731		else
732			pfkey_sadump(msg);
733		break;
734
735	case SADB_DUMP:
736		/* filter out DEAD SAs */
737		if (!f_all) {
738			caddr_t mhp[SADB_EXT_MAX + 1];
739			struct sadb_sa *sa;
740			pfkey_align(msg, mhp);
741			pfkey_check(mhp);
742			if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
743				if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
744					break;
745			}
746		}
747		if (f_forever) {
748			/* TODO: f_withports */
749			shortdump(msg);
750		} else {
751			if (f_withports)
752				pfkey_sadump_withports(msg);
753			else
754				pfkey_sadump(msg);
755		}
756		break;
757
758	case SADB_X_SPDGET:
759		if (f_withports)
760			pfkey_spdump_withports(msg);
761		else
762			pfkey_spdump(msg);
763		break;
764
765	case SADB_X_SPDDUMP:
766		if (f_withports)
767			pfkey_spdump_withports(msg);
768		else
769			pfkey_spdump(msg);
770		break;
771#ifdef HAVE_PFKEY_POLICY_PRIORITY
772	case SADB_X_SPDADD:
773		if (last_msg_type == SADB_X_SPDADD && last_priority != 0 &&
774		    msg->sadb_msg_pid == getpid() && !priority_support_check) {
775			priority_support_check = 1;
776			if (!verifypriority(msg))
777				printf ("WARNING: Kernel does not support policy priorities\n");
778		}
779		break;
780#endif
781	}
782
783	return (0);
784}
785
786#ifdef HAVE_PFKEY_POLICY_PRIORITY
787int
788verifypriority(m)
789	struct sadb_msg *m;
790{
791	caddr_t mhp[SADB_EXT_MAX + 1];
792	struct sadb_x_policy *xpl;
793
794	/* check pfkey message. */
795	if (pfkey_align(m, mhp)) {
796		printf("(%s\n", ipsec_strerror());
797		return 0;
798	}
799	if (pfkey_check(mhp)) {
800		printf("%s\n", ipsec_strerror());
801		return 0;
802	}
803
804	xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY];
805
806	if (xpl == NULL) {
807		printf("no X_POLICY extension.\n");
808		return 0;
809	}
810
811	/* now make sure they match */
812	if (last_priority != xpl->sadb_x_policy_priority)
813		return 0;
814
815	return 1;
816}
817#endif
818
819int
820fileproc(filename)
821	const char *filename;
822{
823	int fd;
824	ssize_t len, l;
825	u_char *p, *ep;
826	struct sadb_msg *msg;
827	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
828
829	fd = open(filename, O_RDONLY);
830	if (fd < 0)
831		return -1;
832
833	l = 0;
834	while (1) {
835		len = read(fd, rbuf + l, sizeof(rbuf) - l);
836		if (len < 0) {
837			close(fd);
838			return -1;
839		} else if (len == 0)
840			break;
841		l += len;
842	}
843
844	if (l < sizeof(struct sadb_msg)) {
845		close(fd);
846		errno = EINVAL;
847		return -1;
848	}
849	close(fd);
850
851	p = rbuf;
852	ep = rbuf + l;
853
854	while (p < ep) {
855		msg = (struct sadb_msg *)p;
856		len = PFKEY_UNUNIT64(msg->sadb_msg_len);
857		if (f_verbose) {
858			kdebug_sadb((struct sadb_msg *)msg);
859			printf("\n");
860		}
861		postproc(msg, len);
862		p += len;
863	}
864
865	return (0);
866}
867
868
869/*------------------------------------------------------------*/
870static const char *satype[] = {
871	NULL, NULL, "ah", "esp"
872};
873static const char *sastate[] = {
874	"L", "M", "D", "d"
875};
876static const char *ipproto[] = {
877/*0*/	"ip", "icmp", "igmp", "ggp", "ip4",
878	NULL, "tcp", NULL, "egp", NULL,
879/*10*/	NULL, NULL, NULL, NULL, NULL,
880	NULL, NULL, "udp", NULL, NULL,
881/*20*/	NULL, NULL, "idp", NULL, NULL,
882	NULL, NULL, NULL, NULL, "tp",
883/*30*/	NULL, NULL, NULL, NULL, NULL,
884	NULL, NULL, NULL, NULL, NULL,
885/*40*/	NULL, "ip6", NULL, "rt6", "frag6",
886	NULL, "rsvp", "gre", NULL, NULL,
887/*50*/	"esp", "ah", NULL, NULL, NULL,
888	NULL, NULL, NULL, "icmp6", "none",
889/*60*/	"dst6",
890};
891
892#define STR_OR_ID(x, tab) \
893	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
894
895const char *
896numstr(x)
897	int x;
898{
899	static char buf[20];
900	snprintf(buf, sizeof(buf), "#%d", x);
901	return buf;
902}
903
904void
905shortdump_hdr()
906{
907	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
908		"time", "p", "s", "spi", "ltime", "src", "dst");
909}
910
911void
912shortdump(msg)
913	struct sadb_msg *msg;
914{
915	caddr_t mhp[SADB_EXT_MAX + 1];
916	char buf[NI_MAXHOST], pbuf[NI_MAXSERV];
917	struct sadb_sa *sa;
918	struct sadb_address *saddr;
919	struct sadb_lifetime *lts, *lth, *ltc;
920	struct sockaddr *s;
921	u_int t;
922	time_t cur = time(0);
923
924	pfkey_align(msg, mhp);
925	pfkey_check(mhp);
926
927	printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
928
929	printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
930
931	if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
932		printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
933		printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
934	} else
935		printf("%-1s %-8s", "?", "?");
936
937	lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
938	lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
939	ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
940	if (lts && lth && ltc) {
941		if (ltc->sadb_lifetime_addtime == 0)
942			t = (u_long)0;
943		else
944			t = (u_long)(cur - ltc->sadb_lifetime_addtime);
945		if (t >= 1000)
946			strlcpy(buf, " big/", sizeof(buf));
947		else
948			snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
949		printf("%s", buf);
950
951		t = (u_long)lth->sadb_lifetime_addtime;
952		if (t >= 1000)
953			strlcpy(buf, "big", sizeof(buf));
954		else
955			snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
956		printf("%s", buf);
957	} else
958		printf(" ??\?/???");	/* backslash to avoid trigraph ??/ */
959
960	printf(" ");
961
962	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
963		if (saddr->sadb_address_proto)
964			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
965		s = (struct sockaddr *)(saddr + 1);
966		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
967			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
968		if (strcmp(pbuf, "0") != 0)
969			printf("%s[%s]", buf, pbuf);
970		else
971			printf("%s", buf);
972	} else
973		printf("?");
974
975	printf(" -> ");
976
977	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
978		if (saddr->sadb_address_proto)
979			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
980
981		s = (struct sockaddr *)(saddr + 1);
982		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
983			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
984		if (strcmp(pbuf, "0") != 0)
985			printf("%s[%s]", buf, pbuf);
986		else
987			printf("%s", buf);
988	} else
989		printf("?");
990
991	printf("\n");
992}
993
994/* From: tcpdump(1):gmt2local.c and util.c */
995/*
996 * Print the timestamp
997 */
998static void
999printdate()
1000{
1001	struct timeval tp;
1002	int s;
1003
1004	if (gettimeofday(&tp, NULL) == -1) {
1005		perror("gettimeofday");
1006		return;
1007	}
1008
1009	if (f_tflag == 1) {
1010		/* Default */
1011		s = (tp.tv_sec + thiszone ) % 86400;
1012		(void)printf("%02d:%02d:%02d.%06u ",
1013		    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec);
1014	} else if (f_tflag > 1) {
1015		/* Unix timeval style */
1016		(void)printf("%u.%06u ",
1017		    (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec);
1018	}
1019
1020	printf("\n");
1021}
1022
1023/*
1024 * Returns the difference between gmt and local time in seconds.
1025 * Use gmtime() and localtime() to keep things simple.
1026 */
1027int32_t
1028gmt2local(time_t t)
1029{
1030	register int dt, dir;
1031	register struct tm *gmt, *loc;
1032	struct tm sgmt;
1033
1034	if (t == 0)
1035		t = time(NULL);
1036	gmt = &sgmt;
1037	*gmt = *gmtime(&t);
1038	loc = localtime(&t);
1039	dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
1040	    (loc->tm_min - gmt->tm_min) * 60;
1041
1042	/*
1043	 * If the year or julian day is different, we span 00:00 GMT
1044	 * and must add or subtract a day. Check the year first to
1045	 * avoid problems when the julian day wraps.
1046	 */
1047	dir = loc->tm_year - gmt->tm_year;
1048	if (dir == 0)
1049		dir = loc->tm_yday - gmt->tm_yday;
1050	dt += dir * 24 * 60 * 60;
1051
1052	return (dt);
1053}
1054