1 /*	$NetBSD: setkey.c,v 1.7 2005/08/07 09:38:46 manu 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 #ifdef HAVE_NETINET6_IPSEC
48 #  include <netinet6/ipsec.h>
49 #else
50 #  include <netinet/ipsec.h>
51 #endif
52 
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <limits.h>
56 #include <string.h>
57 #include <ctype.h>
58 #include <unistd.h>
59 #include <errno.h>
60 #include <netdb.h>
61 #include <fcntl.h>
62 #include <dirent.h>
63 #include <time.h>
64 
65 #ifdef HAVE_READLINE
66 #include <readline/readline.h>
67 #include <readline/history.h>
68 #endif
69 
70 #include "config.h"
71 #include "libpfkey.h"
72 #include "package_version.h"
73 #define extern /* so that variables in extern.h are not extern... */
74 #include "extern.h"
75 
76 #define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0')
77 
78 void usage __P((int));
79 int main __P((int, char **));
80 int get_supported __P((void));
81 void sendkeyshort __P((u_int));
82 void promisc __P((void));
83 int postproc __P((struct sadb_msg *, int));
84 int verifypriority __P((struct sadb_msg *m));
85 int fileproc __P((const char *));
86 const char *numstr __P((int));
87 void shortdump_hdr __P((void));
88 void shortdump __P((struct sadb_msg *));
89 static void printdate __P((void));
90 static int32_t gmt2local __P((time_t));
91 void stdin_loop __P((void));
92 
93 #define MODE_SCRIPT	1
94 #define MODE_CMDDUMP	2
95 #define MODE_CMDFLUSH	3
96 #define MODE_PROMISC	4
97 #define MODE_STDIN	5
98 
99 int so;
100 
101 int f_forever = 0;
102 int f_all = 0;
103 int f_verbose = 0;
104 int f_mode = 0;
105 int f_cmddump = 0;
106 int f_policy = 0;
107 int f_hexdump = 0;
108 int f_tflag = 0;
109 int f_notreally = 0;
110 int f_withports = 0;
111 #ifdef HAVE_POLICY_FWD
112 int f_rfcmode = 1;
113 #define RK_OPTS "rk"
114 #else
115 int f_rkwarn = 0;
116 #define RK_OPTS ""
117 static void rkwarn(void);
118 static void
119 rkwarn(void)
120 {
121 	if (!f_rkwarn) {
122 		f_rkwarn = 1;
123 		printf("warning: -r and -k options are not supported in this environment\n");
124 	}
125 }
126 
127 #endif
128 static time_t thiszone;
129 
130 void
131 usage(int only_version)
132 {
133 	printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL);
134 	if (! only_version) {
135 		printf("usage: setkey [-v" RK_OPTS "] file ...\n");
136 		printf("       setkey [-nv" RK_OPTS "] -c\n");
137 		printf("       setkey [-nv" RK_OPTS "] -f filename\n");
138 		printf("       setkey [-Palv" RK_OPTS "] -D\n");
139 		printf("       setkey [-Pv] -F\n");
140 		printf("       setkey [-H] -x\n");
141 		printf("       setkey [-V] [-h]\n");
142 	}
143 	exit(1);
144 }
145 
146 int
147 main(argc, argv)
148 	int argc;
149 	char **argv;
150 {
151 	FILE *fp = stdin;
152 	int c;
153 
154 	if (argc == 1) {
155 		usage(0);
156 		/* NOTREACHED */
157 	}
158 
159 	thiszone = gmt2local(0);
160 
161 	while ((c = getopt(argc, argv, "acdf:HlnvxDFPphVrk?")) != -1) {
162 		switch (c) {
163 		case 'c':
164 			f_mode = MODE_STDIN;
165 #ifdef HAVE_READLINE
166 			/* disable filename completion */
167 			rl_bind_key('\t', rl_insert);
168 #endif
169 			break;
170 		case 'f':
171 			f_mode = MODE_SCRIPT;
172 			if ((fp = fopen(optarg, "r")) == NULL) {
173 				err(1, "fopen");
174 				/*NOTREACHED*/
175 			}
176 			break;
177 		case 'D':
178 			f_mode = MODE_CMDDUMP;
179 			break;
180 		case 'F':
181 			f_mode = MODE_CMDFLUSH;
182 			break;
183 		case 'a':
184 			f_all = 1;
185 			break;
186 		case 'l':
187 			f_forever = 1;
188 			break;
189 		case 'n':
190 			f_notreally = 1;
191 			break;
192 #ifdef __NetBSD__
193 		case 'h':
194 #endif
195 		case 'H':
196 			f_hexdump = 1;
197 			break;
198 		case 'x':
199 			f_mode = MODE_PROMISC;
200 			f_tflag++;
201 			break;
202 		case 'P':
203 			f_policy = 1;
204 			break;
205 		case 'p':
206 			f_withports = 1;
207 			break;
208 		case 'v':
209 			f_verbose = 1;
210 			break;
211 		case 'r':
212 #ifdef HAVE_POLICY_FWD
213 			f_rfcmode = 1;
214 #else
215 			rkwarn();
216 #endif
217 			break;
218 		case 'k':
219 #ifdef HAVE_POLICY_FWD
220 			f_rfcmode = 0;
221 #else
222 			rkwarn();
223 #endif
224 			break;
225 		case 'V':
226 			usage(1);
227 			break;
228 			/*NOTREACHED*/
229 #ifndef __NetBSD__
230 		case 'h':
231 #endif
232 		case '?':
233 		default:
234 			usage(0);
235 			/*NOTREACHED*/
236 		}
237 	}
238 
239 	argc -= optind;
240 	argv += optind;
241 
242 	if (argc > 0) {
243 		while (argc--)
244 			if (fileproc(*argv++) < 0) {
245 				err(1, "%s", argv[-1]);
246 				/*NOTREACHED*/
247 			}
248 		exit(0);
249 	}
250 
251 	so = pfkey_open();
252 	if (so < 0) {
253 		perror("pfkey_open");
254 		exit(1);
255 	}
256 
257 	switch (f_mode) {
258 	case MODE_CMDDUMP:
259 		sendkeyshort(f_policy ? SADB_X_SPDDUMP : SADB_DUMP);
260 		break;
261 	case MODE_CMDFLUSH:
262 		sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
263 		break;
264 	case MODE_SCRIPT:
265 		if (get_supported() < 0) {
266 			errx(1, "%s", ipsec_strerror());
267 			/*NOTREACHED*/
268 		}
269 		if (parse(&fp))
270 			exit (1);
271 		break;
272 	case MODE_STDIN:
273 		if (get_supported() < 0) {
274 			errx(1, "%s", ipsec_strerror());
275 			/*NOTREACHED*/
276 		}
277 		stdin_loop();
278 		break;
279 	case MODE_PROMISC:
280 		promisc();
281 		/*NOTREACHED*/
282 	default:
283 		usage(0);
284 		/*NOTREACHED*/
285 	}
286 
287 	exit(0);
288 }
289 
290 int
291 get_supported()
292 {
293 
294 	if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0)
295 		return -1;
296 
297 	if (pfkey_recv_register(so) < 0)
298 		return -1;
299 
300 	return (0);
301 }
302 
303 void
304 stdin_loop()
305 {
306 	char line[1024], *semicolon, *comment;
307 	size_t linelen = 0;
308 
309 	memset (line, 0, sizeof(line));
310 
311 	parse_init();
312 	while (1) {
313 #ifdef HAVE_READLINE
314 		char *rbuf;
315 		rbuf = readline ("");
316 		if (! rbuf)
317 			break;
318 #else
319 		char rbuf[1024];
320 		rbuf[0] = '\0';
321 		fgets (rbuf, sizeof(rbuf), stdin);
322 		if (!rbuf[0])
323 			break;
324 		if (rbuf[strlen(rbuf)-1] == '\n')
325 			rbuf[strlen(rbuf)-1] = '\0';
326 #endif
327 		comment = strchr(rbuf, '#');
328 		if (comment)
329 			*comment = '\0';
330 
331 		if (!rbuf[0])
332 			continue;
333 
334 		linelen += snprintf (&line[linelen], sizeof(line) - linelen,
335 				     "%s%s", linelen > 0 ? " " : "", rbuf);
336 
337 		semicolon = strchr(line, ';');
338 		while (semicolon) {
339 			char saved_char = *++semicolon;
340 			*semicolon = '\0';
341 #ifdef HAVE_READLINE
342 			add_history (line);
343 #endif
344 
345 #ifdef HAVE_PFKEY_POLICY_PRIORITY
346 			last_msg_type = -1;  /* invalid message type */
347 #endif
348 
349 			parse_string (line);
350 			if (exit_now)
351 				return;
352 			if (saved_char) {
353 				*semicolon = saved_char;
354 				linelen = strlen (semicolon);
355 				memmove (line, semicolon, linelen + 1);
356 				semicolon = strchr(line, ';');
357 			}
358 			else {
359 				semicolon = NULL;
360 				linelen = 0;
361 			}
362 		}
363 	}
364 }
365 
366 void
367 sendkeyshort(type)
368         u_int type;
369 {
370 	struct sadb_msg msg;
371 
372 	msg.sadb_msg_version = PF_KEY_V2;
373 	msg.sadb_msg_type = type;
374 	msg.sadb_msg_errno = 0;
375 	msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
376 	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
377 	msg.sadb_msg_reserved = 0;
378 	msg.sadb_msg_seq = 0;
379 	msg.sadb_msg_pid = getpid();
380 
381 	sendkeymsg((char *)&msg, sizeof(msg));
382 
383 	return;
384 }
385 
386 void
387 promisc()
388 {
389 	struct sadb_msg msg;
390 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
391 	ssize_t l;
392 
393 	msg.sadb_msg_version = PF_KEY_V2;
394 	msg.sadb_msg_type = SADB_X_PROMISC;
395 	msg.sadb_msg_errno = 0;
396 	msg.sadb_msg_satype = 1;
397 	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
398 	msg.sadb_msg_reserved = 0;
399 	msg.sadb_msg_seq = 0;
400 	msg.sadb_msg_pid = getpid();
401 
402 	if ((l = send(so, &msg, sizeof(msg), 0)) < 0) {
403 		err(1, "send");
404 		/*NOTREACHED*/
405 	}
406 
407 	while (1) {
408 		struct sadb_msg *base;
409 
410 		if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
411 			err(1, "recv");
412 			/*NOTREACHED*/
413 		}
414 
415 		if (l != sizeof(*base))
416 			continue;
417 
418 		base = (struct sadb_msg *)rbuf;
419 		if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
420 				0)) < 0) {
421 			err(1, "recv");
422 			/*NOTREACHED*/
423 		}
424 		printdate();
425 		if (f_hexdump) {
426 			int i;
427 			for (i = 0; i < l; i++) {
428 				if (i % 16 == 0)
429 					printf("%08x: ", i);
430 				printf("%02x ", rbuf[i] & 0xff);
431 				if (i % 16 == 15)
432 					printf("\n");
433 			}
434 			if (l % 16)
435 				printf("\n");
436 		}
437 		/* adjust base pointer for promisc mode */
438 		if (base->sadb_msg_type == SADB_X_PROMISC) {
439 			if ((ssize_t)sizeof(*base) < l)
440 				base++;
441 			else
442 				base = NULL;
443 		}
444 		if (base) {
445 			kdebug_sadb(base);
446 			printf("\n");
447 			fflush(stdout);
448 		}
449 	}
450 }
451 
452 int
453 sendkeymsg(buf, len)
454 	char *buf;
455 	size_t len;
456 {
457 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
458 	ssize_t l;
459 	struct sadb_msg *msg;
460 
461 	if (f_notreally) {
462 		goto end;
463 	}
464 
465     {
466 	struct timeval tv;
467 	tv.tv_sec = 1;
468 	tv.tv_usec = 0;
469 	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
470 		perror("setsockopt");
471 		goto end;
472 	}
473     }
474 
475 	if (f_forever)
476 		shortdump_hdr();
477 again:
478 	if (f_verbose) {
479 		kdebug_sadb((struct sadb_msg *)buf);
480 		printf("\n");
481 	}
482 	if (f_hexdump) {
483 		int i;
484 		for (i = 0; i < len; i++) {
485 			if (i % 16 == 0)
486 				printf("%08x: ", i);
487 			printf("%02x ", buf[i] & 0xff);
488 			if (i % 16 == 15)
489 				printf("\n");
490 		}
491 		if (len % 16)
492 			printf("\n");
493 	}
494 
495 	if ((l = send(so, buf, len, 0)) < 0) {
496 		perror("send");
497 		goto end;
498 	}
499 
500 	msg = (struct sadb_msg *)rbuf;
501 	do {
502 		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
503 			perror("recv");
504 			goto end;
505 		}
506 
507 		if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) {
508 			warnx("invalid keymsg length");
509 			break;
510 		}
511 
512 		if (f_verbose) {
513 			kdebug_sadb((struct sadb_msg *)rbuf);
514 			printf("\n");
515 		}
516 		if (postproc(msg, l) < 0)
517 			break;
518 	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);
519 
520 	if (f_forever) {
521 		fflush(stdout);
522 		sleep(1);
523 		goto again;
524 	}
525 
526 end:
527 	return (0);
528 }
529 
530 int
531 postproc(msg, len)
532 	struct sadb_msg *msg;
533 	int len;
534 {
535 #ifdef HAVE_PFKEY_POLICY_PRIORITY
536 	static int priority_support_check = 0;
537 #endif
538 
539 	if (msg->sadb_msg_errno != 0) {
540 		char inf[80];
541 		const char *errmsg = NULL;
542 
543 		if (f_mode == MODE_SCRIPT)
544 			snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
545 		else
546 			inf[0] = '\0';
547 
548 		switch (msg->sadb_msg_errno) {
549 		case ENOENT:
550 			switch (msg->sadb_msg_type) {
551 			case SADB_DELETE:
552 			case SADB_GET:
553 			case SADB_X_SPDDELETE:
554 				errmsg = "No entry";
555 				break;
556 			case SADB_DUMP:
557 				errmsg = "No SAD entries";
558 				break;
559 			case SADB_X_SPDDUMP:
560 				errmsg = "No SPD entries";
561 				break;
562 			}
563 			break;
564 		default:
565 			errmsg = strerror(msg->sadb_msg_errno);
566 		}
567 		printf("%s%s.\n", inf, errmsg);
568 		return (-1);
569 	}
570 
571 	switch (msg->sadb_msg_type) {
572 	case SADB_GET:
573 		pfkey_sadump(msg);
574 		break;
575 
576 	case SADB_DUMP:
577 		/* filter out DEAD SAs */
578 		if (!f_all) {
579 			caddr_t mhp[SADB_EXT_MAX + 1];
580 			struct sadb_sa *sa;
581 			pfkey_align(msg, mhp);
582 			pfkey_check(mhp);
583 			if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
584 				if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
585 					break;
586 			}
587 		}
588 		if (f_forever)
589 			shortdump(msg);
590 		else
591 			pfkey_sadump(msg);
592 		msg = (struct sadb_msg *)((caddr_t)msg +
593 				     PFKEY_UNUNIT64(msg->sadb_msg_len));
594 		if (f_verbose) {
595 			kdebug_sadb((struct sadb_msg *)msg);
596 			printf("\n");
597 		}
598 		break;
599 
600 	case SADB_X_SPDGET:
601 		if (f_withports)
602 			pfkey_spdump_withports(msg);
603 		else
604 			pfkey_spdump(msg);
605 		break;
606 
607 	case SADB_X_SPDDUMP:
608 		if (f_withports)
609 			pfkey_spdump_withports(msg);
610 		else
611 			pfkey_spdump(msg);
612 		if (msg->sadb_msg_seq == 0) break;
613 		msg = (struct sadb_msg *)((caddr_t)msg +
614 				     PFKEY_UNUNIT64(msg->sadb_msg_len));
615 		if (f_verbose) {
616 			kdebug_sadb((struct sadb_msg *)msg);
617 			printf("\n");
618 		}
619 		break;
620 #ifdef HAVE_PFKEY_POLICY_PRIORITY
621 	case SADB_X_SPDADD:
622 		if (last_msg_type == SADB_X_SPDADD && last_priority != 0 &&
623 		    msg->sadb_msg_pid == getpid() && !priority_support_check) {
624 			priority_support_check = 1;
625 			if (!verifypriority(msg))
626 				printf ("WARNING: Kernel does not support policy priorities\n");
627 		}
628 		break;
629 #endif
630 	}
631 
632 	return (0);
633 }
634 
635 #ifdef HAVE_PFKEY_POLICY_PRIORITY
636 int
637 verifypriority(m)
638 	struct sadb_msg *m;
639 {
640 	caddr_t mhp[SADB_EXT_MAX + 1];
641 	struct sadb_x_policy *xpl;
642 
643 	/* check pfkey message. */
644 	if (pfkey_align(m, mhp)) {
645 		printf("(%s\n", ipsec_strerror());
646 		return 0;
647 	}
648 	if (pfkey_check(mhp)) {
649 		printf("%s\n", ipsec_strerror());
650 		return 0;
651 	}
652 
653 	xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY];
654 
655 	if (xpl == NULL) {
656 		printf("no X_POLICY extension.\n");
657 		return 0;
658 	}
659 
660 	/* now make sure they match */
661 	if (last_priority != xpl->sadb_x_policy_priority)
662 		return 0;
663 
664 	return 1;
665 }
666 #endif
667 
668 int
669 fileproc(filename)
670 	const char *filename;
671 {
672 	int fd;
673 	ssize_t len, l;
674 	u_char *p, *ep;
675 	struct sadb_msg *msg;
676 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
677 
678 	fd = open(filename, O_RDONLY);
679 	if (fd < 0)
680 		return -1;
681 
682 	l = 0;
683 	while (1) {
684 		len = read(fd, rbuf + l, sizeof(rbuf) - l);
685 		if (len < 0) {
686 			close(fd);
687 			return -1;
688 		} else if (len == 0)
689 			break;
690 		l += len;
691 	}
692 
693 	if (l < sizeof(struct sadb_msg)) {
694 		close(fd);
695 		errno = EINVAL;
696 		return -1;
697 	}
698 	close(fd);
699 
700 	p = rbuf;
701 	ep = rbuf + l;
702 
703 	while (p < ep) {
704 		msg = (struct sadb_msg *)p;
705 		len = PFKEY_UNUNIT64(msg->sadb_msg_len);
706 		postproc(msg, len);
707 		p += len;
708 	}
709 
710 	return (0);
711 }
712 
713 
714 /*------------------------------------------------------------*/
715 static const char *satype[] = {
716 	NULL, NULL, "ah", "esp"
717 };
718 static const char *sastate[] = {
719 	"L", "M", "D", "d"
720 };
721 static const char *ipproto[] = {
722 /*0*/	"ip", "icmp", "igmp", "ggp", "ip4",
723 	NULL, "tcp", NULL, "egp", NULL,
724 /*10*/	NULL, NULL, NULL, NULL, NULL,
725 	NULL, NULL, "udp", NULL, NULL,
726 /*20*/	NULL, NULL, "idp", NULL, NULL,
727 	NULL, NULL, NULL, NULL, "tp",
728 /*30*/	NULL, NULL, NULL, NULL, NULL,
729 	NULL, NULL, NULL, NULL, NULL,
730 /*40*/	NULL, "ip6", NULL, "rt6", "frag6",
731 	NULL, "rsvp", "gre", NULL, NULL,
732 /*50*/	"esp", "ah", NULL, NULL, NULL,
733 	NULL, NULL, NULL, "icmp6", "none",
734 /*60*/	"dst6",
735 };
736 
737 #define STR_OR_ID(x, tab) \
738 	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
739 
740 const char *
741 numstr(x)
742 	int x;
743 {
744 	static char buf[20];
745 	snprintf(buf, sizeof(buf), "#%d", x);
746 	return buf;
747 }
748 
749 void
750 shortdump_hdr()
751 {
752 	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
753 		"time", "p", "s", "spi", "ltime", "src", "dst");
754 }
755 
756 void
757 shortdump(msg)
758 	struct sadb_msg *msg;
759 {
760 	caddr_t mhp[SADB_EXT_MAX + 1];
761 	char buf[NI_MAXHOST], pbuf[NI_MAXSERV];
762 	struct sadb_sa *sa;
763 	struct sadb_address *saddr;
764 	struct sadb_lifetime *lts, *lth, *ltc;
765 	struct sockaddr *s;
766 	u_int t;
767 	time_t cur = time(0);
768 
769 	pfkey_align(msg, mhp);
770 	pfkey_check(mhp);
771 
772 	printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
773 
774 	printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
775 
776 	if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
777 		printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
778 		printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
779 	} else
780 		printf("%-1s %-8s", "?", "?");
781 
782 	lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
783 	lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
784 	ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
785 	if (lts && lth && ltc) {
786 		if (ltc->sadb_lifetime_addtime == 0)
787 			t = (u_long)0;
788 		else
789 			t = (u_long)(cur - ltc->sadb_lifetime_addtime);
790 		if (t >= 1000)
791 			strlcpy(buf, " big/", sizeof(buf));
792 		else
793 			snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
794 		printf("%s", buf);
795 
796 		t = (u_long)lth->sadb_lifetime_addtime;
797 		if (t >= 1000)
798 			strlcpy(buf, "big", sizeof(buf));
799 		else
800 			snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
801 		printf("%s", buf);
802 	} else
803 		printf(" ??\?/???");	/* backslash to avoid trigraph ??/ */
804 
805 	printf(" ");
806 
807 	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
808 		if (saddr->sadb_address_proto)
809 			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
810 		s = (struct sockaddr *)(saddr + 1);
811 		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
812 			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
813 		if (strcmp(pbuf, "0") != 0)
814 			printf("%s[%s]", buf, pbuf);
815 		else
816 			printf("%s", buf);
817 	} else
818 		printf("?");
819 
820 	printf(" -> ");
821 
822 	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
823 		if (saddr->sadb_address_proto)
824 			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
825 
826 		s = (struct sockaddr *)(saddr + 1);
827 		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
828 			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
829 		if (strcmp(pbuf, "0") != 0)
830 			printf("%s[%s]", buf, pbuf);
831 		else
832 			printf("%s", buf);
833 	} else
834 		printf("?");
835 
836 	printf("\n");
837 }
838 
839 /* From: tcpdump(1):gmt2local.c and util.c */
840 /*
841  * Print the timestamp
842  */
843 static void
844 printdate()
845 {
846 	struct timeval tp;
847 	int s;
848 
849 	if (gettimeofday(&tp, NULL) == -1) {
850 		perror("gettimeofday");
851 		return;
852 	}
853 
854 	if (f_tflag == 1) {
855 		/* Default */
856 		s = (tp.tv_sec + thiszone ) % 86400;
857 		(void)printf("%02d:%02d:%02d.%06u ",
858 		    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec);
859 	} else if (f_tflag > 1) {
860 		/* Unix timeval style */
861 		(void)printf("%u.%06u ",
862 		    (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec);
863 	}
864 
865 	printf("\n");
866 }
867 
868 /*
869  * Returns the difference between gmt and local time in seconds.
870  * Use gmtime() and localtime() to keep things simple.
871  */
872 int32_t
873 gmt2local(time_t t)
874 {
875 	register int dt, dir;
876 	register struct tm *gmt, *loc;
877 	struct tm sgmt;
878 
879 	if (t == 0)
880 		t = time(NULL);
881 	gmt = &sgmt;
882 	*gmt = *gmtime(&t);
883 	loc = localtime(&t);
884 	dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
885 	    (loc->tm_min - gmt->tm_min) * 60;
886 
887 	/*
888 	 * If the year or julian day is different, we span 00:00 GMT
889 	 * and must add or subtract a day. Check the year first to
890 	 * avoid problems when the julian day wraps.
891 	 */
892 	dir = loc->tm_year - gmt->tm_year;
893 	if (dir == 0)
894 		dir = loc->tm_yday - gmt->tm_yday;
895 	dt += dir * 24 * 60 * 60;
896 
897 	return (dt);
898 }
899