1/*	$KAME: pfkey_dump.c,v 1.35 2001/11/13 12:38:47 jinmei Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/param.h>
34#include <sys/socket.h>
35#include <netinet/ipsec.h>
36#include <net/pfkeyv2.h>
37
38#include <netinet/in.h>
39#include <arpa/inet.h>
40
41#include <stdlib.h>
42#include <unistd.h>
43#include <stdio.h>
44#include <string.h>
45#include <time.h>
46#include <netdb.h>
47
48#include "ipsec_strerror.h"
49#include "libpfkey.h"
50#include "libipsec.h"
51
52/* cope with old kame headers - ugly */
53#ifndef SADB_X_AALG_MD5
54#define SADB_X_AALG_MD5		SADB_AALG_MD5
55#endif
56#ifndef SADB_X_AALG_SHA
57#define SADB_X_AALG_SHA		SADB_AALG_SHA
58#endif
59#ifndef SADB_X_AALG_NULL
60#define SADB_X_AALG_NULL	SADB_AALG_NULL
61#endif
62
63#ifndef SADB_X_EALG_BLOWFISHCBC
64#define SADB_X_EALG_BLOWFISHCBC	SADB_EALG_BLOWFISHCBC
65#endif
66#ifndef SADB_X_EALG_CAST128CBC
67#define SADB_X_EALG_CAST128CBC	SADB_EALG_CAST128CBC
68#endif
69#ifndef SADB_X_EALG_RC5CBC
70#ifdef SADB_EALG_RC5CBC
71#define SADB_X_EALG_RC5CBC	SADB_EALG_RC5CBC
72#endif
73#endif
74
75#define GETMSGSTR(str, num) \
76do { \
77	if (sizeof((str)[0]) == 0 \
78	 || num >= sizeof(str)/sizeof((str)[0])) \
79		printf("%d ", (num)); \
80	else if (strlen((str)[(num)]) == 0) \
81		printf("%d ", (num)); \
82	else \
83		printf("%s ", (str)[(num)]); \
84} while (0)
85
86#define GETMSGV2S(v2s, num) \
87do { \
88	struct val2str *p;  \
89	for (p = (v2s); p && p->str; p++) { \
90		if (p->val == (num)) \
91			break; \
92	} \
93	if (p && p->str) \
94		printf("%s ", p->str); \
95	else \
96		printf("%d ", (num)); \
97} while (0)
98
99static char *str_ipaddr __P((struct sockaddr *));
100static char *str_prefport __P((u_int, u_int, u_int, u_int));
101static void str_upperspec __P((u_int, u_int, u_int));
102static char *str_time __P((time_t));
103static void str_lifetime_byte __P((struct sadb_lifetime *, char *));
104
105struct val2str {
106	int val;
107	const char *str;
108};
109
110/*
111 * Must to be re-written about following strings.
112 */
113static char *str_satype[] = {
114	"unspec",
115	"unknown",
116	"ah",
117	"esp",
118	"unknown",
119	"rsvp",
120	"ospfv2",
121	"ripv2",
122	"mip",
123	"ipcomp",
124};
125
126static char *str_mode[] = {
127	"any",
128	"transport",
129	"tunnel",
130};
131
132static char *str_state[] = {
133	"larval",
134	"mature",
135	"dying",
136	"dead",
137};
138
139static struct val2str str_alg_auth[] = {
140	{ SADB_AALG_NONE, "none", },
141	{ SADB_AALG_MD5HMAC, "hmac-md5", },
142	{ SADB_AALG_SHA1HMAC, "hmac-sha1", },
143	{ SADB_X_AALG_MD5, "md5", },
144	{ SADB_X_AALG_SHA, "sha", },
145	{ SADB_X_AALG_NULL, "null", },
146#ifdef SADB_X_AALG_SHA2_256
147	{ SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
148#endif
149#ifdef SADB_X_AALG_SHA2_384
150	{ SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
151#endif
152#ifdef SADB_X_AALG_SHA2_512
153	{ SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
154#endif
155	{ -1, NULL, },
156};
157
158static struct val2str str_alg_enc[] = {
159	{ SADB_EALG_NONE, "none", },
160	{ SADB_EALG_DESCBC, "des-cbc", },
161	{ SADB_EALG_3DESCBC, "3des-cbc", },
162	{ SADB_EALG_NULL, "null", },
163#ifdef SADB_X_EALG_RC5CBC
164	{ SADB_X_EALG_RC5CBC, "rc5-cbc", },
165#endif
166	{ SADB_X_EALG_CAST128CBC, "cast128-cbc", },
167	{ SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
168#ifdef SADB_X_EALG_RIJNDAELCBC
169	{ SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", },
170#endif
171#ifdef SADB_X_EALG_TWOFISHCBC
172	{ SADB_X_EALG_TWOFISHCBC, "twofish-cbc", },
173#endif
174	{ -1, NULL, },
175};
176
177static struct val2str str_alg_comp[] = {
178	{ SADB_X_CALG_NONE, "none", },
179	{ SADB_X_CALG_OUI, "oui", },
180	{ SADB_X_CALG_DEFLATE, "deflate", },
181	{ SADB_X_CALG_LZS, "lzs", },
182	{ -1, NULL, },
183};
184
185/*
186 * dump SADB_MSG formated.  For debugging, you should use kdebug_sadb().
187 */
188void
189pfkey_sadump(m)
190	struct sadb_msg *m;
191{
192	caddr_t mhp[SADB_EXT_MAX + 1];
193	struct sadb_sa *m_sa;
194	struct sadb_x_sa2 *m_sa2;
195	struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts;
196	struct sadb_address *m_saddr, *m_daddr, *m_paddr;
197	struct sadb_key *m_auth, *m_enc;
198	struct sadb_ident *m_sid, *m_did;
199	struct sadb_sens *m_sens;
200
201	/* check pfkey message. */
202	if (pfkey_align(m, mhp)) {
203		printf("%s\n", ipsec_strerror());
204		return;
205	}
206	if (pfkey_check(mhp)) {
207		printf("%s\n", ipsec_strerror());
208		return;
209	}
210
211	m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
212	m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2];
213	m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
214	m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
215	m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
216	m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
217	m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
218	m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY];
219	m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH];
220	m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT];
221	m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC];
222	m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST];
223	m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY];
224
225	/* source address */
226	if (m_saddr == NULL) {
227		printf("no ADDRESS_SRC extension.\n");
228		return;
229	}
230	printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1)));
231
232	/* destination address */
233	if (m_daddr == NULL) {
234		printf("no ADDRESS_DST extension.\n");
235		return;
236	}
237	printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1)));
238
239	/* SA type */
240	if (m_sa == NULL) {
241		printf("no SA extension.\n");
242		return;
243	}
244	if (m_sa2 == NULL) {
245		printf("no SA2 extension.\n");
246		return;
247	}
248	printf("\n\t");
249
250	GETMSGSTR(str_satype, m->sadb_msg_satype);
251
252	printf("mode=");
253	GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode);
254
255	printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n",
256		(u_int32_t)ntohl(m_sa->sadb_sa_spi),
257		(u_int32_t)ntohl(m_sa->sadb_sa_spi),
258		(u_int32_t)m_sa2->sadb_x_sa2_reqid,
259		(u_int32_t)m_sa2->sadb_x_sa2_reqid);
260
261	/* encryption key */
262	if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
263		printf("\tC: ");
264		GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt);
265	} else if (m->sadb_msg_satype == SADB_SATYPE_ESP) {
266		if (m_enc != NULL) {
267			printf("\tE: ");
268			GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt);
269			ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc),
270				      m_enc->sadb_key_bits / 8);
271			printf("\n");
272		}
273	}
274
275	/* authentication key */
276	if (m_auth != NULL) {
277		printf("\tA: ");
278		GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth);
279		ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth),
280		              m_auth->sadb_key_bits / 8);
281		printf("\n");
282	}
283
284	/* replay windoe size & flags */
285	printf("\tseq=0x%08x replay=%u flags=0x%08x ",
286		m_sa2->sadb_x_sa2_sequence,
287		m_sa->sadb_sa_replay,
288		m_sa->sadb_sa_flags);
289
290	/* state */
291	printf("state=");
292	GETMSGSTR(str_state, m_sa->sadb_sa_state);
293	printf("\n");
294
295	/* lifetime */
296	if (m_lftc != NULL) {
297		time_t tmp_time = time(0);
298
299		printf("\tcreated: %s",
300			str_time(m_lftc->sadb_lifetime_addtime));
301		printf("\tcurrent: %s\n", str_time(tmp_time));
302		printf("\tdiff: %lu(s)",
303			(u_long)(m_lftc->sadb_lifetime_addtime == 0 ?
304			0 : (tmp_time - m_lftc->sadb_lifetime_addtime)));
305
306		printf("\thard: %lu(s)",
307			(u_long)(m_lfth == NULL ?
308			0 : m_lfth->sadb_lifetime_addtime));
309		printf("\tsoft: %lu(s)\n",
310			(u_long)(m_lfts == NULL ?
311			0 : m_lfts->sadb_lifetime_addtime));
312
313		printf("\tlast: %s",
314			str_time(m_lftc->sadb_lifetime_usetime));
315		printf("\thard: %lu(s)",
316			(u_long)(m_lfth == NULL ?
317			0 : m_lfth->sadb_lifetime_usetime));
318		printf("\tsoft: %lu(s)\n",
319			(u_long)(m_lfts == NULL ?
320			0 : m_lfts->sadb_lifetime_usetime));
321
322		str_lifetime_byte(m_lftc, "current");
323		str_lifetime_byte(m_lfth, "hard");
324		str_lifetime_byte(m_lfts, "soft");
325		printf("\n");
326
327		printf("\tallocated: %lu",
328			(unsigned long)m_lftc->sadb_lifetime_allocations);
329		printf("\thard: %lu",
330			(u_long)(m_lfth == NULL ?
331			0 : m_lfth->sadb_lifetime_allocations));
332		printf("\tsoft: %lu\n",
333			(u_long)(m_lfts == NULL ?
334			0 : m_lfts->sadb_lifetime_allocations));
335	}
336
337	printf("\tsadb_seq=%lu pid=%lu ",
338		(u_long)m->sadb_msg_seq,
339		(u_long)m->sadb_msg_pid);
340
341	printf("refcnt=%u\n", m->sadb_msg_reserved);
342
343	return;
344}
345
346void
347pfkey_spdump(m)
348	struct sadb_msg *m;
349{
350	char pbuf[NI_MAXSERV];
351	caddr_t mhp[SADB_EXT_MAX + 1];
352	struct sadb_address *m_saddr, *m_daddr;
353	struct sadb_x_policy *m_xpl;
354	struct sadb_lifetime *m_lftc = NULL, *m_lfth = NULL;
355	struct sockaddr *sa;
356	u_int16_t sport = 0, dport = 0;
357
358	/* check pfkey message. */
359	if (pfkey_align(m, mhp)) {
360		printf("%s\n", ipsec_strerror());
361		return;
362	}
363	if (pfkey_check(mhp)) {
364		printf("%s\n", ipsec_strerror());
365		return;
366	}
367
368	m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
369	m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
370	m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
371	m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
372	m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
373
374	/* source address */
375	if (m_saddr == NULL) {
376		printf("no ADDRESS_SRC extension.\n");
377		return;
378	}
379	sa = (struct sockaddr *)(m_saddr + 1);
380	switch (sa->sa_family) {
381	case AF_INET:
382	case AF_INET6:
383		if (getnameinfo(sa, sysdep_sa_len(sa), NULL, 0, pbuf, sizeof(pbuf),
384		    NI_NUMERICSERV) != 0)
385			sport = 0;
386		else
387			sport = atoi(pbuf);
388		printf("%s%s ", str_ipaddr(sa),
389			str_prefport(sa->sa_family,
390			    m_saddr->sadb_address_prefixlen, sport,
391			    m_saddr->sadb_address_proto));
392		break;
393	default:
394		printf("unknown-af ");
395		break;
396	}
397
398	/* destination address */
399	if (m_daddr == NULL) {
400		printf("no ADDRESS_DST extension.\n");
401		return;
402	}
403	sa = (struct sockaddr *)(m_daddr + 1);
404	switch (sa->sa_family) {
405	case AF_INET:
406	case AF_INET6:
407		if (getnameinfo(sa, sysdep_sa_len(sa), NULL, 0, pbuf, sizeof(pbuf),
408		    NI_NUMERICSERV) != 0)
409			dport = 0;
410		else
411			dport = atoi(pbuf);
412		printf("%s%s ", str_ipaddr(sa),
413			str_prefport(sa->sa_family,
414			    m_daddr->sadb_address_prefixlen, dport,
415			    m_saddr->sadb_address_proto));
416		break;
417	default:
418		printf("unknown-af ");
419		break;
420	}
421
422	/* upper layer protocol */
423	if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) {
424		printf("upper layer protocol mismatched.\n");
425		return;
426	}
427	str_upperspec(m_saddr->sadb_address_proto, sport, dport);
428
429	/* policy */
430    {
431	char *d_xpl;
432
433	if (m_xpl == NULL) {
434		printf("no X_POLICY extension.\n");
435		return;
436	}
437	d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t");
438	if (!d_xpl)
439		printf("\n\tPolicy:[%s]\n", ipsec_strerror());
440	else {
441		/* dump SPD */
442		printf("\n\t%s\n", d_xpl);
443		free(d_xpl);
444	}
445    }
446
447	/* lifetime */
448	if (m_lftc) {
449		printf("\tcreated:%s ",
450			str_time(m_lftc->sadb_lifetime_addtime));
451		printf("lastused:%s\n",
452			str_time(m_lftc->sadb_lifetime_usetime));
453	}
454	if (m_lfth) {
455		printf("\tlifetime:%lu(s) ",
456			(u_long)m_lfth->sadb_lifetime_addtime);
457		printf("validtime:%lu(s)\n",
458			(u_long)m_lfth->sadb_lifetime_usetime);
459	}
460
461
462	printf("\tspid=%ld seq=%ld pid=%ld\n",
463		(u_long)m_xpl->sadb_x_policy_id,
464		(u_long)m->sadb_msg_seq,
465		(u_long)m->sadb_msg_pid);
466
467	printf("\trefcnt=%u\n", m->sadb_msg_reserved);
468
469	return;
470}
471
472/*
473 * set "ipaddress" to buffer.
474 */
475static char *
476str_ipaddr(sa)
477	struct sockaddr *sa;
478{
479	static char buf[NI_MAXHOST];
480	const int niflag = NI_NUMERICHOST;
481
482	if (sa == NULL)
483		return "";
484
485	if (getnameinfo(sa, sysdep_sa_len(sa), buf, sizeof(buf), NULL, 0, niflag) == 0)
486		return buf;
487	return NULL;
488}
489
490/*
491 * set "/prefix[port number]" to buffer.
492 */
493static char *
494str_prefport(family, pref, port, ulp)
495	u_int family, pref, port, ulp;
496{
497	static char buf[128];
498	char prefbuf[10];
499	char portbuf[10];
500	int plen;
501
502	switch (family) {
503	case AF_INET:
504		plen = sizeof(struct in_addr) << 3;
505		break;
506	case AF_INET6:
507		plen = sizeof(struct in6_addr) << 3;
508		break;
509	default:
510		return "?";
511	}
512
513	if (pref == plen)
514		prefbuf[0] = '\0';
515	else
516		snprintf(prefbuf, sizeof(prefbuf), "/%u", pref);
517
518	if (ulp == IPPROTO_ICMPV6)
519		memset(portbuf, 0, sizeof(portbuf));
520	else if (ulp != IPPROTO_ICMPV6 && port == IPSEC_PORT_ANY)
521		snprintf(portbuf, sizeof(portbuf), "[%s]", "any");
522	else
523		snprintf(portbuf, sizeof(portbuf), "[%u]", port);
524
525	snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf);
526
527	return buf;
528}
529
530static void
531str_upperspec(ulp, p1, p2)
532	u_int ulp, p1, p2;
533{
534	if (ulp == IPSEC_ULPROTO_ANY)
535		printf("any");
536	else if (ulp == IPPROTO_ICMPV6) {
537		printf("icmp6");
538		if (!(p1 == IPSEC_PORT_ANY && p2 == IPSEC_PORT_ANY))
539			printf(" %d,%d", p1, p2);
540	} else {
541		struct protoent *ent;
542
543		switch (ulp) {
544		case IPPROTO_IPIP:
545			printf("ip4");
546			break;
547		default:
548			ent = getprotobynumber(ulp);
549			if (ent)
550				printf("%s", ent->p_name);
551			else
552				printf("%d", ulp);
553
554			endprotoent();
555			break;
556		}
557	}
558}
559
560/*
561 * set "Mon Day Time Year" to buffer
562 */
563static char *
564str_time(t)
565	time_t t;
566{
567	static char buf[128];
568
569	if (t == 0) {
570		int i = 0;
571		for (;i < 20;) buf[i++] = ' ';
572	} else {
573		char *t0;
574		t0 = ctime(&t);
575		memcpy(buf, t0 + 4, 20);
576	}
577
578	buf[20] = '\0';
579
580	return(buf);
581}
582
583static void
584str_lifetime_byte(x, str)
585	struct sadb_lifetime *x;
586	char *str;
587{
588	double y;
589	char *unit;
590	int w;
591
592	if (x == NULL) {
593		printf("\t%s: 0(bytes)", str);
594		return;
595	}
596
597	y = (x->sadb_lifetime_bytes) * 1.0;
598	unit = "";
599	w = 0;
600	printf("\t%s: %.*f(%sbytes)", str, w, y, unit);
601}
602