setkey.c revision 78064
162583Sitojun/*	$FreeBSD: head/sbin/setkey/setkey.c 78064 2001-06-11 12:39:29Z ume $	*/
278064Sume/*	$KAME: setkey.c,v 1.18 2001/05/08 04:36:39 itojun Exp $	*/
362583Sitojun
455505Sshin/*
555505Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
655505Sshin * All rights reserved.
762583Sitojun *
855505Sshin * Redistribution and use in source and binary forms, with or without
955505Sshin * modification, are permitted provided that the following conditions
1055505Sshin * are met:
1155505Sshin * 1. Redistributions of source code must retain the above copyright
1255505Sshin *    notice, this list of conditions and the following disclaimer.
1355505Sshin * 2. Redistributions in binary form must reproduce the above copyright
1455505Sshin *    notice, this list of conditions and the following disclaimer in the
1555505Sshin *    documentation and/or other materials provided with the distribution.
1655505Sshin * 3. Neither the name of the project nor the names of its contributors
1755505Sshin *    may be used to endorse or promote products derived from this software
1855505Sshin *    without specific prior written permission.
1962583Sitojun *
2055505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2155505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355505Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2455505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2555505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2655505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2755505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2855505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2955505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3055505Sshin * SUCH DAMAGE.
3155505Sshin */
3255505Sshin
3355505Sshin#include <sys/types.h>
3455505Sshin#include <sys/param.h>
3555505Sshin#include <sys/socket.h>
3655505Sshin#include <sys/time.h>
3755505Sshin#include <err.h>
3855505Sshin#include <net/route.h>
3955505Sshin#include <netinet/in.h>
4055505Sshin#include <net/pfkeyv2.h>
4155505Sshin#include <netkey/keydb.h>
4255505Sshin#include <netkey/key_debug.h>
4355505Sshin#include <netinet6/ipsec.h>
4455505Sshin
4555505Sshin#include <stdio.h>
4655505Sshin#include <stdlib.h>
4755505Sshin#include <limits.h>
4855505Sshin#include <string.h>
4955505Sshin#include <ctype.h>
5055505Sshin#include <unistd.h>
5155505Sshin#include <errno.h>
5255505Sshin#include <netdb.h>
5355505Sshin
5462583Sitojun#include "libpfkey.h"
5555505Sshin
5662583Sitojunvoid Usage __P((void));
5762583Sitojunint main __P((int, char **));
5862583Sitojunint get_supported __P((void));
5962583Sitojunvoid sendkeyshort __P((u_int));
6062583Sitojunvoid promisc __P((void));
6162583Sitojunint sendkeymsg __P((void));
6262583Sitojunint postproc __P((struct sadb_msg *, int));
6362583Sitojunconst char *numstr __P((int));
6462583Sitojunvoid shortdump_hdr __P((void));
6562583Sitojunvoid shortdump __P((struct sadb_msg *));
6678064Sumestatic void printdate __P((void));
6778064Sumestatic int32_t gmt2local __P((time_t));
6862583Sitojun
6955505Sshin#define MODE_SCRIPT	1
7055505Sshin#define MODE_CMDDUMP	2
7155505Sshin#define MODE_CMDFLUSH	3
7262583Sitojun#define MODE_PROMISC	4
7355505Sshin
7455505Sshinint so;
7555505Sshin
7662583Sitojunint f_forever = 0;
7762583Sitojunint f_all = 0;
7862583Sitojunint f_debug = 0;
7962583Sitojunint f_verbose = 0;
8062583Sitojunint f_mode = 0;
8162583Sitojunint f_cmddump = 0;
8262583Sitojunint f_policy = 0;
8362583Sitojunint f_hexdump = 0;
8478064Sumeint f_tflag = 0;
8562583Sitojunchar *pname;
8655505Sshin
8762583Sitojunu_char m_buf[BUFSIZ];
8862583Sitojunu_int m_len;
8955505Sshin
9078064Sumestatic time_t thiszone;
9178064Sume
9262583Sitojunextern int lineno;
9355505Sshin
9462583Sitojunextern int parse __P((FILE **));
9555505Sshin
9655505Sshinvoid
9755505SshinUsage()
9855505Sshin{
9955505Sshin	printf("Usage:\t%s [-dv] -c\n", pname);
10055505Sshin	printf("\t%s [-dv] -f (file)\n", pname);
10155505Sshin	printf("\t%s [-Padlv] -D\n", pname);
10255505Sshin	printf("\t%s [-Pdv] -F\n", pname);
10355505Sshin	printf("\t%s [-h] -x\n", pname);
10455505Sshin	pfkey_close(so);
10562583Sitojun	exit(1);
10655505Sshin}
10755505Sshin
10855505Sshinint
10955505Sshinmain(ac, av)
11055505Sshin	int ac;
11155505Sshin	char **av;
11255505Sshin{
11355505Sshin	FILE *fp = stdin;
11455505Sshin	int c;
11555505Sshin
11655505Sshin	pname = *av;
11755505Sshin
11855505Sshin	if (ac == 1) Usage();
11955505Sshin
12078064Sume	thiszone = gmt2local(0);
12178064Sume
12278064Sume	while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) {
12355505Sshin		switch (c) {
12455505Sshin		case 'c':
12555505Sshin			f_mode = MODE_SCRIPT;
12655505Sshin			fp = stdin;
12755505Sshin			break;
12855505Sshin		case 'f':
12955505Sshin			f_mode = MODE_SCRIPT;
13055505Sshin			if ((fp = fopen(optarg, "r")) == NULL) {
13155505Sshin				err(-1, "fopen");
13255505Sshin				/*NOTREACHED*/
13355505Sshin			}
13455505Sshin			break;
13555505Sshin		case 'D':
13655505Sshin			f_mode = MODE_CMDDUMP;
13755505Sshin			break;
13855505Sshin		case 'F':
13955505Sshin			f_mode = MODE_CMDFLUSH;
14055505Sshin			break;
14155505Sshin		case 'a':
14255505Sshin			f_all = 1;
14355505Sshin			break;
14455505Sshin		case 'l':
14555505Sshin			f_forever = 1;
14655505Sshin			break;
14755505Sshin		case 'h':
14855505Sshin			f_hexdump = 1;
14955505Sshin			break;
15055505Sshin		case 'x':
15162583Sitojun			f_mode = MODE_PROMISC;
15278064Sume			f_tflag++;
15362583Sitojun			break;
15455505Sshin		case 'P':
15555505Sshin			f_policy = 1;
15655505Sshin			break;
15755505Sshin		case 'd':
15855505Sshin			f_debug = 1;
15955505Sshin			break;
16055505Sshin		case 'v':
16155505Sshin			f_verbose = 1;
16255505Sshin			break;
16355505Sshin		default:
16455505Sshin			Usage();
16555505Sshin			/*NOTREACHED*/
16655505Sshin		}
16755505Sshin	}
16855505Sshin
16955505Sshin	switch (f_mode) {
17055505Sshin	case MODE_CMDDUMP:
17155505Sshin		sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP);
17255505Sshin		break;
17355505Sshin	case MODE_CMDFLUSH:
17455505Sshin		sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
17555505Sshin		pfkey_close(so);
17655505Sshin		break;
17755505Sshin	case MODE_SCRIPT:
17855505Sshin		if (get_supported() < 0) {
17955505Sshin			errx(-1, "%s", ipsec_strerror());
18055505Sshin			/*NOTREACHED*/
18155505Sshin		}
18262583Sitojun		if (parse(&fp))
18362583Sitojun			exit (1);
18455505Sshin		break;
18562583Sitojun	case MODE_PROMISC:
18662583Sitojun		promisc();
18762583Sitojun		/*NOTREACHED*/
18855505Sshin	default:
18955505Sshin		Usage();
19062583Sitojun		/*NOTREACHED*/
19155505Sshin	}
19255505Sshin
19355505Sshin	exit(0);
19455505Sshin}
19555505Sshin
19655505Sshinint
19755505Sshinget_supported()
19855505Sshin{
19955505Sshin	int so;
20055505Sshin
20155505Sshin	if ((so = pfkey_open()) < 0) {
20255505Sshin		perror("pfkey_open");
20355505Sshin		return -1;
20455505Sshin	}
20555505Sshin
20655505Sshin	/* debug mode ? */
20755505Sshin	if (f_debug)
20855505Sshin		return 0;
20955505Sshin
21078064Sume	if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0)
21155505Sshin		return -1;
21255505Sshin
21355505Sshin	if (pfkey_recv_register(so) < 0)
21455505Sshin		return -1;
21555505Sshin
21655505Sshin	return 0;
21755505Sshin}
21855505Sshin
21955505Sshinvoid
22055505Sshinsendkeyshort(type)
22155505Sshin        u_int type;
22255505Sshin{
22355505Sshin	struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
22455505Sshin
22555505Sshin	m_len = sizeof(struct sadb_msg);
22655505Sshin
22755505Sshin	m_msg->sadb_msg_version = PF_KEY_V2;
22855505Sshin	m_msg->sadb_msg_type = type;
22955505Sshin	m_msg->sadb_msg_errno = 0;
23055505Sshin	m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
23155505Sshin	m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
23255505Sshin	m_msg->sadb_msg_reserved = 0;
23355505Sshin	m_msg->sadb_msg_seq = 0;
23455505Sshin	m_msg->sadb_msg_pid = getpid();
23555505Sshin
23655505Sshin	sendkeymsg();
23755505Sshin
23855505Sshin	return;
23955505Sshin}
24055505Sshin
24155505Sshinvoid
24255505Sshinpromisc()
24355505Sshin{
24455505Sshin	struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
24555505Sshin	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
24655505Sshin	int so, len;
24755505Sshin
24855505Sshin	m_len = sizeof(struct sadb_msg);
24955505Sshin
25055505Sshin	m_msg->sadb_msg_version = PF_KEY_V2;
25155505Sshin	m_msg->sadb_msg_type = SADB_X_PROMISC;
25255505Sshin	m_msg->sadb_msg_errno = 0;
25355505Sshin	m_msg->sadb_msg_satype = 1;
25455505Sshin	m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
25555505Sshin	m_msg->sadb_msg_reserved = 0;
25655505Sshin	m_msg->sadb_msg_seq = 0;
25755505Sshin	m_msg->sadb_msg_pid = getpid();
25855505Sshin
25955505Sshin	if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
26055505Sshin		err(1, "socket(PF_KEY)");
26155505Sshin		/*NOTREACHED*/
26255505Sshin	}
26355505Sshin
26455505Sshin	if ((len = send(so, m_buf, m_len, 0)) < 0) {
26555505Sshin		err(1, "send");
26655505Sshin		/*NOTREACHED*/
26755505Sshin	}
26855505Sshin
26955505Sshin	while (1) {
27055505Sshin		struct sadb_msg *base;
27155505Sshin
27255505Sshin		if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
27355505Sshin			err(1, "recv");
27455505Sshin			/*NOTREACHED*/
27555505Sshin		}
27655505Sshin
27755505Sshin		if (len != sizeof(*base))
27855505Sshin			continue;
27955505Sshin
28055505Sshin		base = (struct sadb_msg *)rbuf;
28155505Sshin		if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
28255505Sshin				0)) < 0) {
28355505Sshin			err(1, "recv");
28455505Sshin			/*NOTREACHED*/
28555505Sshin		}
28678064Sume		printdate();
28755505Sshin		if (f_hexdump) {
28855505Sshin			int i;
28955505Sshin			for (i = 0; i < len; i++) {
29055505Sshin				if (i % 16 == 0)
29155505Sshin					printf("%08x: ", i);
29255505Sshin				printf("%02x ", rbuf[i] & 0xff);
29355505Sshin				if (i % 16 == 15)
29455505Sshin					printf("\n");
29555505Sshin			}
29655505Sshin			if (len % 16)
29755505Sshin				printf("\n");
29855505Sshin		}
29955505Sshin		/* adjust base pointer for promisc mode */
30055505Sshin		if (base->sadb_msg_type == SADB_X_PROMISC) {
30155505Sshin			if (sizeof(*base) < len)
30255505Sshin				base++;
30355505Sshin			else
30455505Sshin				base = NULL;
30555505Sshin		}
30655505Sshin		if (base) {
30755505Sshin			kdebug_sadb(base);
30855505Sshin			printf("\n");
30955505Sshin			fflush(stdout);
31055505Sshin		}
31155505Sshin	}
31255505Sshin}
31355505Sshin
31455505Sshinint
31555505Sshinsendkeymsg()
31655505Sshin{
31755505Sshin	int so;
31855505Sshin
31955505Sshin	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
32055505Sshin	int len;
32155505Sshin	struct sadb_msg *msg;
32255505Sshin
32355505Sshin	if ((so = pfkey_open()) < 0) {
32455505Sshin		perror("pfkey_open");
32555505Sshin		return -1;
32655505Sshin	}
32755505Sshin
32855505Sshin    {
32955505Sshin	struct timeval tv;
33055505Sshin	tv.tv_sec = 1;
33155505Sshin	tv.tv_usec = 0;
33255505Sshin	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
33355505Sshin		perror("setsockopt");
33455505Sshin		goto end;
33555505Sshin	}
33655505Sshin    }
33755505Sshin
33855505Sshin	if (f_forever)
33955505Sshin		shortdump_hdr();
34055505Sshinagain:
34162583Sitojun	if (f_verbose) {
34255505Sshin		kdebug_sadb((struct sadb_msg *)m_buf);
34362583Sitojun		printf("\n");
34462583Sitojun	}
34555505Sshin
34655505Sshin	if ((len = send(so, m_buf, m_len, 0)) < 0) {
34755505Sshin		perror("send");
34855505Sshin		goto end;
34955505Sshin	}
35055505Sshin
35155505Sshin	msg = (struct sadb_msg *)rbuf;
35255505Sshin	do {
35355505Sshin		if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
35455505Sshin			perror("recv");
35555505Sshin			goto end;
35655505Sshin		}
35755505Sshin
35855505Sshin		if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) {
35955505Sshin			warnx("invalid keymsg length");
36055505Sshin			break;
36155505Sshin		}
36255505Sshin
36362583Sitojun		if (f_verbose) {
36455505Sshin			kdebug_sadb((struct sadb_msg *)rbuf);
36562583Sitojun			printf("\n");
36662583Sitojun		}
36755505Sshin		if (postproc(msg, len) < 0)
36855505Sshin			break;
36955505Sshin	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);
37055505Sshin
37155505Sshin	if (f_forever) {
37255505Sshin		fflush(stdout);
37355505Sshin		sleep(1);
37455505Sshin		goto again;
37555505Sshin	}
37655505Sshin
37755505Sshinend:
37855505Sshin	pfkey_close(so);
37955505Sshin	return(0);
38055505Sshin}
38155505Sshin
38255505Sshinint
38355505Sshinpostproc(msg, len)
38455505Sshin	struct sadb_msg *msg;
38555505Sshin	int len;
38655505Sshin{
38755505Sshin
38855505Sshin	if (msg->sadb_msg_errno != 0) {
38955505Sshin		char inf[80];
39055505Sshin		char *errmsg = NULL;
39155505Sshin
39255505Sshin		if (f_mode == MODE_SCRIPT)
39355505Sshin			snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
39455505Sshin		else
39555505Sshin			inf[0] = '\0';
39655505Sshin
39755505Sshin		switch (msg->sadb_msg_errno) {
39855505Sshin		case ENOENT:
39955505Sshin			switch (msg->sadb_msg_type) {
40055505Sshin			case SADB_DELETE:
40155505Sshin			case SADB_GET:
40255505Sshin			case SADB_X_SPDDELETE:
40355505Sshin				errmsg = "No entry";
40455505Sshin				break;
40555505Sshin			case SADB_DUMP:
40655505Sshin				errmsg = "No SAD entries";
40755505Sshin				break;
40855505Sshin			case SADB_X_SPDDUMP:
40955505Sshin				errmsg = "No SPD entries";
41055505Sshin				break;
41155505Sshin			}
41255505Sshin			break;
41355505Sshin		default:
41455505Sshin			errmsg = strerror(msg->sadb_msg_errno);
41555505Sshin		}
41655505Sshin		printf("%s%s.\n", inf, errmsg);
41755505Sshin		return(-1);
41855505Sshin	}
41955505Sshin
42055505Sshin	switch (msg->sadb_msg_type) {
42155505Sshin	case SADB_GET:
42255505Sshin		pfkey_sadump(msg);
42355505Sshin		break;
42455505Sshin
42555505Sshin	case SADB_DUMP:
42655505Sshin		/* filter out DEAD SAs */
42755505Sshin		if (!f_all) {
42855505Sshin			caddr_t mhp[SADB_EXT_MAX + 1];
42955505Sshin			struct sadb_sa *sa;
43055505Sshin			pfkey_align(msg, mhp);
43155505Sshin			pfkey_check(mhp);
43255505Sshin			if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
43355505Sshin				if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
43455505Sshin					break;
43555505Sshin			}
43655505Sshin		}
43755505Sshin		if (f_forever)
43855505Sshin			shortdump(msg);
43955505Sshin		else
44055505Sshin			pfkey_sadump(msg);
44155505Sshin		msg = (struct sadb_msg *)((caddr_t)msg +
44255505Sshin				     PFKEY_UNUNIT64(msg->sadb_msg_len));
44362583Sitojun		if (f_verbose) {
44455505Sshin			kdebug_sadb((struct sadb_msg *)msg);
44562583Sitojun			printf("\n");
44662583Sitojun		}
44755505Sshin		break;
44855505Sshin
44955505Sshin	case SADB_X_SPDDUMP:
45055505Sshin		pfkey_spdump(msg);
45155505Sshin		if (msg->sadb_msg_seq == 0) break;
45255505Sshin		msg = (struct sadb_msg *)((caddr_t)msg +
45355505Sshin				     PFKEY_UNUNIT64(msg->sadb_msg_len));
45462583Sitojun		if (f_verbose) {
45555505Sshin			kdebug_sadb((struct sadb_msg *)msg);
45662583Sitojun			printf("\n");
45762583Sitojun		}
45855505Sshin		break;
45955505Sshin	}
46055505Sshin
46155505Sshin	return(0);
46255505Sshin}
46355505Sshin
46455505Sshin/*------------------------------------------------------------*/
46555505Sshinstatic char *satype[] = {
46655505Sshin	NULL, NULL, "ah", "esp"
46755505Sshin};
46855505Sshinstatic char *sastate[] = {
46955505Sshin	"L", "M", "D", "d"
47055505Sshin};
47155505Sshinstatic char *ipproto[] = {
47255505Sshin/*0*/	"ip", "icmp", "igmp", "ggp", "ip4",
47355505Sshin	NULL, "tcp", NULL, "egp", NULL,
47455505Sshin/*10*/	NULL, NULL, NULL, NULL, NULL,
47555505Sshin	NULL, NULL, "udp", NULL, NULL,
47655505Sshin/*20*/	NULL, NULL, "idp", NULL, NULL,
47755505Sshin	NULL, NULL, NULL, NULL, "tp",
47855505Sshin/*30*/	NULL, NULL, NULL, NULL, NULL,
47955505Sshin	NULL, NULL, NULL, NULL, NULL,
48055505Sshin/*40*/	NULL, "ip6", NULL, "rt6", "frag6",
48155505Sshin	NULL, "rsvp", "gre", NULL, NULL,
48255505Sshin/*50*/	"esp", "ah", NULL, NULL, NULL,
48355505Sshin	NULL, NULL, NULL, "icmp6", "none",
48455505Sshin/*60*/	"dst6",
48555505Sshin};
48655505Sshin
48755505Sshin#define STR_OR_ID(x, tab) \
48855505Sshin	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
48955505Sshin
49055505Sshinconst char *
49155505Sshinnumstr(x)
49255505Sshin	int x;
49355505Sshin{
49455505Sshin	static char buf[20];
49555505Sshin	snprintf(buf, sizeof(buf), "#%d", x);
49655505Sshin	return buf;
49755505Sshin}
49855505Sshin
49955505Sshinvoid
50055505Sshinshortdump_hdr()
50155505Sshin{
50255505Sshin	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
50355505Sshin		"time", "p", "s", "spi", "ltime", "src", "dst");
50455505Sshin}
50555505Sshin
50655505Sshinvoid
50755505Sshinshortdump(msg)
50855505Sshin	struct sadb_msg *msg;
50955505Sshin{
51055505Sshin	caddr_t mhp[SADB_EXT_MAX + 1];
51155505Sshin	char buf[1024], pbuf[10];
51255505Sshin	struct sadb_sa *sa;
51355505Sshin	struct sadb_address *saddr;
51455505Sshin	struct sadb_lifetime *lts, *lth, *ltc;
51555505Sshin	struct sockaddr *s;
51655505Sshin	u_int t;
51755505Sshin	time_t cur = time(0);
51855505Sshin
51955505Sshin	pfkey_align(msg, mhp);
52055505Sshin	pfkey_check(mhp);
52155505Sshin
52255505Sshin	printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
52355505Sshin
52455505Sshin	printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
52555505Sshin
52655505Sshin	if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
52755505Sshin		printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
52855505Sshin		printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
52955505Sshin	} else
53055505Sshin		printf("%-1s %-8s", "?", "?");
53155505Sshin
53255505Sshin	lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
53355505Sshin	lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
53455505Sshin	ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
53555505Sshin	if (lts && lth && ltc) {
53655505Sshin		if (ltc->sadb_lifetime_addtime == 0)
53755505Sshin			t = (u_long)0;
53855505Sshin		else
53955505Sshin			t = (u_long)(cur - ltc->sadb_lifetime_addtime);
54055505Sshin		if (t >= 1000)
54155505Sshin			strcpy(buf, " big/");
54255505Sshin		else
54355505Sshin			snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
54455505Sshin		printf("%s", buf);
54555505Sshin
54655505Sshin		t = (u_long)lth->sadb_lifetime_addtime;
54755505Sshin		if (t >= 1000)
54855505Sshin			strcpy(buf, "big");
54955505Sshin		else
55055505Sshin			snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
55155505Sshin		printf("%s", buf);
55255505Sshin	} else
55378064Sume		printf(" ??\?/???");	/* backslash to avoid trigraph ??/ */
55455505Sshin
55555505Sshin	printf(" ");
55655505Sshin
55755505Sshin	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
55855505Sshin		if (saddr->sadb_address_proto)
55955505Sshin			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
56055505Sshin		s = (struct sockaddr *)(saddr + 1);
56155505Sshin		getnameinfo(s, s->sa_len, buf, sizeof(buf),
56255505Sshin			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
56355505Sshin		if (strcmp(pbuf, "0") != 0)
56455505Sshin			printf("%s[%s]", buf, pbuf);
56555505Sshin		else
56655505Sshin			printf("%s", buf);
56755505Sshin	} else
56855505Sshin		printf("?");
56955505Sshin
57055505Sshin	printf(" -> ");
57155505Sshin
57255505Sshin	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
57355505Sshin		if (saddr->sadb_address_proto)
57455505Sshin			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
57555505Sshin
57655505Sshin		s = (struct sockaddr *)(saddr + 1);
57755505Sshin		getnameinfo(s, s->sa_len, buf, sizeof(buf),
57855505Sshin			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
57955505Sshin		if (strcmp(pbuf, "0") != 0)
58055505Sshin			printf("%s[%s]", buf, pbuf);
58155505Sshin		else
58255505Sshin			printf("%s", buf);
58355505Sshin	} else
58455505Sshin		printf("?");
58555505Sshin
58655505Sshin	printf("\n");
58755505Sshin}
58878064Sume
58978064Sume/* From: tcpdump(1):gmt2local.c and util.c */
59078064Sume/*
59178064Sume * Print the timestamp
59278064Sume */
59378064Sumestatic void
59478064Sumeprintdate()
59578064Sume{
59678064Sume	struct timeval tp;
59778064Sume	int s;
59878064Sume
59978064Sume	if (gettimeofday(&tp, NULL) == -1) {
60078064Sume		perror("gettimeofday");
60178064Sume		return;
60278064Sume	}
60378064Sume
60478064Sume	if (f_tflag == 1) {
60578064Sume		/* Default */
60678064Sume		s = (tp.tv_sec + thiszone ) % 86400;
60778064Sume		(void)printf("%02d:%02d:%02d.%06u ",
60878064Sume		    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec);
60978064Sume	} else if (f_tflag > 1) {
61078064Sume		/* Unix timeval style */
61178064Sume		(void)printf("%u.%06u ",
61278064Sume		    (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec);
61378064Sume	}
61478064Sume
61578064Sume	printf("\n");
61678064Sume}
61778064Sume
61878064Sume/*
61978064Sume * Returns the difference between gmt and local time in seconds.
62078064Sume * Use gmtime() and localtime() to keep things simple.
62178064Sume */
62278064Sumeint32_t
62378064Sumegmt2local(time_t t)
62478064Sume{
62578064Sume	register int dt, dir;
62678064Sume	register struct tm *gmt, *loc;
62778064Sume	struct tm sgmt;
62878064Sume
62978064Sume	if (t == 0)
63078064Sume		t = time(NULL);
63178064Sume	gmt = &sgmt;
63278064Sume	*gmt = *gmtime(&t);
63378064Sume	loc = localtime(&t);
63478064Sume	dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
63578064Sume	    (loc->tm_min - gmt->tm_min) * 60;
63678064Sume
63778064Sume	/*
63878064Sume	 * If the year or julian day is different, we span 00:00 GMT
63978064Sume	 * and must add or subtract a day. Check the year first to
64078064Sume	 * avoid problems when the julian day wraps.
64178064Sume	 */
64278064Sume	dir = loc->tm_year - gmt->tm_year;
64378064Sume	if (dir == 0)
64478064Sume		dir = loc->tm_yday - gmt->tm_yday;
64578064Sume	dt += dir * 24 * 60 * 60;
64678064Sume
64778064Sume	return (dt);
64878064Sume}
649