xref: /freebsd/contrib/tcpdump/print-isakmp.c (revision 6fd05b64b5b65dd4ba9b86482a0634a5f0b96c29)
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 #ifndef lint
32 static const char rcsid[] _U_ =
33     "@(#) $Header: /tcpdump/master/tcpdump/print-isakmp.c,v 1.36.2.11 2004/03/24 01:32:42 guy Exp $ (LBL)";
34 #endif
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <tcpdump-stdinc.h>
41 
42 #include <string.h>
43 
44 #include <stdio.h>
45 
46 #include "isakmp.h"
47 #include "ipsec_doi.h"
48 #include "oakley.h"
49 #include "interface.h"
50 #include "addrtoname.h"
51 #include "extract.h"                    /* must come after interface.h */
52 
53 #include "ip.h"
54 #ifdef INET6
55 #include "ip6.h"
56 #endif
57 
58 #ifndef HAVE_SOCKADDR_STORAGE
59 #define sockaddr_storage sockaddr
60 #endif
61 
62 static const u_char *isakmp_sa_print(const struct isakmp_gen *,
63 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
64 static const u_char *isakmp_p_print(const struct isakmp_gen *,
65 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
66 static const u_char *isakmp_t_print(const struct isakmp_gen *,
67 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
68 static const u_char *isakmp_ke_print(const struct isakmp_gen *,
69 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
70 static const u_char *isakmp_id_print(const struct isakmp_gen *,
71 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
72 static const u_char *isakmp_cert_print(const struct isakmp_gen *,
73 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
74 static const u_char *isakmp_cr_print(const struct isakmp_gen *,
75 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
76 static const u_char *isakmp_sig_print(const struct isakmp_gen *,
77 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
78 static const u_char *isakmp_hash_print(const struct isakmp_gen *,
79 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
80 static const u_char *isakmp_nonce_print(const struct isakmp_gen *,
81 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
82 static const u_char *isakmp_n_print(const struct isakmp_gen *,
83 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
84 static const u_char *isakmp_d_print(const struct isakmp_gen *,
85 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
86 static const u_char *isakmp_vid_print(const struct isakmp_gen *,
87 	u_int, const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
88 static const u_char *isakmp_sub0_print(u_char, const struct isakmp_gen *,
89 	const u_char *,	u_int32_t, u_int32_t, u_int32_t, int);
90 static const u_char *isakmp_sub_print(u_char, const struct isakmp_gen *,
91 	const u_char *, u_int32_t, u_int32_t, u_int32_t, int);
92 static char *numstr(int);
93 static void safememcpy(void *, const void *, size_t);
94 
95 #define MAXINITIATORS	20
96 int ninitiator = 0;
97 struct {
98 	cookie_t initiator;
99 	struct sockaddr_storage iaddr;
100 	struct sockaddr_storage raddr;
101 } cookiecache[MAXINITIATORS];
102 
103 /* protocol id */
104 static const char *protoidstr[] = {
105 	NULL, "isakmp", "ipsec-ah", "ipsec-esp", "ipcomp",
106 };
107 
108 /* isakmp->np */
109 static const char *npstr[] = {
110 	"none", "sa", "p", "t", "ke", "id", "cert", "cr", "hash",
111 	"sig", "nonce", "n", "d", "vid"
112 };
113 
114 /* isakmp->np */
115 static const u_char *(*npfunc[])(const struct isakmp_gen *, u_int,
116 		const u_char *, u_int32_t, u_int32_t, u_int32_t, int) = {
117 	NULL,
118 	isakmp_sa_print,
119 	isakmp_p_print,
120 	isakmp_t_print,
121 	isakmp_ke_print,
122 	isakmp_id_print,
123 	isakmp_cert_print,
124 	isakmp_cr_print,
125 	isakmp_hash_print,
126 	isakmp_sig_print,
127 	isakmp_nonce_print,
128 	isakmp_n_print,
129 	isakmp_d_print,
130 	isakmp_vid_print,
131 };
132 
133 /* isakmp->etype */
134 static const char *etypestr[] = {
135 	"none", "base", "ident", "auth", "agg", "inf", NULL, NULL,
136 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
137 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
138 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
139 	"oakley-quick", "oakley-newgroup",
140 };
141 
142 #define STR_OR_ID(x, tab) \
143 	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
144 #define PROTOIDSTR(x)	STR_OR_ID(x, protoidstr)
145 #define NPSTR(x)	STR_OR_ID(x, npstr)
146 #define ETYPESTR(x)	STR_OR_ID(x, etypestr)
147 
148 #define NPFUNC(x) \
149 	(((x) < sizeof(npfunc)/sizeof(npfunc[0]) && npfunc[(x)]) \
150 		? npfunc[(x)] : NULL)
151 
152 static int
153 iszero(u_char *p, size_t l)
154 {
155 	while (l--) {
156 		if (*p++)
157 			return 0;
158 	}
159 	return 1;
160 }
161 
162 /* find cookie from initiator cache */
163 static int
164 cookie_find(cookie_t *in)
165 {
166 	int i;
167 
168 	for (i = 0; i < MAXINITIATORS; i++) {
169 		if (memcmp(in, &cookiecache[i].initiator, sizeof(*in)) == 0)
170 			return i;
171 	}
172 
173 	return -1;
174 }
175 
176 /* record initiator */
177 static void
178 cookie_record(cookie_t *in, const u_char *bp2)
179 {
180 	int i;
181 	struct ip *ip;
182 	struct sockaddr_in *sin;
183 #ifdef INET6
184 	struct ip6_hdr *ip6;
185 	struct sockaddr_in6 *sin6;
186 #endif
187 
188 	i = cookie_find(in);
189 	if (0 <= i) {
190 		ninitiator = (i + 1) % MAXINITIATORS;
191 		return;
192 	}
193 
194 	ip = (struct ip *)bp2;
195 	switch (IP_V(ip)) {
196 	case 4:
197 		memset(&cookiecache[ninitiator].iaddr, 0,
198 			sizeof(cookiecache[ninitiator].iaddr));
199 		memset(&cookiecache[ninitiator].raddr, 0,
200 			sizeof(cookiecache[ninitiator].raddr));
201 
202 		sin = (struct sockaddr_in *)&cookiecache[ninitiator].iaddr;
203 #ifdef HAVE_SOCKADDR_SA_LEN
204 		sin->sin_len = sizeof(struct sockaddr_in);
205 #endif
206 		sin->sin_family = AF_INET;
207 		memcpy(&sin->sin_addr, &ip->ip_src, sizeof(ip->ip_src));
208 		sin = (struct sockaddr_in *)&cookiecache[ninitiator].raddr;
209 #ifdef HAVE_SOCKADDR_SA_LEN
210 		sin->sin_len = sizeof(struct sockaddr_in);
211 #endif
212 		sin->sin_family = AF_INET;
213 		memcpy(&sin->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
214 		break;
215 #ifdef INET6
216 	case 6:
217 		memset(&cookiecache[ninitiator].iaddr, 0,
218 			sizeof(cookiecache[ninitiator].iaddr));
219 		memset(&cookiecache[ninitiator].raddr, 0,
220 			sizeof(cookiecache[ninitiator].raddr));
221 
222 		ip6 = (struct ip6_hdr *)bp2;
223 		sin6 = (struct sockaddr_in6 *)&cookiecache[ninitiator].iaddr;
224 #ifdef HAVE_SOCKADDR_SA_LEN
225 		sin6->sin6_len = sizeof(struct sockaddr_in6);
226 #endif
227 		sin6->sin6_family = AF_INET6;
228 		memcpy(&sin6->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
229 		sin6 = (struct sockaddr_in6 *)&cookiecache[ninitiator].raddr;
230 #ifdef HAVE_SOCKADDR_SA_LEN
231 		sin6->sin6_len = sizeof(struct sockaddr_in6);
232 #endif
233 		sin6->sin6_family = AF_INET6;
234 		memcpy(&sin6->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
235 		break;
236 #endif
237 	default:
238 		return;
239 	}
240 	memcpy(&cookiecache[ninitiator].initiator, in, sizeof(*in));
241 	ninitiator = (ninitiator + 1) % MAXINITIATORS;
242 }
243 
244 #define cookie_isinitiator(x, y)	cookie_sidecheck((x), (y), 1)
245 #define cookie_isresponder(x, y)	cookie_sidecheck((x), (y), 0)
246 static int
247 cookie_sidecheck(int i, const u_char *bp2, int initiator)
248 {
249 	struct sockaddr_storage ss;
250 	struct sockaddr *sa;
251 	struct ip *ip;
252 	struct sockaddr_in *sin;
253 #ifdef INET6
254 	struct ip6_hdr *ip6;
255 	struct sockaddr_in6 *sin6;
256 #endif
257 	int salen;
258 
259 	memset(&ss, 0, sizeof(ss));
260 	ip = (struct ip *)bp2;
261 	switch (IP_V(ip)) {
262 	case 4:
263 		sin = (struct sockaddr_in *)&ss;
264 #ifdef HAVE_SOCKADDR_SA_LEN
265 		sin->sin_len = sizeof(struct sockaddr_in);
266 #endif
267 		sin->sin_family = AF_INET;
268 		memcpy(&sin->sin_addr, &ip->ip_src, sizeof(ip->ip_src));
269 		break;
270 #ifdef INET6
271 	case 6:
272 		ip6 = (struct ip6_hdr *)bp2;
273 		sin6 = (struct sockaddr_in6 *)&ss;
274 #ifdef HAVE_SOCKADDR_SA_LEN
275 		sin6->sin6_len = sizeof(struct sockaddr_in6);
276 #endif
277 		sin6->sin6_family = AF_INET6;
278 		memcpy(&sin6->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
279 		break;
280 #endif
281 	default:
282 		return 0;
283 	}
284 
285 	sa = (struct sockaddr *)&ss;
286 	if (initiator) {
287 		if (sa->sa_family != ((struct sockaddr *)&cookiecache[i].iaddr)->sa_family)
288 			return 0;
289 #ifdef HAVE_SOCKADDR_SA_LEN
290 		salen = sa->sa_len;
291 #else
292 #ifdef INET6
293 		if (sa->sa_family == AF_INET6)
294 			salen = sizeof(struct sockaddr_in6);
295 		else
296 			salen = sizeof(struct sockaddr);
297 #else
298 		salen = sizeof(struct sockaddr);
299 #endif
300 #endif
301 		if (memcmp(&ss, &cookiecache[i].iaddr, salen) == 0)
302 			return 1;
303 	} else {
304 		if (sa->sa_family != ((struct sockaddr *)&cookiecache[i].raddr)->sa_family)
305 			return 0;
306 #ifdef HAVE_SOCKADDR_SA_LEN
307 		salen = sa->sa_len;
308 #else
309 #ifdef INET6
310 		if (sa->sa_family == AF_INET6)
311 			salen = sizeof(struct sockaddr_in6);
312 		else
313 			salen = sizeof(struct sockaddr);
314 #else
315 		salen = sizeof(struct sockaddr);
316 #endif
317 #endif
318 		if (memcmp(&ss, &cookiecache[i].raddr, salen) == 0)
319 			return 1;
320 	}
321 	return 0;
322 }
323 
324 static int
325 rawprint(caddr_t loc, size_t len)
326 {
327 	static u_char *p;
328 	size_t i;
329 
330 	TCHECK2(*loc, len);
331 
332 	p = (u_char *)loc;
333 	for (i = 0; i < len; i++)
334 		printf("%02x", p[i] & 0xff);
335 	return 1;
336 trunc:
337 	return 0;
338 }
339 
340 struct attrmap {
341 	const char *type;
342 	u_int nvalue;
343 	const char *value[30];	/*XXX*/
344 };
345 
346 static const u_char *
347 isakmp_attrmap_print(const u_char *p, const u_char *ep,
348 	const struct attrmap *map, size_t nmap)
349 {
350 	u_int16_t *q;
351 	int totlen;
352 	u_int32_t t, v;
353 
354 	q = (u_int16_t *)p;
355 	if (p[0] & 0x80)
356 		totlen = 4;
357 	else
358 		totlen = 4 + EXTRACT_16BITS(&q[1]);
359 	if (ep < p + totlen) {
360 		printf("[|attr]");
361 		return ep + 1;
362 	}
363 
364 	printf("(");
365 	t = EXTRACT_16BITS(&q[0]) & 0x7fff;
366 	if (map && t < nmap && map[t].type)
367 		printf("type=%s ", map[t].type);
368 	else
369 		printf("type=#%d ", t);
370 	if (p[0] & 0x80) {
371 		printf("value=");
372 		v = EXTRACT_16BITS(&q[1]);
373 		if (map && t < nmap && v < map[t].nvalue && map[t].value[v])
374 			printf("%s", map[t].value[v]);
375 		else
376 			rawprint((caddr_t)&q[1], 2);
377 	} else {
378 		printf("len=%d value=", EXTRACT_16BITS(&q[1]));
379 		rawprint((caddr_t)&p[4], EXTRACT_16BITS(&q[1]));
380 	}
381 	printf(")");
382 	return p + totlen;
383 }
384 
385 static const u_char *
386 isakmp_attr_print(const u_char *p, const u_char *ep)
387 {
388 	u_int16_t *q;
389 	int totlen;
390 	u_int32_t t;
391 
392 	q = (u_int16_t *)p;
393 	if (p[0] & 0x80)
394 		totlen = 4;
395 	else
396 		totlen = 4 + EXTRACT_16BITS(&q[1]);
397 	if (ep < p + totlen) {
398 		printf("[|attr]");
399 		return ep + 1;
400 	}
401 
402 	printf("(");
403 	t = EXTRACT_16BITS(&q[0]) & 0x7fff;
404 	printf("type=#%d ", t);
405 	if (p[0] & 0x80) {
406 		printf("value=");
407 		t = q[1];
408 		rawprint((caddr_t)&q[1], 2);
409 	} else {
410 		printf("len=%d value=", EXTRACT_16BITS(&q[1]));
411 		rawprint((caddr_t)&p[2], EXTRACT_16BITS(&q[1]));
412 	}
413 	printf(")");
414 	return p + totlen;
415 }
416 
417 static const u_char *
418 isakmp_sa_print(const struct isakmp_gen *ext, u_int item_len,
419 	const u_char *ep, u_int32_t phase, u_int32_t doi0 _U_,
420 	u_int32_t proto0, int depth)
421 {
422 	const struct isakmp_pl_sa *p;
423 	struct isakmp_pl_sa sa;
424 	const u_int32_t *q;
425 	u_int32_t doi, sit, ident;
426 	const u_char *cp, *np;
427 	int t;
428 
429 	printf("%s:", NPSTR(ISAKMP_NPTYPE_SA));
430 
431 	p = (struct isakmp_pl_sa *)ext;
432 	TCHECK(*p);
433 	safememcpy(&sa, ext, sizeof(sa));
434 	doi = ntohl(sa.doi);
435 	sit = ntohl(sa.sit);
436 	if (doi != 1) {
437 		printf(" doi=%d", doi);
438 		printf(" situation=%u", (u_int32_t)ntohl(sa.sit));
439 		return (u_char *)(p + 1);
440 	}
441 
442 	printf(" doi=ipsec");
443 	q = (u_int32_t *)&sa.sit;
444 	printf(" situation=");
445 	t = 0;
446 	if (sit & 0x01) {
447 		printf("identity");
448 		t++;
449 	}
450 	if (sit & 0x02) {
451 		printf("%ssecrecy", t ? "+" : "");
452 		t++;
453 	}
454 	if (sit & 0x04)
455 		printf("%sintegrity", t ? "+" : "");
456 
457 	np = (u_char *)ext + sizeof(sa);
458 	if (sit != 0x01) {
459 		TCHECK2(*(ext + 1), sizeof(ident));
460 		safememcpy(&ident, ext + 1, sizeof(ident));
461 		printf(" ident=%u", (u_int32_t)ntohl(ident));
462 		np += sizeof(ident);
463 	}
464 
465 	ext = (struct isakmp_gen *)np;
466 	TCHECK(*ext);
467 
468 	cp = isakmp_sub_print(ISAKMP_NPTYPE_P, ext, ep, phase, doi, proto0,
469 		depth);
470 
471 	return cp;
472 trunc:
473 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_SA));
474 	return NULL;
475 }
476 
477 static const u_char *
478 isakmp_p_print(const struct isakmp_gen *ext, u_int item_len,
479 	const u_char *ep, u_int32_t phase, u_int32_t doi0,
480 	u_int32_t proto0 _U_, int depth)
481 {
482 	const struct isakmp_pl_p *p;
483 	struct isakmp_pl_p prop;
484 	const u_char *cp;
485 
486 	printf("%s:", NPSTR(ISAKMP_NPTYPE_P));
487 
488 	p = (struct isakmp_pl_p *)ext;
489 	TCHECK(*p);
490 	safememcpy(&prop, ext, sizeof(prop));
491 	printf(" #%d protoid=%s transform=%d",
492 		prop.p_no, PROTOIDSTR(prop.prot_id), prop.num_t);
493 	if (prop.spi_size) {
494 		printf(" spi=");
495 		if (!rawprint((caddr_t)(p + 1), prop.spi_size))
496 			goto trunc;
497 	}
498 
499 	ext = (struct isakmp_gen *)((u_char *)(p + 1) + prop.spi_size);
500 	TCHECK(*ext);
501 
502 	cp = isakmp_sub_print(ISAKMP_NPTYPE_T, ext, ep, phase, doi0,
503 		prop.prot_id, depth);
504 
505 	return cp;
506 trunc:
507 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_P));
508 	return NULL;
509 }
510 
511 static const char *isakmp_p_map[] = {
512 	NULL, "ike",
513 };
514 
515 static const char *ah_p_map[] = {
516 	NULL, "(reserved)", "md5", "sha", "1des",
517 	"sha2-256", "sha2-384", "sha2-512",
518 };
519 
520 static const char *esp_p_map[] = {
521 	NULL, "1des-iv64", "1des", "3des", "rc5", "idea", "cast",
522 	"blowfish", "3idea", "1des-iv32", "rc4", "null", "aes"
523 };
524 
525 static const char *ipcomp_p_map[] = {
526 	NULL, "oui", "deflate", "lzs",
527 };
528 
529 const struct attrmap ipsec_t_map[] = {
530 	{ NULL,	0, { NULL } },
531 	{ "lifetype", 3, { NULL, "sec", "kb", }, },
532 	{ "life", 0, { NULL } },
533 	{ "group desc", 5,	{ NULL, "modp768", "modp1024", "EC2N 2^155",
534 				  "EC2N 2^185", }, },
535 	{ "enc mode", 3, { NULL, "tunnel", "transport", }, },
536 	{ "auth", 5, { NULL, "hmac-md5", "hmac-sha1", "1des-mac", "keyed", }, },
537 	{ "keylen", 0, { NULL } },
538 	{ "rounds", 0, { NULL } },
539 	{ "dictsize", 0, { NULL } },
540 	{ "privalg", 0, { NULL } },
541 };
542 
543 const struct attrmap oakley_t_map[] = {
544 	{ NULL,	0, { NULL } },
545 	{ "enc", 8,	{ NULL, "1des", "idea", "blowfish", "rc5",
546 		 	  "3des", "cast", "aes", }, },
547 	{ "hash", 7,	{ NULL, "md5", "sha1", "tiger",
548 			  "sha2-256", "sha2-384", "sha2-512", }, },
549 	{ "auth", 6,	{ NULL, "preshared", "dss", "rsa sig", "rsa enc",
550 			  "rsa enc revised", }, },
551 	{ "group desc", 5,	{ NULL, "modp768", "modp1024", "EC2N 2^155",
552 				  "EC2N 2^185", }, },
553 	{ "group type", 4,	{ NULL, "MODP", "ECP", "EC2N", }, },
554 	{ "group prime", 0, { NULL } },
555 	{ "group gen1", 0, { NULL } },
556 	{ "group gen2", 0, { NULL } },
557 	{ "group curve A", 0, { NULL } },
558 	{ "group curve B", 0, { NULL } },
559 	{ "lifetype", 3,	{ NULL, "sec", "kb", }, },
560 	{ "lifeduration", 0, { NULL } },
561 	{ "prf", 0, { NULL } },
562 	{ "keylen", 0, { NULL } },
563 	{ "field", 0, { NULL } },
564 	{ "order", 0, { NULL } },
565 };
566 
567 static const u_char *
568 isakmp_t_print(const struct isakmp_gen *ext, u_int item_len,
569 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi _U_,
570 	u_int32_t proto, int depth _U_)
571 {
572 	const struct isakmp_pl_t *p;
573 	struct isakmp_pl_t t;
574 	const u_char *cp;
575 	const char *idstr;
576 	const struct attrmap *map;
577 	size_t nmap;
578 	const u_char *ep2;
579 
580 	printf("%s:", NPSTR(ISAKMP_NPTYPE_T));
581 
582 	p = (struct isakmp_pl_t *)ext;
583 	TCHECK(*p);
584 	safememcpy(&t, ext, sizeof(t));
585 
586 	switch (proto) {
587 	case 1:
588 		idstr = STR_OR_ID(t.t_id, isakmp_p_map);
589 		map = oakley_t_map;
590 		nmap = sizeof(oakley_t_map)/sizeof(oakley_t_map[0]);
591 		break;
592 	case 2:
593 		idstr = STR_OR_ID(t.t_id, ah_p_map);
594 		map = ipsec_t_map;
595 		nmap = sizeof(ipsec_t_map)/sizeof(ipsec_t_map[0]);
596 		break;
597 	case 3:
598 		idstr = STR_OR_ID(t.t_id, esp_p_map);
599 		map = ipsec_t_map;
600 		nmap = sizeof(ipsec_t_map)/sizeof(ipsec_t_map[0]);
601 		break;
602 	case 4:
603 		idstr = STR_OR_ID(t.t_id, ipcomp_p_map);
604 		map = ipsec_t_map;
605 		nmap = sizeof(ipsec_t_map)/sizeof(ipsec_t_map[0]);
606 		break;
607 	default:
608 		idstr = NULL;
609 		map = NULL;
610 		nmap = 0;
611 		break;
612 	}
613 
614 	if (idstr)
615 		printf(" #%d id=%s ", t.t_no, idstr);
616 	else
617 		printf(" #%d id=%d ", t.t_no, t.t_id);
618 	cp = (u_char *)(p + 1);
619 	ep2 = (u_char *)p + item_len;
620 	while (cp < ep && cp < ep2) {
621 		if (map && nmap) {
622 			cp = isakmp_attrmap_print(cp, (ep < ep2) ? ep : ep2,
623 				map, nmap);
624 		} else
625 			cp = isakmp_attr_print(cp, (ep < ep2) ? ep : ep2);
626 	}
627 	if (ep < ep2)
628 		printf("...");
629 	return cp;
630 trunc:
631 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_T));
632 	return NULL;
633 }
634 
635 static const u_char *
636 isakmp_ke_print(const struct isakmp_gen *ext, u_int item_len,
637 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi _U_,
638 	u_int32_t proto _U_, int depth _U_)
639 {
640 	struct isakmp_gen e;
641 
642 	printf("%s:", NPSTR(ISAKMP_NPTYPE_KE));
643 
644 	TCHECK(*ext);
645 	safememcpy(&e, ext, sizeof(e));
646 	printf(" key len=%d", ntohs(e.len) - 4);
647 	if (2 < vflag && 4 < ntohs(e.len)) {
648 		printf(" ");
649 		if (!rawprint((caddr_t)(ext + 1), ntohs(e.len) - 4))
650 			goto trunc;
651 	}
652 	return (u_char *)ext + ntohs(e.len);
653 trunc:
654 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_KE));
655 	return NULL;
656 }
657 
658 static const u_char *
659 isakmp_id_print(const struct isakmp_gen *ext, u_int item_len,
660 	const u_char *ep, u_int32_t phase, u_int32_t doi _U_,
661 	u_int32_t proto _U_, int depth _U_)
662 {
663 #define USE_IPSECDOI_IN_PHASE1	1
664 	const struct isakmp_pl_id *p;
665 	struct isakmp_pl_id id;
666 	static const char *idtypestr[] = {
667 		"IPv4", "IPv4net", "IPv6", "IPv6net",
668 	};
669 	static const char *ipsecidtypestr[] = {
670 		NULL, "IPv4", "FQDN", "user FQDN", "IPv4net", "IPv6",
671 		"IPv6net", "IPv4range", "IPv6range", "ASN1 DN", "ASN1 GN",
672 		"keyid",
673 	};
674 	int len;
675 	const u_char *data;
676 
677 	printf("%s:", NPSTR(ISAKMP_NPTYPE_ID));
678 
679 	p = (struct isakmp_pl_id *)ext;
680 	TCHECK(*p);
681 	safememcpy(&id, ext, sizeof(id));
682 	if (sizeof(*p) < item_len) {
683 		data = (u_char *)(p + 1);
684 		len = item_len - sizeof(*p);
685 	} else {
686 		data = NULL;
687 		len = 0;
688 	}
689 
690 #if 0 /*debug*/
691 	printf(" [phase=%d doi=%d proto=%d]", phase, doi, proto);
692 #endif
693 	switch (phase) {
694 #ifndef USE_IPSECDOI_IN_PHASE1
695 	case 1:
696 #endif
697 	default:
698 		printf(" idtype=%s", STR_OR_ID(id.d.id_type, idtypestr));
699 		printf(" doi_data=%u",
700 			(u_int32_t)(ntohl(id.d.doi_data) & 0xffffff));
701 		break;
702 
703 #ifdef USE_IPSECDOI_IN_PHASE1
704 	case 1:
705 #endif
706 	case 2:
707 	    {
708 		const struct ipsecdoi_id *p;
709 		struct ipsecdoi_id id;
710 		struct protoent *pe;
711 
712 		p = (struct ipsecdoi_id *)ext;
713 		TCHECK(*p);
714 		safememcpy(&id, ext, sizeof(id));
715 		printf(" idtype=%s", STR_OR_ID(id.type, ipsecidtypestr));
716 		if (id.proto_id) {
717 #ifndef WIN32
718 			setprotoent(1);
719 #endif /* WIN32 */
720 			pe = getprotobynumber(id.proto_id);
721 			if (pe)
722 				printf(" protoid=%s", pe->p_name);
723 #ifndef WIN32
724 			endprotoent();
725 #endif /* WIN32 */
726 		} else {
727 			/* it DOES NOT mean IPPROTO_IP! */
728 			printf(" protoid=%s", "0");
729 		}
730 		printf(" port=%d", ntohs(id.port));
731 		if (!len)
732 			break;
733 		if (data == NULL)
734 			goto trunc;
735 		TCHECK2(*data, len);
736 		switch (id.type) {
737 		case IPSECDOI_ID_IPV4_ADDR:
738 			if (len < 4)
739 				printf(" len=%d [bad: < 4]", len);
740 			else
741 				printf(" len=%d %s", len, ipaddr_string(data));
742 			len = 0;
743 			break;
744 		case IPSECDOI_ID_FQDN:
745 		case IPSECDOI_ID_USER_FQDN:
746 		    {
747 			int i;
748 			printf(" len=%d ", len);
749 			for (i = 0; i < len; i++)
750 				safeputchar(data[i]);
751 			len = 0;
752 			break;
753 		    }
754 		case IPSECDOI_ID_IPV4_ADDR_SUBNET:
755 		    {
756 			const u_char *mask;
757 			if (len < 8)
758 				printf(" len=%d [bad: < 8]", len);
759 			else {
760 				mask = data + sizeof(struct in_addr);
761 				printf(" len=%d %s/%u.%u.%u.%u", len,
762 					ipaddr_string(data),
763 					mask[0], mask[1], mask[2], mask[3]);
764 			}
765 			len = 0;
766 			break;
767 		    }
768 #ifdef INET6
769 		case IPSECDOI_ID_IPV6_ADDR:
770 			if (len < 16)
771 				printf(" len=%d [bad: < 16]", len);
772 			else
773 				printf(" len=%d %s", len, ip6addr_string(data));
774 			len = 0;
775 			break;
776 		case IPSECDOI_ID_IPV6_ADDR_SUBNET:
777 		    {
778 			const u_int32_t *mask;
779 			if (len < 20)
780 				printf(" len=%d [bad: < 20]", len);
781 			else {
782 				mask = (u_int32_t *)(data + sizeof(struct in6_addr));
783 				/*XXX*/
784 				printf(" len=%d %s/0x%08x%08x%08x%08x", len,
785 					ip6addr_string(data),
786 					mask[0], mask[1], mask[2], mask[3]);
787 			}
788 			len = 0;
789 			break;
790 		    }
791 #endif /*INET6*/
792 		case IPSECDOI_ID_IPV4_ADDR_RANGE:
793 			if (len < 8)
794 				printf(" len=%d [bad: < 8]", len);
795 			else {
796 				printf(" len=%d %s-%s", len,
797 					ipaddr_string(data),
798 					ipaddr_string(data + sizeof(struct in_addr)));
799 			}
800 			len = 0;
801 			break;
802 #ifdef INET6
803 		case IPSECDOI_ID_IPV6_ADDR_RANGE:
804 			if (len < 32)
805 				printf(" len=%d [bad: < 32]", len);
806 			else {
807 				printf(" len=%d %s-%s", len,
808 					ip6addr_string(data),
809 					ip6addr_string(data + sizeof(struct in6_addr)));
810 			}
811 			len = 0;
812 			break;
813 #endif /*INET6*/
814 		case IPSECDOI_ID_DER_ASN1_DN:
815 		case IPSECDOI_ID_DER_ASN1_GN:
816 		case IPSECDOI_ID_KEY_ID:
817 			break;
818 		}
819 		break;
820 	    }
821 	}
822 	if (data && len) {
823 		printf(" len=%d", len);
824 		if (2 < vflag) {
825 			printf(" ");
826 			if (!rawprint((caddr_t)data, len))
827 				goto trunc;
828 		}
829 	}
830 	return (u_char *)ext + item_len;
831 trunc:
832 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_ID));
833 	return NULL;
834 }
835 
836 static const u_char *
837 isakmp_cert_print(const struct isakmp_gen *ext, u_int item_len,
838 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi0 _U_,
839 	u_int32_t proto0 _U_, int depth _U_)
840 {
841 	const struct isakmp_pl_cert *p;
842 	struct isakmp_pl_cert cert;
843 	static const char *certstr[] = {
844 		"none",	"pkcs7", "pgp", "dns",
845 		"x509sign", "x509ke", "kerberos", "crl",
846 		"arl", "spki", "x509attr",
847 	};
848 
849 	printf("%s:", NPSTR(ISAKMP_NPTYPE_CERT));
850 
851 	p = (struct isakmp_pl_cert *)ext;
852 	TCHECK(*p);
853 	safememcpy(&cert, ext, sizeof(cert));
854 	printf(" len=%d", item_len - 4);
855 	printf(" type=%s", STR_OR_ID((cert.encode), certstr));
856 	if (2 < vflag && 4 < item_len) {
857 		printf(" ");
858 		if (!rawprint((caddr_t)(ext + 1), item_len - 4))
859 			goto trunc;
860 	}
861 	return (u_char *)ext + item_len;
862 trunc:
863 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_CERT));
864 	return NULL;
865 }
866 
867 static const u_char *
868 isakmp_cr_print(const struct isakmp_gen *ext, u_int item_len,
869 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi0 _U_,
870 	u_int32_t proto0 _U_, int depth _U_)
871 {
872 	const struct isakmp_pl_cert *p;
873 	struct isakmp_pl_cert cert;
874 	static const char *certstr[] = {
875 		"none",	"pkcs7", "pgp", "dns",
876 		"x509sign", "x509ke", "kerberos", "crl",
877 		"arl", "spki", "x509attr",
878 	};
879 
880 	printf("%s:", NPSTR(ISAKMP_NPTYPE_CR));
881 
882 	p = (struct isakmp_pl_cert *)ext;
883 	TCHECK(*p);
884 	safememcpy(&cert, ext, sizeof(cert));
885 	printf(" len=%d", item_len - 4);
886 	printf(" type=%s", STR_OR_ID((cert.encode), certstr));
887 	if (2 < vflag && 4 < item_len) {
888 		printf(" ");
889 		if (!rawprint((caddr_t)(ext + 1), item_len - 4))
890 			goto trunc;
891 	}
892 	return (u_char *)ext + item_len;
893 trunc:
894 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_CR));
895 	return NULL;
896 }
897 
898 static const u_char *
899 isakmp_hash_print(const struct isakmp_gen *ext, u_int item_len,
900 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi _U_,
901 	u_int32_t proto _U_, int depth _U_)
902 {
903 	struct isakmp_gen e;
904 
905 	printf("%s:", NPSTR(ISAKMP_NPTYPE_HASH));
906 
907 	TCHECK(*ext);
908 	safememcpy(&e, ext, sizeof(e));
909 	printf(" len=%d", ntohs(e.len) - 4);
910 	if (2 < vflag && 4 < ntohs(e.len)) {
911 		printf(" ");
912 		if (!rawprint((caddr_t)(ext + 1), ntohs(e.len) - 4))
913 			goto trunc;
914 	}
915 	return (u_char *)ext + ntohs(e.len);
916 trunc:
917 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_HASH));
918 	return NULL;
919 }
920 
921 static const u_char *
922 isakmp_sig_print(const struct isakmp_gen *ext, u_int item_len,
923 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi _U_,
924 	u_int32_t proto _U_, int depth _U_)
925 {
926 	struct isakmp_gen e;
927 
928 	printf("%s:", NPSTR(ISAKMP_NPTYPE_SIG));
929 
930 	TCHECK(*ext);
931 	safememcpy(&e, ext, sizeof(e));
932 	printf(" len=%d", ntohs(e.len) - 4);
933 	if (2 < vflag && 4 < ntohs(e.len)) {
934 		printf(" ");
935 		if (!rawprint((caddr_t)(ext + 1), ntohs(e.len) - 4))
936 			goto trunc;
937 	}
938 	return (u_char *)ext + ntohs(e.len);
939 trunc:
940 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_SIG));
941 	return NULL;
942 }
943 
944 static const u_char *
945 isakmp_nonce_print(const struct isakmp_gen *ext, u_int item_len,
946 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi _U_,
947 	u_int32_t proto _U_, int depth _U_)
948 {
949 	struct isakmp_gen e;
950 
951 	printf("%s:", NPSTR(ISAKMP_NPTYPE_NONCE));
952 
953 	TCHECK(*ext);
954 	safememcpy(&e, ext, sizeof(e));
955 	printf(" n len=%d", ntohs(e.len) - 4);
956 	if (2 < vflag && 4 < ntohs(e.len)) {
957 		printf(" ");
958 		if (!rawprint((caddr_t)(ext + 1), ntohs(e.len) - 4))
959 			goto trunc;
960 	}
961 	return (u_char *)ext + ntohs(e.len);
962 trunc:
963 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_NONCE));
964 	return NULL;
965 }
966 
967 static const u_char *
968 isakmp_n_print(const struct isakmp_gen *ext, u_int item_len,
969 	const u_char *ep, u_int32_t phase, u_int32_t doi0 _U_,
970 	u_int32_t proto0 _U_, int depth)
971 {
972 	struct isakmp_pl_n *p, n;
973 	const u_char *cp;
974 	u_char *ep2;
975 	u_int32_t doi;
976 	u_int32_t proto;
977 	static const char *notify_error_str[] = {
978 		NULL,				"INVALID-PAYLOAD-TYPE",
979 		"DOI-NOT-SUPPORTED",		"SITUATION-NOT-SUPPORTED",
980 		"INVALID-COOKIE",		"INVALID-MAJOR-VERSION",
981 		"INVALID-MINOR-VERSION",	"INVALID-EXCHANGE-TYPE",
982 		"INVALID-FLAGS",		"INVALID-MESSAGE-ID",
983 		"INVALID-PROTOCOL-ID",		"INVALID-SPI",
984 		"INVALID-TRANSFORM-ID",		"ATTRIBUTES-NOT-SUPPORTED",
985 		"NO-PROPOSAL-CHOSEN",		"BAD-PROPOSAL-SYNTAX",
986 		"PAYLOAD-MALFORMED",		"INVALID-KEY-INFORMATION",
987 		"INVALID-ID-INFORMATION",	"INVALID-CERT-ENCODING",
988 		"INVALID-CERTIFICATE",		"CERT-TYPE-UNSUPPORTED",
989 		"INVALID-CERT-AUTHORITY",	"INVALID-HASH-INFORMATION",
990 		"AUTHENTICATION-FAILED",	"INVALID-SIGNATURE",
991 		"ADDRESS-NOTIFICATION",		"NOTIFY-SA-LIFETIME",
992 		"CERTIFICATE-UNAVAILABLE",	"UNSUPPORTED-EXCHANGE-TYPE",
993 		"UNEQUAL-PAYLOAD-LENGTHS",
994 	};
995 	static const char *ipsec_notify_error_str[] = {
996 		"RESERVED",
997 	};
998 	static const char *notify_status_str[] = {
999 		"CONNECTED",
1000 	};
1001 	static const char *ipsec_notify_status_str[] = {
1002 		"RESPONDER-LIFETIME",		"REPLAY-STATUS",
1003 		"INITIAL-CONTACT",
1004 	};
1005 /* NOTE: these macro must be called with x in proper range */
1006 
1007 /* 0 - 8191 */
1008 #define NOTIFY_ERROR_STR(x) \
1009 	STR_OR_ID((x), notify_error_str)
1010 
1011 /* 8192 - 16383 */
1012 #define IPSEC_NOTIFY_ERROR_STR(x) \
1013 	STR_OR_ID((u_int)((x) - 8192), ipsec_notify_error_str)
1014 
1015 /* 16384 - 24575 */
1016 #define NOTIFY_STATUS_STR(x) \
1017 	STR_OR_ID((u_int)((x) - 16384), notify_status_str)
1018 
1019 /* 24576 - 32767 */
1020 #define IPSEC_NOTIFY_STATUS_STR(x) \
1021 	STR_OR_ID((u_int)((x) - 24576), ipsec_notify_status_str)
1022 
1023 	printf("%s:", NPSTR(ISAKMP_NPTYPE_N));
1024 
1025 	p = (struct isakmp_pl_n *)ext;
1026 	TCHECK(*p);
1027 	safememcpy(&n, ext, sizeof(n));
1028 	doi = ntohl(n.doi);
1029 	proto = n.prot_id;
1030 	if (doi != 1) {
1031 		printf(" doi=%d", doi);
1032 		printf(" proto=%d", proto);
1033 		if (ntohs(n.type) < 8192)
1034 			printf(" type=%s", NOTIFY_ERROR_STR(ntohs(n.type)));
1035 		else if (ntohs(n.type) < 16384)
1036 			printf(" type=%s", numstr(ntohs(n.type)));
1037 		else if (ntohs(n.type) < 24576)
1038 			printf(" type=%s", NOTIFY_STATUS_STR(ntohs(n.type)));
1039 		else
1040 			printf(" type=%s", numstr(ntohs(n.type)));
1041 		if (n.spi_size) {
1042 			printf(" spi=");
1043 			if (!rawprint((caddr_t)(p + 1), n.spi_size))
1044 				goto trunc;
1045 		}
1046 		return (u_char *)(p + 1) + n.spi_size;
1047 	}
1048 
1049 	printf(" doi=ipsec");
1050 	printf(" proto=%s", PROTOIDSTR(proto));
1051 	if (ntohs(n.type) < 8192)
1052 		printf(" type=%s", NOTIFY_ERROR_STR(ntohs(n.type)));
1053 	else if (ntohs(n.type) < 16384)
1054 		printf(" type=%s", IPSEC_NOTIFY_ERROR_STR(ntohs(n.type)));
1055 	else if (ntohs(n.type) < 24576)
1056 		printf(" type=%s", NOTIFY_STATUS_STR(ntohs(n.type)));
1057 	else if (ntohs(n.type) < 32768)
1058 		printf(" type=%s", IPSEC_NOTIFY_STATUS_STR(ntohs(n.type)));
1059 	else
1060 		printf(" type=%s", numstr(ntohs(n.type)));
1061 	if (n.spi_size) {
1062 		printf(" spi=");
1063 		if (!rawprint((caddr_t)(p + 1), n.spi_size))
1064 			goto trunc;
1065 	}
1066 
1067 	cp = (u_char *)(p + 1) + n.spi_size;
1068 	ep2 = (u_char *)p + item_len;
1069 
1070 	if (cp < ep) {
1071 		printf(" orig=(");
1072 		switch (ntohs(n.type)) {
1073 		case IPSECDOI_NTYPE_RESPONDER_LIFETIME:
1074 		    {
1075 			const struct attrmap *map = oakley_t_map;
1076 			size_t nmap = sizeof(oakley_t_map)/sizeof(oakley_t_map[0]);
1077 			while (cp < ep && cp < ep2) {
1078 				cp = isakmp_attrmap_print(cp,
1079 					(ep < ep2) ? ep : ep2, map, nmap);
1080 			}
1081 			break;
1082 		    }
1083 		case IPSECDOI_NTYPE_REPLAY_STATUS:
1084 			printf("replay detection %sabled",
1085 				(*(u_int32_t *)cp) ? "en" : "dis");
1086 			break;
1087 		case ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN:
1088 			if (isakmp_sub_print(ISAKMP_NPTYPE_SA,
1089 			    (struct isakmp_gen *)cp, ep, phase, doi, proto,
1090 			    depth) == NULL)
1091 				return NULL;
1092 			break;
1093 		default:
1094 			/* NULL is dummy */
1095 			isakmp_print(cp, item_len - sizeof(*p) - n.spi_size,
1096 				NULL);
1097 		}
1098 		printf(")");
1099 	}
1100 	return (u_char *)ext + item_len;
1101 trunc:
1102 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_N));
1103 	return NULL;
1104 }
1105 
1106 static const u_char *
1107 isakmp_d_print(const struct isakmp_gen *ext, u_int item_len,
1108 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi0 _U_,
1109 	u_int32_t proto0 _U_, int depth _U_)
1110 {
1111 	const struct isakmp_pl_d *p;
1112 	struct isakmp_pl_d d;
1113 	const u_int8_t *q;
1114 	u_int32_t doi;
1115 	u_int32_t proto;
1116 	int i;
1117 
1118 	printf("%s:", NPSTR(ISAKMP_NPTYPE_D));
1119 
1120 	p = (struct isakmp_pl_d *)ext;
1121 	TCHECK(*p);
1122 	safememcpy(&d, ext, sizeof(d));
1123 	doi = ntohl(d.doi);
1124 	proto = d.prot_id;
1125 	if (doi != 1) {
1126 		printf(" doi=%u", doi);
1127 		printf(" proto=%u", proto);
1128 	} else {
1129 		printf(" doi=ipsec");
1130 		printf(" proto=%s", PROTOIDSTR(proto));
1131 	}
1132 	printf(" spilen=%u", d.spi_size);
1133 	printf(" nspi=%u", ntohs(d.num_spi));
1134 	printf(" spi=");
1135 	q = (u_int8_t *)(p + 1);
1136 	for (i = 0; i < ntohs(d.num_spi); i++) {
1137 		if (i != 0)
1138 			printf(",");
1139 		if (!rawprint((caddr_t)q, d.spi_size))
1140 			goto trunc;
1141 		q += d.spi_size;
1142 	}
1143 	return q;
1144 trunc:
1145 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_D));
1146 	return NULL;
1147 }
1148 
1149 static const u_char *
1150 isakmp_vid_print(const struct isakmp_gen *ext, u_int item_len,
1151 	const u_char *ep, u_int32_t phase _U_, u_int32_t doi _U_,
1152 	u_int32_t proto _U_, int depth _U_)
1153 {
1154 	struct isakmp_gen e;
1155 
1156 	printf("%s:", NPSTR(ISAKMP_NPTYPE_VID));
1157 
1158 	TCHECK(*ext);
1159 	safememcpy(&e, ext, sizeof(e));
1160 	printf(" len=%d", ntohs(e.len) - 4);
1161 	if (2 < vflag && 4 < ntohs(e.len)) {
1162 		printf(" ");
1163 		if (!rawprint((caddr_t)(ext + 1), ntohs(e.len) - 4))
1164 			goto trunc;
1165 	}
1166 	return (u_char *)ext + ntohs(e.len);
1167 trunc:
1168 	printf(" [|%s]", NPSTR(ISAKMP_NPTYPE_VID));
1169 	return NULL;
1170 }
1171 
1172 static const u_char *
1173 isakmp_sub0_print(u_char np, const struct isakmp_gen *ext, const u_char *ep,
1174 	u_int32_t phase, u_int32_t doi, u_int32_t proto, int depth)
1175 {
1176 	const u_char *cp;
1177 	struct isakmp_gen e;
1178 	u_int item_len;
1179 
1180 	cp = (u_char *)ext;
1181 	TCHECK(*ext);
1182 	safememcpy(&e, ext, sizeof(e));
1183 
1184 	/*
1185 	 * Since we can't have a payload length of less than 4 bytes,
1186 	 * we need to bail out here if the generic header is nonsensical
1187 	 * or truncated, otherwise we could loop forever processing
1188 	 * zero-length items or otherwise misdissect the packet.
1189 	 */
1190 	item_len = ntohs(e.len);
1191 	if (item_len <= 4)
1192 		return NULL;
1193 
1194 	if (NPFUNC(np)) {
1195 		/*
1196 		 * XXX - what if item_len is too short, or too long,
1197 		 * for this payload type?
1198 		 */
1199 		cp = (*NPFUNC(np))(ext, item_len, ep, phase, doi, proto, depth);
1200 	} else {
1201 		printf("%s", NPSTR(np));
1202 		cp += item_len;
1203 	}
1204 
1205 	return cp;
1206 trunc:
1207 	printf(" [|isakmp]");
1208 	return NULL;
1209 }
1210 
1211 static const u_char *
1212 isakmp_sub_print(u_char np, const struct isakmp_gen *ext, const u_char *ep,
1213 	u_int32_t phase, u_int32_t doi, u_int32_t proto, int depth)
1214 {
1215 	const u_char *cp;
1216 	int i;
1217 	struct isakmp_gen e;
1218 
1219 	cp = (const u_char *)ext;
1220 
1221 	while (np) {
1222 		TCHECK(*ext);
1223 
1224 		safememcpy(&e, ext, sizeof(e));
1225 
1226 		TCHECK2(*ext, ntohs(e.len));
1227 
1228 		depth++;
1229 		printf("\n");
1230 		for (i = 0; i < depth; i++)
1231 			printf("    ");
1232 		printf("(");
1233 		cp = isakmp_sub0_print(np, ext, ep, phase, doi, proto, depth);
1234 		printf(")");
1235 		depth--;
1236 
1237 		if (cp == NULL) {
1238 			/* Zero-length subitem */
1239 			return NULL;
1240 		}
1241 
1242 		np = e.np;
1243 		ext = (struct isakmp_gen *)cp;
1244 	}
1245 	return cp;
1246 trunc:
1247 	printf(" [|%s]", NPSTR(np));
1248 	return NULL;
1249 }
1250 
1251 static char *
1252 numstr(int x)
1253 {
1254 	static char buf[20];
1255 	snprintf(buf, sizeof(buf), "#%d", x);
1256 	return buf;
1257 }
1258 
1259 /*
1260  * some compiler tries to optimize memcpy(), using the alignment constraint
1261  * on the argument pointer type.  by using this function, we try to avoid the
1262  * optimization.
1263  */
1264 static void
1265 safememcpy(void *p, const void *q, size_t l)
1266 {
1267 	memcpy(p, q, l);
1268 }
1269 
1270 void
1271 isakmp_print(const u_char *bp, u_int length, const u_char *bp2)
1272 {
1273 	const struct isakmp *p;
1274 	struct isakmp base;
1275 	const u_char *ep;
1276 	u_char np;
1277 	int i;
1278 	int phase;
1279 	int major, minor;
1280 
1281 	p = (const struct isakmp *)bp;
1282 	ep = snapend;
1283 
1284 	if ((struct isakmp *)ep < p + 1) {
1285 		printf("[|isakmp]");
1286 		return;
1287 	}
1288 
1289 	safememcpy(&base, p, sizeof(base));
1290 
1291 	printf("isakmp");
1292 	if (vflag) {
1293 		major = (base.vers & ISAKMP_VERS_MAJOR)
1294 				>> ISAKMP_VERS_MAJOR_SHIFT;
1295 		minor = (base.vers & ISAKMP_VERS_MINOR)
1296 				>> ISAKMP_VERS_MINOR_SHIFT;
1297 		printf(" %d.%d", major, minor);
1298 	}
1299 
1300 	if (vflag) {
1301 		printf(" msgid ");
1302 		rawprint((caddr_t)&base.msgid, sizeof(base.msgid));
1303 	}
1304 
1305 	if (1 < vflag) {
1306 		printf(" cookie ");
1307 		rawprint((caddr_t)&base.i_ck, sizeof(base.i_ck));
1308 		printf("->");
1309 		rawprint((caddr_t)&base.r_ck, sizeof(base.r_ck));
1310 	}
1311 	printf(":");
1312 
1313 	phase = (*(u_int32_t *)base.msgid == 0) ? 1 : 2;
1314 	if (phase == 1)
1315 		printf(" phase %d", phase);
1316 	else
1317 		printf(" phase %d/others", phase);
1318 
1319 	i = cookie_find(&base.i_ck);
1320 	if (i < 0) {
1321 		if (iszero((u_char *)&base.r_ck, sizeof(base.r_ck))) {
1322 			/* the first packet */
1323 			printf(" I");
1324 			if (bp2)
1325 				cookie_record(&base.i_ck, bp2);
1326 		} else
1327 			printf(" ?");
1328 	} else {
1329 		if (bp2 && cookie_isinitiator(i, bp2))
1330 			printf(" I");
1331 		else if (bp2 && cookie_isresponder(i, bp2))
1332 			printf(" R");
1333 		else
1334 			printf(" ?");
1335 	}
1336 
1337 	printf(" %s", ETYPESTR(base.etype));
1338 	if (base.flags) {
1339 		printf("[%s%s]", base.flags & ISAKMP_FLAG_E ? "E" : "",
1340 			base.flags & ISAKMP_FLAG_C ? "C" : "");
1341 	}
1342 
1343 	if (vflag) {
1344 		const struct isakmp_gen *ext;
1345 		int nparen;
1346 
1347 #define CHECKLEN(p, np) \
1348 		if (ep < (u_char *)(p)) {				\
1349 			printf(" [|%s]", NPSTR(np));			\
1350 			goto done;					\
1351 		}
1352 
1353 		printf(":");
1354 
1355 		/* regardless of phase... */
1356 		if (base.flags & ISAKMP_FLAG_E) {
1357 			/*
1358 			 * encrypted, nothing we can do right now.
1359 			 * we hope to decrypt the packet in the future...
1360 			 */
1361 			printf(" [encrypted %s]", NPSTR(base.np));
1362 			goto done;
1363 		}
1364 
1365 		nparen = 0;
1366 		CHECKLEN(p + 1, base.np)
1367 
1368 		np = base.np;
1369 		ext = (struct isakmp_gen *)(p + 1);
1370 		isakmp_sub_print(np, ext, ep, phase, 0, 0, 0);
1371 	}
1372 
1373 done:
1374 	if (vflag) {
1375 		if (ntohl(base.len) != length) {
1376 			printf(" (len mismatch: isakmp %u/ip %u)",
1377 				(u_int32_t)ntohl(base.len), length);
1378 		}
1379 	}
1380 }
1381