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