1 /*	$NetBSD: setkey.c,v 1.15 2011/05/27 18:00:21 drochner 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 ((fp = fopen(optarg, "r")) == NULL) {
169 				err(1, "fopen");
170 				/*NOTREACHED*/
171 			}
172 			break;
173 		case 'D':
174 			f_mode = MODE_CMDDUMP;
175 			break;
176 		case 'F':
177 			f_mode = MODE_CMDFLUSH;
178 			break;
179 		case 'a':
180 			f_all = 1;
181 			break;
182 		case 'l':
183 			f_forever = 1;
184 			break;
185 		case 'n':
186 			f_notreally = 1;
187 			break;
188 #ifdef __NetBSD__
189 		case 'h':
190 #endif
191 		case 'H':
192 			f_hexdump = 1;
193 			break;
194 		case 'x':
195 			f_mode = MODE_PROMISC;
196 			f_tflag++;
197 			break;
198 		case 'P':
199 			f_policy = 1;
200 			break;
201 		case 'p':
202 			f_withports = 1;
203 			break;
204 		case 'v':
205 			f_verbose = 1;
206 			break;
207 		case 'r':
208 #ifdef HAVE_POLICY_FWD
209 			f_rfcmode = 1;
210 #else
211 			rkwarn();
212 #endif
213 			break;
214 		case 'k':
215 #ifdef HAVE_POLICY_FWD
216 			f_rfcmode = 0;
217 #else
218 			rkwarn();
219 #endif
220 			break;
221 		case 'V':
222 			usage(1);
223 			break;
224 			/*NOTREACHED*/
225 #ifndef __NetBSD__
226 		case 'h':
227 #endif
228 		case '?':
229 		default:
230 			usage(0);
231 			/*NOTREACHED*/
232 		}
233 	}
234 
235 	argc -= optind;
236 	argv += optind;
237 
238 	if (argc > 0) {
239 		while (argc--)
240 			if (fileproc(*argv++) < 0) {
241 				err(1, "%s", argv[-1]);
242 				/*NOTREACHED*/
243 			}
244 		exit(0);
245 	}
246 
247 	so = pfkey_open();
248 	if (so < 0) {
249 		perror("pfkey_open");
250 		exit(1);
251 	}
252 
253 	switch (f_mode) {
254 	case MODE_CMDDUMP:
255 		sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP);
256 		break;
257 	case MODE_CMDFLUSH:
258 		sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
259 		break;
260 	case MODE_SCRIPT:
261 		if (get_supported() < 0) {
262 			errx(1, "%s", ipsec_strerror());
263 			/*NOTREACHED*/
264 		}
265 		if (parse(&fp))
266 			exit (1);
267 		break;
268 	case MODE_STDIN:
269 		if (get_supported() < 0) {
270 			errx(1, "%s", ipsec_strerror());
271 			/*NOTREACHED*/
272 		}
273 		stdin_loop();
274 		break;
275 	case MODE_PROMISC:
276 		promisc();
277 		/*NOTREACHED*/
278 	default:
279 		usage(0);
280 		/*NOTREACHED*/
281 	}
282 
283 	exit(0);
284 }
285 
286 int
287 get_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 
299 void
300 stdin_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 
361 void
362 sendkeyshort(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 
381 void
382 promisc()
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  */
452 u_int32_t *
453 sendkeymsg_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 
608 int
609 sendkeymsg(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();
633 again:
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 
682 end:
683 	return (0);
684 }
685 
686 int
687 postproc(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
787 int
788 verifypriority(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 
819 int
820 fileproc(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 /*------------------------------------------------------------*/
870 static const char *satype[] = {
871 	NULL, NULL, "ah", "esp"
872 };
873 static const char *sastate[] = {
874 	"L", "M", "D", "d"
875 };
876 static 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 
895 const char *
896 numstr(x)
897 	int x;
898 {
899 	static char buf[20];
900 	snprintf(buf, sizeof(buf), "#%d", x);
901 	return buf;
902 }
903 
904 void
905 shortdump_hdr()
906 {
907 	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
908 		"time", "p", "s", "spi", "ltime", "src", "dst");
909 }
910 
911 void
912 shortdump(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  */
998 static void
999 printdate()
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  */
1027 int32_t
1028 gmt2local(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