1/*	$NetBSD: setkey.c,v 1.22 2020/05/12 16:17:58 christos Exp $	*/
2/*	$KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $	*/
3
4/*
5 * Copyright (c) 2018 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 *    notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 *    notice, this list of conditions and the following disclaimer in the
41 *    documentation and/or other materials provided with the distribution.
42 * 3. Neither the name of the project nor the names of its contributors
43 *    may be used to endorse or promote products derived from this software
44 *    without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58
59#ifdef HAVE_CONFIG_H
60#include "config.h"
61#endif
62
63#include <sys/types.h>
64#include <sys/param.h>
65#include <sys/socket.h>
66#include <sys/time.h>
67#include <sys/stat.h>
68#include <sys/sysctl.h>
69#include <err.h>
70#include <netinet/in.h>
71#include <net/pfkeyv2.h>
72#include PATH_IPSEC_H
73
74#include <stdio.h>
75#include <stdlib.h>
76#include <limits.h>
77#include <string.h>
78#include <ctype.h>
79#include <unistd.h>
80#include <errno.h>
81#include <netdb.h>
82#include <fcntl.h>
83#include <dirent.h>
84#include <time.h>
85
86#ifdef HAVE_READLINE
87#include <readline/readline.h>
88#include <readline/history.h>
89#endif
90
91#include "config.h"
92#include "libpfkey.h"
93#include "package_version.h"
94#include "extern.h"
95
96#define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0')
97
98static int get_supported(void);
99static void sendkeyshort(u_int);
100static void promisc(void);
101static int postproc(struct sadb_msg *, int);
102#ifdef HAVE_PFKEY_POLICY_PRIORITY
103static int verifypriority(struct sadb_msg *);
104#endif
105static int fileproc(const char *);
106static const char *numstr(int);
107static void shortdump_hdr(void);
108static void shortdump(struct sadb_msg *);
109static void printdate(void);
110static int32_t gmt2local(time_t);
111static void stdin_loop(void);
112
113int so;
114
115int f_forever = 0;
116int f_all = 0;
117int f_verbose = 0;
118int f_mode = 0;
119int f_cmddump = 0;
120int f_policy = 0;
121int f_hexdump = 0;
122int f_tflag = 0;
123int f_notreally = 0;
124int f_withports = 0;
125#ifdef HAVE_PFKEY_POLICY_PRIORITY
126int last_msg_type;
127uint32_t last_priority;
128#endif
129#ifdef HAVE_POLICY_FWD
130int f_rfcmode = 1;
131#define RK_OPTS "rk"
132#else
133static int f_rkwarn = 0;
134#define RK_OPTS ""
135static void
136rkwarn(void)
137{
138	if (!f_rkwarn) {
139		f_rkwarn = 1;
140		printf("warning: -r and -k options are not supported in this environment\n");
141	}
142}
143#endif
144
145int lineno;
146const char *filename;
147int exit_now;
148static time_t thiszone;
149
150static void
151usage(int only_version)
152{
153	printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL);
154	if (!only_version) {
155		printf("usage: setkey [-v" RK_OPTS "] file ...\n");
156		printf("       setkey [-nv" RK_OPTS "] -c\n");
157		printf("       setkey [-nv" RK_OPTS "] -f filename\n");
158		printf("       setkey [-Palpv" RK_OPTS "] -D\n");
159		printf("       setkey [-Pv] -F\n");
160		printf("       setkey [-H] -x\n");
161		printf("       setkey [-V] [-h]\n");
162	}
163	exit(1);
164}
165
166int
167main(int argc, char **argv)
168{
169	FILE *fp = stdin;
170	const char *fname = "<stdin>";
171	int c;
172
173	if (argc == 1) {
174		usage(0);
175	}
176
177	thiszone = gmt2local(0);
178
179	while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) {
180		switch (c) {
181		case 'c':
182			f_mode = MODE_STDIN;
183#ifdef HAVE_READLINE
184			/* disable filename completion */
185			rl_bind_key('\t', rl_insert);
186#endif
187			break;
188		case 'f':
189			f_mode = MODE_SCRIPT;
190			if (strcmp(optarg, "-") == 0) {
191				fp = stdin;
192				fname = "<stdin>";
193			} else if ((fp = fopen(optarg, "r")) == NULL) {
194				err(1, "Can't open `%s'", optarg);
195			}
196			fname = optarg;
197			break;
198		case 'D':
199			f_mode = MODE_CMDDUMP;
200			break;
201		case 'F':
202			f_mode = MODE_CMDFLUSH;
203			break;
204		case 'a':
205			f_all = 1;
206			break;
207		case 'l':
208			f_forever = 1;
209			break;
210		case 'n':
211			f_notreally = 1;
212			break;
213#ifdef __NetBSD__
214		case 'h':
215#endif
216		case 'H':
217			f_hexdump = 1;
218			break;
219		case 'x':
220			f_mode = MODE_PROMISC;
221			f_tflag++;
222			break;
223		case 'P':
224			f_policy = 1;
225			break;
226		case 'p':
227			f_withports = 1;
228			break;
229		case 'v':
230			f_verbose = 1;
231			break;
232		case 'r':
233#ifdef HAVE_POLICY_FWD
234			f_rfcmode = 1;
235#else
236			rkwarn();
237#endif
238			break;
239		case 'k':
240#ifdef HAVE_POLICY_FWD
241			f_rfcmode = 0;
242#else
243			rkwarn();
244#endif
245			break;
246		case 'V':
247			usage(1);
248			break;
249#ifndef __NetBSD__
250		case 'h':
251#endif
252		case '?':
253		default:
254			usage(0);
255		}
256	}
257
258	argc -= optind;
259	argv += optind;
260
261	if (argc > 0) {
262		while (argc--) {
263			if (fileproc(*argv++) < 0) {
264				err(1, "%s", argv[-1]);
265			}
266		}
267		exit(0);
268	}
269
270	so = pfkey_open();
271	if (so < 0) {
272		err(1, "pfkey_open");
273	}
274
275	switch (f_mode) {
276	case MODE_CMDDUMP:
277		sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP);
278		break;
279	case MODE_CMDFLUSH:
280		sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
281		break;
282	case MODE_SCRIPT:
283		if (get_supported() < 0) {
284			errx(1, "%s", ipsec_strerror());
285		}
286		if (parse(fname, fp))
287			exit(1);
288		break;
289	case MODE_STDIN:
290		if (get_supported() < 0) {
291			errx(1, "%s", ipsec_strerror());
292		}
293		stdin_loop();
294		break;
295	case MODE_PROMISC:
296		promisc();
297		/* NOTREACHED */
298	default:
299		usage(0);
300	}
301
302	exit(0);
303}
304
305static int
306get_supported(void)
307{
308
309	if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0)
310		return -1;
311
312	if (pfkey_recv_register(so) < 0)
313		return -1;
314
315	return 0;
316}
317
318static void
319stdin_loop(void)
320{
321	char line[1024], *semicolon, *comment;
322	size_t linelen = 0;
323
324	memset(line, 0, sizeof(line));
325
326	parse_init();
327	while (1) {
328#ifdef HAVE_READLINE
329		char *rbuf;
330		rbuf = readline("");
331		if (!rbuf)
332			break;
333#else
334		char rbuf[1024];
335		rbuf[0] = '\0';
336		if (fgets(rbuf, sizeof(rbuf), stdin) == NULL)
337			break;
338		if (rbuf[strlen(rbuf)-1] == '\n')
339			rbuf[strlen(rbuf)-1] = '\0';
340#endif
341		comment = strchr(rbuf, '#');
342		if (comment)
343			*comment = '\0';
344
345		if (!rbuf[0])
346			continue;
347
348		linelen += snprintf(&line[linelen], sizeof(line) - linelen,
349		    "%s%s", linelen > 0 ? " " : "", rbuf);
350
351		semicolon = strchr(line, ';');
352		while (semicolon) {
353			char saved_char = *++semicolon;
354			*semicolon = '\0';
355#ifdef HAVE_READLINE
356			add_history(line);
357#endif
358
359#ifdef HAVE_PFKEY_POLICY_PRIORITY
360			last_msg_type = -1;  /* invalid message type */
361#endif
362
363			parse_string(line);
364			if (exit_now)
365				return;
366			if (saved_char) {
367				*semicolon = saved_char;
368				linelen = strlen(semicolon);
369				memmove(line, semicolon, linelen + 1);
370				semicolon = strchr(line, ';');
371			} else {
372				semicolon = NULL;
373				linelen = 0;
374			}
375		}
376	}
377}
378
379static void
380sendkeyshort(u_int type)
381{
382	struct sadb_msg msg;
383
384	msg.sadb_msg_version = PF_KEY_V2;
385	msg.sadb_msg_type = type;
386	msg.sadb_msg_errno = 0;
387	msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
388	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
389	msg.sadb_msg_reserved = 0;
390	msg.sadb_msg_seq = 0;
391	msg.sadb_msg_pid = getpid();
392
393	sendkeymsg((char *)&msg, sizeof(msg));
394}
395
396static void __dead
397promisc(void)
398{
399	struct sadb_msg msg;
400	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
401	ssize_t l;
402
403	msg.sadb_msg_version = PF_KEY_V2;
404	msg.sadb_msg_type = SADB_X_PROMISC;
405	msg.sadb_msg_errno = 0;
406	msg.sadb_msg_satype = 1;
407	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
408	msg.sadb_msg_reserved = 0;
409	msg.sadb_msg_seq = 0;
410	msg.sadb_msg_pid = getpid();
411
412	if ((l = send(so, &msg, sizeof(msg), 0)) < 0) {
413		err(1, "send");
414	}
415
416	while (1) {
417		struct sadb_msg *base;
418
419		if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
420			err(1, "recv");
421		}
422
423		if (l != sizeof(*base))
424			continue;
425
426		base = (struct sadb_msg *)rbuf;
427		if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
428				0)) < 0) {
429			err(1, "recv");
430		}
431		printdate();
432		if (f_hexdump) {
433			int i;
434			for (i = 0; i < l; i++) {
435				if (i % 16 == 0)
436					printf("%08x: ", i);
437				printf("%02x ", rbuf[i] & 0xff);
438				if (i % 16 == 15)
439					printf("\n");
440			}
441			if (l % 16)
442				printf("\n");
443		}
444		/* adjust base pointer for promisc mode */
445		if (base->sadb_msg_type == SADB_X_PROMISC) {
446			if ((ssize_t)sizeof(*base) < l)
447				base++;
448			else
449				base = NULL;
450		}
451		if (base) {
452			kdebug_sadb(base);
453			printf("\n");
454			fflush(stdout);
455		}
456	}
457}
458
459/*
460 * Generate 'spi' array with SPIs matching 'satype', 'srcs', and 'dsts'.
461 * Return value is dynamically generated array of SPIs, also number of
462 * SPIs through num_spi pointer.
463 * On any error, set *num_spi to 0 and return NULL.
464 */
465uint32_t *
466sendkeymsg_spigrep(unsigned int satype, struct addrinfo *srcs,
467    struct addrinfo *dsts, int *num_spi)
468{
469	struct sadb_msg msg, *m;
470	char *buf;
471	size_t len;
472	ssize_t l;
473	u_char rbuf[1024 * 32];
474	caddr_t mhp[SADB_EXT_MAX + 1];
475	struct sadb_address *saddr;
476	struct sockaddr *s;
477	struct addrinfo *a;
478	struct sadb_sa *sa;
479	uint32_t *spi = NULL;
480	int max_spi = 0, fail = 0;
481
482	*num_spi = 0;
483
484	if (f_notreally) {
485		return NULL;
486	}
487
488    {
489	struct timeval tv;
490	tv.tv_sec = 1;
491	tv.tv_usec = 0;
492	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
493		warn("setsockopt");
494		return NULL;
495	}
496    }
497
498	msg.sadb_msg_version = PF_KEY_V2;
499	msg.sadb_msg_type = SADB_DUMP;
500	msg.sadb_msg_errno = 0;
501	msg.sadb_msg_satype = satype;
502	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
503	msg.sadb_msg_reserved = 0;
504	msg.sadb_msg_seq = 0;
505	msg.sadb_msg_pid = getpid();
506	buf = (char *)&msg;
507	len = sizeof(msg);
508
509	if (f_verbose) {
510		kdebug_sadb(&msg);
511		printf("\n");
512	}
513	if (f_hexdump) {
514		int i;
515		for (i = 0; i < len; i++) {
516			if (i % 16 == 0)
517				printf("%08x: ", i);
518			printf("%02x ", buf[i] & 0xff);
519			if (i % 16 == 15)
520				printf("\n");
521		}
522		if (len % 16)
523			printf("\n");
524	}
525
526	if ((l = send(so, buf, len, 0)) < 0) {
527		warn("send");
528		return NULL;
529	}
530
531	m = (struct sadb_msg *)rbuf;
532	do {
533		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
534			warn("recv");
535			fail = 1;
536			break;
537		}
538
539		if (PFKEY_UNUNIT64(m->sadb_msg_len) != l) {
540			warnx("invalid keymsg length");
541			fail = 1;
542			break;
543		}
544
545		if (f_verbose) {
546			kdebug_sadb(m);
547			printf("\n");
548		}
549
550		if (m->sadb_msg_type != SADB_DUMP) {
551			warnx("unexpected message type");
552			fail = 1;
553			break;
554		}
555
556		if (m->sadb_msg_errno != 0) {
557			warnx("error encountered");
558			fail = 1;
559			break;
560		}
561
562		/* match satype */
563		if (m->sadb_msg_satype != satype)
564			continue;
565
566		pfkey_align(m, mhp);
567		pfkey_check(mhp);
568
569		/* match src */
570		saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
571		if (saddr == NULL)
572			continue;
573		s = (struct sockaddr *)(saddr + 1);
574		for (a = srcs; a; a = a->ai_next)
575			if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
576				break;
577		if (a == NULL)
578			continue;
579
580		/* match dst */
581		saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
582		if (saddr == NULL)
583			continue;
584		s = (struct sockaddr *)(saddr + 1);
585		for (a = dsts; a; a = a->ai_next)
586			if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
587				break;
588		if (a == NULL)
589			continue;
590
591		if (*num_spi >= max_spi) {
592			max_spi += 512;
593			spi = realloc(spi, max_spi * sizeof(uint32_t));
594		}
595
596		sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
597		if (sa != NULL)
598			spi[(*num_spi)++] = (uint32_t)ntohl(sa->sadb_sa_spi);
599
600		m = (struct sadb_msg *)((caddr_t)m + PFKEY_UNUNIT64(m->sadb_msg_len));
601
602		if (f_verbose) {
603			kdebug_sadb(m);
604			printf("\n");
605		}
606
607	} while (m->sadb_msg_seq);
608
609	if (fail) {
610		free(spi);
611		*num_spi = 0;
612		return NULL;
613	}
614
615	return spi;
616}
617
618int
619sendkeymsg(char *buf, size_t len)
620{
621	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
622	ssize_t l;
623	struct sadb_msg *msg;
624
625	if (f_notreally) {
626		goto end;
627	}
628
629    {
630	struct timeval tv;
631	tv.tv_sec = 1;
632	tv.tv_usec = 0;
633	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
634		warn("setsockopt");
635		goto end;
636	}
637    }
638
639	if (f_forever)
640		shortdump_hdr();
641again:
642	if (f_verbose) {
643		kdebug_sadb((struct sadb_msg *)buf);
644		printf("\n");
645	}
646	if (f_hexdump) {
647		int i;
648		for (i = 0; i < len; i++) {
649			if (i % 16 == 0)
650				printf("%08x: ", i);
651			printf("%02x ", buf[i] & 0xff);
652			if (i % 16 == 15)
653				printf("\n");
654		}
655		if (len % 16)
656			printf("\n");
657	}
658
659	if ((l = send(so, buf, len, 0)) < 0) {
660		warn("send");
661		goto end;
662	}
663
664	msg = (struct sadb_msg *)rbuf;
665	do {
666		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
667			warn("recv");
668			goto end;
669		}
670
671		if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) {
672			warnx("invalid keymsg length");
673			break;
674		}
675
676		if (f_verbose) {
677			kdebug_sadb(msg);
678			printf("\n");
679		}
680		if (postproc(msg, l) < 0)
681			break;
682	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);
683
684	if (f_forever) {
685		fflush(stdout);
686		sleep(1);
687		goto again;
688	}
689
690end:
691	return 0;
692}
693
694static int
695postproc(struct sadb_msg *msg, int len)
696{
697#ifdef HAVE_PFKEY_POLICY_PRIORITY
698	static int priority_support_check = 0;
699#endif
700
701	if (msg->sadb_msg_errno != 0) {
702		const char *errmsg = NULL;
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		if (f_mode == MODE_SCRIPT)
724			warnx("%s,%d: %s", filename, lineno, errmsg);
725		else
726			printf("%s.\n", errmsg);
727		return -1;
728	}
729
730	switch (msg->sadb_msg_type) {
731	case SADB_GET:
732		if (f_withports)
733			pfkey_sadump_withports(msg);
734		else
735			pfkey_sadump(msg);
736		break;
737
738	case SADB_DUMP:
739		/* filter out DEAD SAs */
740		if (!f_all) {
741			caddr_t mhp[SADB_EXT_MAX + 1];
742			struct sadb_sa *sa;
743			pfkey_align(msg, mhp);
744			pfkey_check(mhp);
745			if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
746				if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
747					break;
748			}
749		}
750		if (f_forever) {
751			/* TODO: f_withports */
752			shortdump(msg);
753		} else {
754			if (f_withports)
755				pfkey_sadump_withports(msg);
756			else
757				pfkey_sadump(msg);
758		}
759		break;
760
761	case SADB_X_SPDGET:
762		if (f_withports)
763			pfkey_spdump_withports(msg);
764		else
765			pfkey_spdump(msg);
766		break;
767
768	case SADB_X_SPDDUMP:
769		if (f_withports)
770			pfkey_spdump_withports(msg);
771		else
772			pfkey_spdump(msg);
773		break;
774#ifdef HAVE_PFKEY_POLICY_PRIORITY
775	case SADB_X_SPDADD:
776		if (last_msg_type == SADB_X_SPDADD && last_priority != 0 &&
777		    msg->sadb_msg_pid == getpid() && !priority_support_check) {
778			priority_support_check = 1;
779			if (!verifypriority(msg))
780				printf("WARNING: Kernel does not support policy priorities\n");
781		}
782		break;
783#endif
784	}
785
786	return 0;
787}
788
789#ifdef HAVE_PFKEY_POLICY_PRIORITY
790static int
791verifypriority(struct sadb_msg *m)
792{
793	caddr_t mhp[SADB_EXT_MAX + 1];
794	struct sadb_x_policy *xpl;
795
796	/* check pfkey message. */
797	if (pfkey_align(m, mhp)) {
798		if (f_mode == MODE_SCRIPT)
799			warnx("%s", ipsec_strerror());
800		else
801			printf("%s\n", ipsec_strerror());
802		return 0;
803	}
804	if (pfkey_check(mhp)) {
805		if (f_mode == MODE_SCRIPT)
806			warnx("%s", ipsec_strerror());
807		else
808			printf("%s\n", ipsec_strerror());
809		return 0;
810	}
811
812	xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY];
813
814	if (xpl == NULL) {
815		if (f_mode == MODE_SCRIPT)
816			warnx("no X_POLICY extension.");
817		else
818			printf("no X_POLICY extension.\n");
819		return 0;
820	}
821
822	/* now make sure they match */
823	if (last_priority != xpl->sadb_x_policy_priority)
824		return 0;
825
826	return 1;
827}
828#endif
829
830static int
831fileproc(const char *fname)
832{
833	int fd;
834	ssize_t len, l;
835	u_char *p, *ep;
836	struct sadb_msg *msg;
837	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
838
839	fd = open(fname, O_RDONLY);
840	if (fd < 0)
841		return -1;
842
843	l = 0;
844	while (1) {
845		len = read(fd, rbuf + l, sizeof(rbuf) - l);
846		if (len < 0) {
847			close(fd);
848			return -1;
849		} else if (len == 0)
850			break;
851		l += len;
852	}
853
854	if (l < sizeof(struct sadb_msg)) {
855		close(fd);
856		errno = EINVAL;
857		return -1;
858	}
859	close(fd);
860
861	p = rbuf;
862	ep = rbuf + l;
863
864	while (p < ep) {
865		msg = (struct sadb_msg *)p;
866		len = PFKEY_UNUNIT64(msg->sadb_msg_len);
867		if (f_verbose) {
868			kdebug_sadb((struct sadb_msg *)msg);
869			printf("\n");
870		}
871		postproc(msg, len);
872		p += len;
873	}
874
875	return 0;
876}
877
878/* -------------------------------------------------------------------------- */
879
880static const char *satype[] = {
881	NULL, NULL, "ah", "esp"
882};
883static const char *sastate[] = {
884	"L", "M", "D", "d"
885};
886static const char *ipproto[] = {
887/*0*/	"ip", "icmp", "igmp", "ggp", "ip4",
888	NULL, "tcp", NULL, "egp", NULL,
889/*10*/	NULL, NULL, NULL, NULL, NULL,
890	NULL, NULL, "udp", NULL, NULL,
891/*20*/	NULL, NULL, "idp", NULL, NULL,
892	NULL, NULL, NULL, NULL, "tp",
893/*30*/	NULL, NULL, NULL, NULL, NULL,
894	NULL, NULL, NULL, NULL, NULL,
895/*40*/	NULL, "ip6", NULL, "rt6", "frag6",
896	NULL, "rsvp", "gre", NULL, NULL,
897/*50*/	"esp", "ah", NULL, NULL, NULL,
898	NULL, NULL, NULL, "icmp6", "none",
899/*60*/	"dst6",
900};
901
902#define STR_OR_ID(x, tab) \
903	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
904
905static const char *
906numstr(int x)
907{
908	static char buf[20];
909	snprintf(buf, sizeof(buf), "#%d", x);
910	return buf;
911}
912
913static void
914shortdump_hdr(void)
915{
916	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
917	    "time", "p", "s", "spi", "ltime", "src", "dst");
918}
919
920static void
921shortdump(struct sadb_msg *msg)
922{
923	caddr_t mhp[SADB_EXT_MAX + 1];
924	char buf[NI_MAXHOST], pbuf[NI_MAXSERV];
925	struct sadb_sa *sa;
926	struct sadb_address *saddr;
927	struct sadb_lifetime *lts, *lth, *ltc;
928	struct sockaddr *s;
929	u_int t;
930	time_t cur = time(0);
931
932	pfkey_align(msg, mhp);
933	pfkey_check(mhp);
934
935	printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
936
937	printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
938
939	if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
940		printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
941		printf(" %08x", (uint32_t)ntohl(sa->sadb_sa_spi));
942	} else
943		printf("%-1s %-8s", "?", "?");
944
945	lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
946	lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
947	ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
948	if (lts && lth && ltc) {
949		if (ltc->sadb_lifetime_addtime == 0)
950			t = (u_long)0;
951		else
952			t = (u_long)(cur - ltc->sadb_lifetime_addtime);
953		if (t >= 1000)
954			strlcpy(buf, " big/", sizeof(buf));
955		else
956			snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
957		printf("%s", buf);
958
959		t = (u_long)lth->sadb_lifetime_addtime;
960		if (t >= 1000)
961			strlcpy(buf, "big", sizeof(buf));
962		else
963			snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
964		printf("%s", buf);
965	} else
966		printf(" ??\?/???");	/* backslash to avoid trigraph ??/ */
967
968	printf(" ");
969
970	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
971		if (saddr->sadb_address_proto)
972			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
973		s = (struct sockaddr *)(saddr + 1);
974		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
975			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
976		if (strcmp(pbuf, "0") != 0)
977			printf("%s[%s]", buf, pbuf);
978		else
979			printf("%s", buf);
980	} else
981		printf("?");
982
983	printf(" -> ");
984
985	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
986		if (saddr->sadb_address_proto)
987			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
988
989		s = (struct sockaddr *)(saddr + 1);
990		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
991			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
992		if (strcmp(pbuf, "0") != 0)
993			printf("%s[%s]", buf, pbuf);
994		else
995			printf("%s", buf);
996	} else
997		printf("?");
998
999	printf("\n");
1000}
1001
1002/* From: tcpdump(1):gmt2local.c and util.c */
1003/*
1004 * Print the timestamp
1005 */
1006static void
1007printdate(void)
1008{
1009	struct timeval tp;
1010	int s;
1011
1012	if (gettimeofday(&tp, NULL) == -1) {
1013		warn("gettimeofday");
1014		return;
1015	}
1016
1017	if (f_tflag == 1) {
1018		/* Default */
1019		s = (tp.tv_sec + thiszone) % 86400;
1020		printf("%02d:%02d:%02d.%06u ",
1021		    s / 3600, (s % 3600) / 60, s % 60, (uint32_t)tp.tv_usec);
1022	} else if (f_tflag > 1) {
1023		/* Unix timeval style */
1024		printf("%u.%06u ", (uint32_t)tp.tv_sec, (uint32_t)tp.tv_usec);
1025	}
1026
1027	printf("\n");
1028}
1029
1030/*
1031 * Returns the difference between gmt and local time in seconds.
1032 * Use gmtime() and localtime() to keep things simple.
1033 */
1034int32_t
1035gmt2local(time_t t)
1036{
1037	register int dt, dir;
1038	register struct tm *gmt, *loc;
1039	struct tm sgmt;
1040
1041	if (t == 0)
1042		t = time(NULL);
1043	gmt = &sgmt;
1044	*gmt = *gmtime(&t);
1045	loc = localtime(&t);
1046	dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
1047	    (loc->tm_min - gmt->tm_min) * 60;
1048
1049	/*
1050	 * If the year or julian day is different, we span 00:00 GMT
1051	 * and must add or subtract a day. Check the year first to
1052	 * avoid problems when the julian day wraps.
1053	 */
1054	dir = loc->tm_year - gmt->tm_year;
1055	if (dir == 0)
1056		dir = loc->tm_yday - gmt->tm_yday;
1057	dt += dir * 24 * 60 * 60;
1058
1059	return dt;
1060}
1061