1 /* $NetBSD: setkey.c,v 1.6 2005/06/26 23:49:31 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 #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
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 			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 *read;
311 		read = readline ("");
312 		if (! read)
313 			break;
314 #else
315 		char rbuf[1024];
316 		rbuf[0] = '\0';
317 		fgets (rbuf, sizeof(rbuf), stdin);
318 		if (! rbuf[0])
319 			break;
320 		if (rbuf[strlen(rbuf)-1] == '\n')
321 			rbuf[strlen(rbuf)-1] = '\0';
322 #endif
323 		comment = strchr(rbuf, '#');
324 		if (comment)
325 			*comment = '\0';
326 
327 		if (! rbuf[0])
328 			continue;
329 
330 		linelen += snprintf (&line[linelen], sizeof(line) - linelen,
331 				     "%s%s", linelen > 0 ? " " : "", rbuf);
332 
333 		semicolon = strchr(line, ';');
334 		while (semicolon) {
335 			char saved_char = *++semicolon;
336 			*semicolon = '\0';
337 #ifdef HAVE_READLINE
338 			add_history (line);
339 #endif
340 
341 #ifdef HAVE_PFKEY_POLICY_PRIORITY
342 			last_msg_type = -1;  /* invalid message type */
343 #endif
344 
345 			parse_string (line);
346 			if (exit_now)
347 				return;
348 			if (saved_char) {
349 				*semicolon = saved_char;
350 				linelen = strlen (semicolon);
351 				memmove (line, semicolon, linelen + 1);
352 				semicolon = strchr(line, ';');
353 			}
354 			else {
355 				semicolon = NULL;
356 				linelen = 0;
357 			}
358 		}
359 	}
360 }
361 
362 void
363 sendkeyshort(type)
364         u_int type;
365 {
366 	struct sadb_msg msg;
367 
368 	msg.sadb_msg_version = PF_KEY_V2;
369 	msg.sadb_msg_type = type;
370 	msg.sadb_msg_errno = 0;
371 	msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
372 	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
373 	msg.sadb_msg_reserved = 0;
374 	msg.sadb_msg_seq = 0;
375 	msg.sadb_msg_pid = getpid();
376 
377 	sendkeymsg((char *)&msg, sizeof(msg));
378 
379 	return;
380 }
381 
382 void
383 promisc()
384 {
385 	struct sadb_msg msg;
386 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
387 	ssize_t l;
388 
389 	msg.sadb_msg_version = PF_KEY_V2;
390 	msg.sadb_msg_type = SADB_X_PROMISC;
391 	msg.sadb_msg_errno = 0;
392 	msg.sadb_msg_satype = 1;
393 	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
394 	msg.sadb_msg_reserved = 0;
395 	msg.sadb_msg_seq = 0;
396 	msg.sadb_msg_pid = getpid();
397 
398 	if ((l = send(so, &msg, sizeof(msg), 0)) < 0) {
399 		err(1, "send");
400 		/*NOTREACHED*/
401 	}
402 
403 	while (1) {
404 		struct sadb_msg *base;
405 
406 		if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
407 			err(1, "recv");
408 			/*NOTREACHED*/
409 		}
410 
411 		if (l != sizeof(*base))
412 			continue;
413 
414 		base = (struct sadb_msg *)rbuf;
415 		if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
416 				0)) < 0) {
417 			err(1, "recv");
418 			/*NOTREACHED*/
419 		}
420 		printdate();
421 		if (f_hexdump) {
422 			int i;
423 			for (i = 0; i < l; i++) {
424 				if (i % 16 == 0)
425 					printf("%08x: ", i);
426 				printf("%02x ", rbuf[i] & 0xff);
427 				if (i % 16 == 15)
428 					printf("\n");
429 			}
430 			if (l % 16)
431 				printf("\n");
432 		}
433 		/* adjust base pointer for promisc mode */
434 		if (base->sadb_msg_type == SADB_X_PROMISC) {
435 			if ((ssize_t)sizeof(*base) < l)
436 				base++;
437 			else
438 				base = NULL;
439 		}
440 		if (base) {
441 			kdebug_sadb(base);
442 			printf("\n");
443 			fflush(stdout);
444 		}
445 	}
446 }
447 
448 int
449 sendkeymsg(buf, len)
450 	char *buf;
451 	size_t len;
452 {
453 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
454 	ssize_t l;
455 	struct sadb_msg *msg;
456 
457 	if (f_notreally) {
458 		goto end;
459 	}
460 
461     {
462 	struct timeval tv;
463 	tv.tv_sec = 1;
464 	tv.tv_usec = 0;
465 	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
466 		perror("setsockopt");
467 		goto end;
468 	}
469     }
470 
471 	if (f_forever)
472 		shortdump_hdr();
473 again:
474 	if (f_verbose) {
475 		kdebug_sadb((struct sadb_msg *)buf);
476 		printf("\n");
477 	}
478 	if (f_hexdump) {
479 		int i;
480 		for (i = 0; i < len; i++) {
481 			if (i % 16 == 0)
482 				printf("%08x: ", i);
483 			printf("%02x ", buf[i] & 0xff);
484 			if (i % 16 == 15)
485 				printf("\n");
486 		}
487 		if (len % 16)
488 			printf("\n");
489 	}
490 
491 	if ((l = send(so, buf, len, 0)) < 0) {
492 		perror("send");
493 		goto end;
494 	}
495 
496 	msg = (struct sadb_msg *)rbuf;
497 	do {
498 		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
499 			perror("recv");
500 			goto end;
501 		}
502 
503 		if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) {
504 			warnx("invalid keymsg length");
505 			break;
506 		}
507 
508 		if (f_verbose) {
509 			kdebug_sadb((struct sadb_msg *)rbuf);
510 			printf("\n");
511 		}
512 		if (postproc(msg, l) < 0)
513 			break;
514 	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);
515 
516 	if (f_forever) {
517 		fflush(stdout);
518 		sleep(1);
519 		goto again;
520 	}
521 
522 end:
523 	return (0);
524 }
525 
526 int
527 postproc(msg, len)
528 	struct sadb_msg *msg;
529 	int len;
530 {
531 #ifdef HAVE_PFKEY_POLICY_PRIORITY
532 	static int priority_support_check = 0;
533 #endif
534 
535 	if (msg->sadb_msg_errno != 0) {
536 		char inf[80];
537 		const char *errmsg = NULL;
538 
539 		if (f_mode == MODE_SCRIPT)
540 			snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
541 		else
542 			inf[0] = '\0';
543 
544 		switch (msg->sadb_msg_errno) {
545 		case ENOENT:
546 			switch (msg->sadb_msg_type) {
547 			case SADB_DELETE:
548 			case SADB_GET:
549 			case SADB_X_SPDDELETE:
550 				errmsg = "No entry";
551 				break;
552 			case SADB_DUMP:
553 				errmsg = "No SAD entries";
554 				break;
555 			case SADB_X_SPDDUMP:
556 				errmsg = "No SPD entries";
557 				break;
558 			}
559 			break;
560 		default:
561 			errmsg = strerror(msg->sadb_msg_errno);
562 		}
563 		printf("%s%s.\n", inf, errmsg);
564 		return (-1);
565 	}
566 
567 	switch (msg->sadb_msg_type) {
568 	case SADB_GET:
569 		pfkey_sadump(msg);
570 		break;
571 
572 	case SADB_DUMP:
573 		/* filter out DEAD SAs */
574 		if (!f_all) {
575 			caddr_t mhp[SADB_EXT_MAX + 1];
576 			struct sadb_sa *sa;
577 			pfkey_align(msg, mhp);
578 			pfkey_check(mhp);
579 			if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
580 				if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
581 					break;
582 			}
583 		}
584 		if (f_forever)
585 			shortdump(msg);
586 		else
587 			pfkey_sadump(msg);
588 		msg = (struct sadb_msg *)((caddr_t)msg +
589 				     PFKEY_UNUNIT64(msg->sadb_msg_len));
590 		if (f_verbose) {
591 			kdebug_sadb((struct sadb_msg *)msg);
592 			printf("\n");
593 		}
594 		break;
595 
596 	case SADB_X_SPDGET:
597 		if (f_withports)
598 			pfkey_spdump_withports(msg);
599 		else
600 			pfkey_spdump(msg);
601 		break;
602 
603 	case SADB_X_SPDDUMP:
604 		if (f_withports)
605 			pfkey_spdump_withports(msg);
606 		else
607 			pfkey_spdump(msg);
608 		if (msg->sadb_msg_seq == 0) break;
609 		msg = (struct sadb_msg *)((caddr_t)msg +
610 				     PFKEY_UNUNIT64(msg->sadb_msg_len));
611 		if (f_verbose) {
612 			kdebug_sadb((struct sadb_msg *)msg);
613 			printf("\n");
614 		}
615 		break;
616 #ifdef HAVE_PFKEY_POLICY_PRIORITY
617 	case SADB_X_SPDADD:
618 		if (last_msg_type == SADB_X_SPDADD && last_priority != 0 &&
619 		    msg->sadb_msg_pid == getpid() && !priority_support_check) {
620 			priority_support_check = 1;
621 			if (!verifypriority(msg))
622 				printf ("WARNING: Kernel does not support policy priorities\n");
623 		}
624 		break;
625 #endif
626 	}
627 
628 	return (0);
629 }
630 
631 #ifdef HAVE_PFKEY_POLICY_PRIORITY
632 int
633 verifypriority(m)
634 	struct sadb_msg *m;
635 {
636 	caddr_t mhp[SADB_EXT_MAX + 1];
637 	struct sadb_x_policy *xpl;
638 
639 	/* check pfkey message. */
640 	if (pfkey_align(m, mhp)) {
641 		printf("(%s\n", ipsec_strerror());
642 		return 0;
643 	}
644 	if (pfkey_check(mhp)) {
645 		printf("%s\n", ipsec_strerror());
646 		return 0;
647 	}
648 
649 	xpl = (struct sadb_x_policy *) mhp[SADB_X_EXT_POLICY];
650 
651 	if (xpl == NULL) {
652 		printf("no X_POLICY extension.\n");
653 		return 0;
654 	}
655 
656 	/* now make sure they match */
657 	if (last_priority != xpl->sadb_x_policy_priority)
658 		return 0;
659 
660 	return 1;
661 }
662 #endif
663 
664 int
665 fileproc(filename)
666 	const char *filename;
667 {
668 	int fd;
669 	ssize_t len, l;
670 	u_char *p, *ep;
671 	struct sadb_msg *msg;
672 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
673 
674 	fd = open(filename, O_RDONLY);
675 	if (fd < 0)
676 		return -1;
677 
678 	l = 0;
679 	while (1) {
680 		len = read(fd, rbuf + l, sizeof(rbuf) - l);
681 		if (len < 0) {
682 			close(fd);
683 			return -1;
684 		} else if (len == 0)
685 			break;
686 		l += len;
687 	}
688 
689 	if (l < sizeof(struct sadb_msg)) {
690 		close(fd);
691 		errno = EINVAL;
692 		return -1;
693 	}
694 	close(fd);
695 
696 	p = rbuf;
697 	ep = rbuf + l;
698 
699 	while (p < ep) {
700 		msg = (struct sadb_msg *)p;
701 		len = PFKEY_UNUNIT64(msg->sadb_msg_len);
702 		postproc(msg, len);
703 		p += len;
704 	}
705 
706 	return (0);
707 }
708 
709 
710 /*------------------------------------------------------------*/
711 static const char *satype[] = {
712 	NULL, NULL, "ah", "esp"
713 };
714 static const char *sastate[] = {
715 	"L", "M", "D", "d"
716 };
717 static const char *ipproto[] = {
718 /*0*/	"ip", "icmp", "igmp", "ggp", "ip4",
719 	NULL, "tcp", NULL, "egp", NULL,
720 /*10*/	NULL, NULL, NULL, NULL, NULL,
721 	NULL, NULL, "udp", NULL, NULL,
722 /*20*/	NULL, NULL, "idp", NULL, NULL,
723 	NULL, NULL, NULL, NULL, "tp",
724 /*30*/	NULL, NULL, NULL, NULL, NULL,
725 	NULL, NULL, NULL, NULL, NULL,
726 /*40*/	NULL, "ip6", NULL, "rt6", "frag6",
727 	NULL, "rsvp", "gre", NULL, NULL,
728 /*50*/	"esp", "ah", NULL, NULL, NULL,
729 	NULL, NULL, NULL, "icmp6", "none",
730 /*60*/	"dst6",
731 };
732 
733 #define STR_OR_ID(x, tab) \
734 	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
735 
736 const char *
737 numstr(x)
738 	int x;
739 {
740 	static char buf[20];
741 	snprintf(buf, sizeof(buf), "#%d", x);
742 	return buf;
743 }
744 
745 void
746 shortdump_hdr()
747 {
748 	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
749 		"time", "p", "s", "spi", "ltime", "src", "dst");
750 }
751 
752 void
753 shortdump(msg)
754 	struct sadb_msg *msg;
755 {
756 	caddr_t mhp[SADB_EXT_MAX + 1];
757 	char buf[NI_MAXHOST], pbuf[NI_MAXSERV];
758 	struct sadb_sa *sa;
759 	struct sadb_address *saddr;
760 	struct sadb_lifetime *lts, *lth, *ltc;
761 	struct sockaddr *s;
762 	u_int t;
763 	time_t cur = time(0);
764 
765 	pfkey_align(msg, mhp);
766 	pfkey_check(mhp);
767 
768 	printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
769 
770 	printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
771 
772 	if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
773 		printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
774 		printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
775 	} else
776 		printf("%-1s %-8s", "?", "?");
777 
778 	lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
779 	lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
780 	ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
781 	if (lts && lth && ltc) {
782 		if (ltc->sadb_lifetime_addtime == 0)
783 			t = (u_long)0;
784 		else
785 			t = (u_long)(cur - ltc->sadb_lifetime_addtime);
786 		if (t >= 1000)
787 			strlcpy(buf, " big/", sizeof(buf));
788 		else
789 			snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
790 		printf("%s", buf);
791 
792 		t = (u_long)lth->sadb_lifetime_addtime;
793 		if (t >= 1000)
794 			strlcpy(buf, "big", sizeof(buf));
795 		else
796 			snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
797 		printf("%s", buf);
798 	} else
799 		printf(" ??\?/???");	/* backslash to avoid trigraph ??/ */
800 
801 	printf(" ");
802 
803 	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
804 		if (saddr->sadb_address_proto)
805 			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
806 		s = (struct sockaddr *)(saddr + 1);
807 		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
808 			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
809 		if (strcmp(pbuf, "0") != 0)
810 			printf("%s[%s]", buf, pbuf);
811 		else
812 			printf("%s", buf);
813 	} else
814 		printf("?");
815 
816 	printf(" -> ");
817 
818 	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
819 		if (saddr->sadb_address_proto)
820 			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
821 
822 		s = (struct sockaddr *)(saddr + 1);
823 		getnameinfo(s, sysdep_sa_len(s), buf, sizeof(buf),
824 			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
825 		if (strcmp(pbuf, "0") != 0)
826 			printf("%s[%s]", buf, pbuf);
827 		else
828 			printf("%s", buf);
829 	} else
830 		printf("?");
831 
832 	printf("\n");
833 }
834 
835 /* From: tcpdump(1):gmt2local.c and util.c */
836 /*
837  * Print the timestamp
838  */
839 static void
840 printdate()
841 {
842 	struct timeval tp;
843 	int s;
844 
845 	if (gettimeofday(&tp, NULL) == -1) {
846 		perror("gettimeofday");
847 		return;
848 	}
849 
850 	if (f_tflag == 1) {
851 		/* Default */
852 		s = (tp.tv_sec + thiszone ) % 86400;
853 		(void)printf("%02d:%02d:%02d.%06u ",
854 		    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec);
855 	} else if (f_tflag > 1) {
856 		/* Unix timeval style */
857 		(void)printf("%u.%06u ",
858 		    (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec);
859 	}
860 
861 	printf("\n");
862 }
863 
864 /*
865  * Returns the difference between gmt and local time in seconds.
866  * Use gmtime() and localtime() to keep things simple.
867  */
868 int32_t
869 gmt2local(time_t t)
870 {
871 	register int dt, dir;
872 	register struct tm *gmt, *loc;
873 	struct tm sgmt;
874 
875 	if (t == 0)
876 		t = time(NULL);
877 	gmt = &sgmt;
878 	*gmt = *gmtime(&t);
879 	loc = localtime(&t);
880 	dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
881 	    (loc->tm_min - gmt->tm_min) * 60;
882 
883 	/*
884 	 * If the year or julian day is different, we span 00:00 GMT
885 	 * and must add or subtract a day. Check the year first to
886 	 * avoid problems when the julian day wraps.
887 	 */
888 	dir = loc->tm_year - gmt->tm_year;
889 	if (dir == 0)
890 		dir = loc->tm_yday - gmt->tm_yday;
891 	dt += dir * 24 * 60 * 60;
892 
893 	return (dt);
894 }
895