xref: /openbsd-src/usr.sbin/tcpdump/print-ike.c (revision e2a1b4748ac00cfe1e64a346f850b3c670166aef)
1 /*	$OpenBSD: print-ike.c,v 1.17 2004/01/15 22:59:42 ho Exp $	*/
2 
3 /*
4  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 2001 H�kan Olsson.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that: (1) source code distributions
10  * retain the above copyright notice and this paragraph in its entirety, (2)
11  * distributions including binary code include the above copyright notice and
12  * this paragraph in its entirety in the documentation or other materials
13  * provided with the distribution, and (3) all advertising materials mentioning
14  * features or use of this software display the following acknowledgement:
15  * ``This product includes software developed by the University of California,
16  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17  * the University nor the names of its contributors may be used to endorse
18  * or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  * Format and print ike (isakmp) packets.
25  *	By Tero Kivinen <kivinen@ssh.fi>, Tero Mononen <tmo@ssh.fi>,
26  *         Tatu Ylonen <ylo@ssh.fi> and Timo J. Rinne <tri@ssh.fi>
27  *         in co-operation with SSH Communications Security, Espoo, Finland
28  */
29 
30 #ifndef lint
31 static const char rcsid[] =
32     "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/print-ike.c,v 1.17 2004/01/15 22:59:42 ho Exp $ (XXX)";
33 #endif
34 
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <sys/socket.h>
38 
39 struct mbuf;
40 struct rtentry;
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 
45 #include <ctype.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 #include "interface.h"
50 #include "addrtoname.h"
51 #include "ike.h"
52 
53 struct isakmp_header {
54 	u_char  init_cookie[8];
55 	u_char  resp_cookie[8];
56 	u_char  nextpayload;
57 	u_char  version;
58 	u_char  exgtype;
59 	u_char  flags;
60 	u_char  msgid[4];
61 	u_int32_t length;
62 	u_char  payloads[0];
63 };
64 
65 struct notification_payload {
66 	u_char    next_payload;
67 	u_char    reserved;
68 	u_int16_t payload_length;
69 	u_int32_t doi;
70 	u_char    protocol_id;
71   	u_char    spi_size;
72   	u_int16_t type;
73 	u_char    data[0];
74 };
75 
76 static void ike_pl_print(u_char, u_char *, u_char);
77 
78 int ike_tab_level = 0;
79 u_char xform_proto;
80 
81 static const char *ike[] = IKE_PROTO_INITIALIZER;
82 
83 #define SMALL_TABS 4
84 #define SPACES "                                                   "
85 const char *
86 ike_tab_offset(void)
87 {
88 	const char *p, *endline;
89 	static const char line[] = SPACES;
90 
91 	endline = line + sizeof line - 1;
92 	p = endline - SMALL_TABS * (ike_tab_level);
93 
94 	return (p > line ? p : line);
95 }
96 
97 static char *
98 ike_get_cookie (u_char *ic, u_char *rc)
99 {
100 	static char cookie_jar[35];
101 	int i;
102 
103 	for (i = 0; i < 8; i++)
104 		snprintf(cookie_jar + i*2, sizeof(cookie_jar) - i*2,
105 		    "%02x", *(ic + i));
106 	strlcat(cookie_jar, "->", sizeof(cookie_jar));
107 	for (i = 0; i < 8; i++)
108 		snprintf(cookie_jar + 18 + i*2, sizeof(cookie_jar) - 18 - i*2,
109 		    "%02x", *(rc + i));
110 	return cookie_jar;
111 }
112 
113 /*
114  * Print isakmp requests
115  */
116 void
117 ike_print (const u_char *cp, u_int length)
118 {
119 	struct isakmp_header *ih;
120 	const u_char *ep;
121 	u_char *payload;
122 	u_char  nextpayload;
123 	int encrypted;
124 	static const char *exgtypes[] = IKE_EXCHANGE_TYPES_INITIALIZER;
125 
126 	encrypted = 0;
127 
128 #ifdef TCHECK
129 #undef TCHECK
130 #endif
131 #define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
132 
133 	ih = (struct isakmp_header *)cp;
134 
135 	if (length < sizeof (struct isakmp_header))
136 		goto trunc;
137 
138 	/* 'ep' points to the end of avaible data. */
139 	ep = snapend;
140 
141 	printf(" isakmp");
142 
143 	printf(" v%d.%d", ih->version >> 4, ih->version & 0xf);
144 
145 	printf(" exchange ");
146 	if (ih->exgtype < (sizeof exgtypes/sizeof exgtypes[0]))
147 		printf("%s", exgtypes[ih->exgtype]);
148 	else
149 		printf("%d (unknown)", ih->exgtype);
150 
151 	if (ih->flags & FLAGS_ENCRYPTION) {
152 		printf(" encrypted");
153 		encrypted = 1;
154 	}
155 
156 	if (ih->flags & FLAGS_COMMIT) {
157 		printf(" commit");
158 	}
159 
160 	printf("\n\tcookie: %s", ike_get_cookie (ih->init_cookie,
161 						 ih->resp_cookie));
162 
163 	TCHECK(ih->msgid, sizeof(ih->msgid));
164 	printf(" msgid: %02x%02x%02x%02x", ih->msgid[0], ih->msgid[1],
165 	    ih->msgid[2], ih->msgid[3]);
166 
167 	TCHECK(ih->length, sizeof(ih->length));
168 	printf(" len: %d", ntohl(ih->length));
169 
170 	if (ih->version > 16) {
171 		printf(" new version");
172 		return;
173 	}
174 
175 	payload = ih->payloads;
176 	nextpayload = ih->nextpayload;
177 
178 	/* if encrypted, then open special file for encryption keys */
179 	if (encrypted) {
180 		/* decrypt XXX */
181 		return;
182 	}
183 
184 	/* if verbose, print payload data */
185 	if (vflag)
186 		ike_pl_print(nextpayload, payload, ISAKMP_DOI);
187 
188 	return;
189 
190 trunc:
191 	fputs(" [|isakmp]", stdout);
192 }
193 
194 void
195 ike_pl_sa_print (u_char *buf, int len)
196 {
197 	u_int32_t situation = ntohl(*(u_int32_t *)(buf + 4));
198 	u_char ike_doi = ntohl((*(u_int32_t *)buf));
199 	printf(" DOI: %d", ike_doi);
200 	if (ike_doi == IPSEC_DOI) {
201 		printf("(IPSEC) situation: ");
202 		if (situation & IKE_SITUATION_IDENTITY_ONLY)
203 			printf("IDENTITY_ONLY ");
204 		if (situation & IKE_SITUATION_SECRECY)
205 			printf("SECRECY ");
206 		if (situation & IKE_SITUATION_INTEGRITY)
207 			printf("INTEGRITY ");
208 		if ((situation & IKE_SITUATION_MASK) == 0)
209 			printf("0x%x (unknown)", situation);
210 		ike_pl_print (PAYLOAD_PROPOSAL, buf + 8, IPSEC_DOI);
211 	} else
212 		printf(" situation: (unknown)");
213 }
214 
215 int
216 ike_attribute_print (u_char *buf, u_char doi, int maxlen)
217 {
218 	static char *attrs[] = IKE_ATTR_INITIALIZER;
219 	static char *attr_enc[] = IKE_ATTR_ENCRYPT_INITIALIZER;
220 	static char *attr_hash[] = IKE_ATTR_HASH_INITIALIZER;
221 	static char *attr_auth[] = IKE_ATTR_AUTH_INITIALIZER;
222 	static char *attr_gdesc[] = IKE_ATTR_GROUP_DESC_INITIALIZER;
223 	static char *attr_gtype[] = IKE_ATTR_GROUP_INITIALIZER;
224 	static char *attr_ltype[] = IKE_ATTR_SA_DURATION_INITIALIZER;
225 	static char *ipsec_attrs[] = IPSEC_ATTR_INITIALIZER;
226 	static char *ipsec_attr_encap[] = IPSEC_ATTR_ENCAP_INITIALIZER;
227 	static char *ipsec_attr_auth[] = IPSEC_ATTR_AUTH_INITIALIZER;
228 	static char *ipsec_attr_ltype[] = IPSEC_ATTR_DURATION_INITIALIZER;
229 
230 	u_char    af   = buf[0] >> 7;
231 	u_int16_t type = (buf[0] & 0x7f) << 8 | buf[1];
232 	u_int16_t len  = buf[2] << 8 | buf[3], val;
233 
234 	if (doi == ISAKMP_DOI)
235 		printf("\n\t%sattribute %s = ", ike_tab_offset(),
236 		    (type < sizeof attrs / sizeof attrs[0] ?
237 		    attrs[type] : "<unknown>"));
238 	else
239 		printf("\n\t%sattribute %s = ", ike_tab_offset(),
240 		    (type < (sizeof ipsec_attrs / sizeof ipsec_attrs[0]) ?
241 		    ipsec_attrs[type] : "<unknown>"));
242 
243 	if ((af == 1 && maxlen < 4) || (af == 0 && maxlen < (len + 4))) {
244 		printf("\n\t%s[|attr]", ike_tab_offset());
245 		return maxlen;
246 	}
247 
248 	if (af == 0) {
249 		/* AF=0; print the variable length attribute value */
250 		for (val = 0; val < len; val++)
251 			printf("%02x", (char)*(buf + 4 + val));
252 		return len + 4;
253 	}
254 
255 	val = len;	/* For AF=1, this field is the "VALUE" */
256 	len = 4; 	/* and with AF=1, length is always 4 */
257 
258 #define CASE_PRINT(TYPE, var) \
259 	case TYPE : \
260 		if (val < sizeof var / sizeof var [0]) \
261 			printf("%s", var [val]); \
262 		else \
263 			printf("%d (unknown)", val); \
264 		break;
265 
266 	if (doi == ISAKMP_DOI)
267 		switch(type) {
268 			CASE_PRINT(IKE_ATTR_ENCRYPTION_ALGORITHM, attr_enc);
269 			CASE_PRINT(IKE_ATTR_HASH_ALGORITHM, attr_hash);
270 			CASE_PRINT(IKE_ATTR_AUTHENTICATION_METHOD, attr_auth);
271 			CASE_PRINT(IKE_ATTR_GROUP_DESC, attr_gdesc);
272 			CASE_PRINT(IKE_ATTR_GROUP_TYPE, attr_gtype);
273 			CASE_PRINT(IKE_ATTR_LIFE_TYPE, attr_ltype);
274 		default:
275 			printf("%d", val);
276 		}
277 	else
278 		switch(type) {
279 			CASE_PRINT(IPSEC_ATTR_SA_LIFE_TYPE, ipsec_attr_ltype);
280 			CASE_PRINT(IPSEC_ATTR_ENCAPSULATION_MODE,
281 			    ipsec_attr_encap);
282 			CASE_PRINT(IPSEC_ATTR_AUTHENTICATION_ALGORITHM,
283 			    ipsec_attr_auth);
284 		default:
285 			printf("%d", val);
286 		}
287 
288 #undef CASE_PRINT
289 	return len;
290 }
291 
292 void
293 ike_pl_transform_print (u_char *buf, int len, u_char doi)
294 {
295 	const char *ah[] = IPSEC_AH_INITIALIZER;
296 	const char *esp[] = IPSEC_ESP_INITIALIZER;
297 	const char *ipcomp[] = IPCOMP_INITIALIZER;
298 	u_char *attr = buf + 4;
299 
300 	printf("\n\t%stransform: %u ID: ", ike_tab_offset(), buf[0]);
301 
302 	switch (doi) {
303 	case ISAKMP_DOI:
304 		if (buf[1] < (sizeof ike / sizeof ike[0]))
305 			printf("%s", ike[buf[1]]);
306 		else
307 			printf("%d(unknown)", buf[1]);
308 		break;
309 
310 	default: /* IPSEC_DOI */
311 		switch (xform_proto) {	/* from ike_proposal_print */
312 		case PROTO_IPSEC_AH:
313 			if (buf[1] < (sizeof ah / sizeof ah[0]))
314 				printf("%s", ah[buf[1]]);
315 			else
316 				printf("%d(unknown)", buf[1]);
317 			break;
318 		case PROTO_IPSEC_ESP:
319 			if (buf[1] < (sizeof esp / sizeof esp[0]))
320 				printf("%s", esp[buf[1]]);
321 			else
322 				printf("%d(unknown)", buf[1]);
323 			break;
324 		case PROTO_IPCOMP:
325 			if (buf[1] < (sizeof ipcomp / sizeof ipcomp[0]))
326 				printf("%s", ipcomp[buf[1]]);
327 			else
328 				printf("%d(unknown)", buf[1]);
329 			break;
330 		default:
331 			printf("%d(unknown)", buf[1]);
332 		}
333 		break;
334 	}
335 
336 	ike_tab_level++;
337 	while ((int)(attr - buf) < len - 4)  /* Skip last 'NONE' attr */
338 		attr += ike_attribute_print(attr, doi, len - (attr-buf));
339 	ike_tab_level--;
340 }
341 
342 void
343 ike_pl_proposal_print (u_char *buf, int len, u_char doi)
344 {
345 	u_int8_t i, p_id = buf[1], spisz = buf[2];
346 
347 	printf(" proposal: %d proto: %s spisz: %d xforms: %d",
348 	    buf[0], (p_id < (sizeof ike / sizeof ike[0]) ? ike[p_id] :
349 	    "(unknown)"), spisz, buf[3]);
350 
351 	/* We need to store this for upcoming ike_attribute_print call. */
352 	xform_proto = p_id;
353 
354 	if (spisz) {
355 		if (p_id == PROTO_IPCOMP)
356 			printf(" CPI: 0x");
357 		else
358 			printf(" SPI: 0x");
359 		for (i = 0; i < spisz && (i + 4) < len; i++)
360 			printf("%02x", buf[i + 4]);
361 		doi = IPSEC_DOI;
362 	} else
363 		doi = ISAKMP_DOI;
364 
365 	if ((char)buf[3] > 0)
366 		ike_pl_print(PAYLOAD_TRANSFORM, buf + 4 + buf[2], doi);
367 }
368 
369 void
370 ike_pl_ke_print (u_char *buf, int len, u_char doi)
371 {
372 	if (doi != IPSEC_DOI)
373 		return;
374 
375 	/* XXX ... */
376 }
377 
378 void
379 ipsec_id_print (u_char *buf, int len, u_char doi)
380 {
381 	static const char *idtypes[] = IPSEC_ID_TYPE_INITIALIZER;
382 	char ntop_buf[INET6_ADDRSTRLEN];
383 	struct in_addr in;
384 	u_char *p;
385 
386 	if (doi != ISAKMP_DOI)
387 		return;
388 
389 	/* Don't print proto+port unless actually used */
390 	if (buf[1] | buf[2] | buf[3])
391 		printf(" proto: %d port: %d", buf[1], (buf[2] << 8) + buf[3]);
392 
393 	printf(" type: %s = ", buf[0] < (sizeof idtypes/sizeof idtypes[0]) ?
394 	    idtypes[buf[0]] : "<unknown>");
395 
396 	switch (buf[0]) {
397 	case IPSEC_ID_IPV4_ADDR:
398 		memcpy (&in.s_addr, buf + 4, sizeof in);
399 		printf("%s", inet_ntoa (in));
400 		break;
401 	case IPSEC_ID_IPV4_ADDR_SUBNET:
402 	case IPSEC_ID_IPV4_ADDR_RANGE:
403 		memcpy (&in.s_addr, buf + 4, sizeof in);
404 		printf("%s%s", inet_ntoa (in),
405 		    buf[0] == IPSEC_ID_IPV4_ADDR_SUBNET ? "/" : "-");
406 		memcpy (&in.s_addr, buf + 8, sizeof in);
407 		printf("%s", inet_ntoa (in));
408 		break;
409 
410 	case IPSEC_ID_IPV6_ADDR:
411 		printf("%s", inet_ntop (AF_INET6, buf + 4, ntop_buf,
412 		    sizeof ntop_buf));
413 		break;
414 	case IPSEC_ID_IPV6_ADDR_SUBNET:
415 	case IPSEC_ID_IPV6_ADDR_RANGE:
416 		printf("%s%s", inet_ntop (AF_INET6, buf + 4, ntop_buf,
417 		    sizeof ntop_buf),
418 		    buf[0] == IPSEC_ID_IPV6_ADDR_SUBNET ? "/" : "-");
419 		printf("%s", inet_ntop (AF_INET6, buf + 4 + sizeof ntop_buf,
420 		    ntop_buf, sizeof ntop_buf));
421 
422 	case IPSEC_ID_FQDN:
423 	case IPSEC_ID_USER_FQDN:
424 		printf("\"");
425 		for(p = buf + 4; (int)(p - buf) < len - 4; p++)
426 			printf("%c",(isprint(*p) ? *p : '.'));
427 		printf("\"");
428 		break;
429 
430 	case IPSEC_ID_DER_ASN1_DN:
431 	case IPSEC_ID_DER_ASN1_GN:
432 	case IPSEC_ID_KEY_ID:
433 	default:
434 		printf("\"(not shown)\"");
435 		break;
436 	}
437 }
438 
439 void
440 ike_pl_notification_print (u_char *buf, int len)
441 {
442   	static const char *nftypes[] = IKE_NOTIFY_TYPES_INITIALIZER;
443   	struct notification_payload *np = (struct notification_payload *)buf;
444 	u_int32_t *replay;
445 	u_char *attr;
446 
447 	if (len < sizeof (struct notification_payload)) {
448 		printf(" (|len)");
449 		return;
450 	}
451 
452 	np->doi  = ntohl (np->doi);
453 	np->type = ntohs (np->type);
454 
455 	if (np->doi != ISAKMP_DOI && np->doi != IPSEC_DOI) {
456 		printf(" (unknown DOI)");
457 		return;
458 	}
459 
460 	printf("\n\t%snotification: ", ike_tab_offset());
461 
462 	if (np->type > 0 && np->type < (sizeof nftypes / sizeof nftypes[0])) {
463 		printf("%s", nftypes[np->type]);
464 		return;
465 	}
466 	switch (np->type) {
467 
468 	case NOTIFY_IPSEC_RESPONDER_LIFETIME:
469 		printf("RESPONDER LIFETIME");
470 		if (np->spi_size == 16)
471 			printf("(%s)", ike_get_cookie (&np->data[0],
472 			    &np->data[8]));
473 		else
474 			printf("SPI: 0x%08x", np->data[0]<<24 |
475 			    np->data[1]<<16 | np->data[2]<<8 | np->data[3]);
476 		attr = &np->data[np->spi_size];
477 		ike_tab_level++;
478 		while ((int)(attr - buf) < len - 4)  /* Skip last 'NONE' attr */
479 			attr += ike_attribute_print(attr, IPSEC_DOI,
480 			    len - (attr-buf));
481 		ike_tab_level--;
482 		break;
483 
484 	case NOTIFY_IPSEC_REPLAY_STATUS:
485 		replay = (u_int32_t *)&np->data[np->spi_size];
486 		printf("REPLAY STATUS [%sabled] ", *replay ? "en" : "dis");
487 		if (np->spi_size == 16)
488 			printf("(%s)", ike_get_cookie (&np->data[0],
489 			    &np->data[8]));
490 		else
491 			printf("SPI: 0x%08x", np->data[0]<<24 |
492 			    np->data[1]<<16 | np->data[2]<<8 | np->data[3]);
493 		break;
494 
495 	case NOTIFY_IPSEC_INITIAL_CONTACT:
496 		printf("INITIAL CONTACT (%s)", ike_get_cookie (&np->data[0],
497 		    &np->data[8]));
498 		break;
499 
500 	default:
501 	  	printf("%d (unknown)", np->type);
502 		break;
503 	}
504 }
505 
506 void
507 ike_pl_vendor_print (u_char *buf, int len, u_char doi)
508 {
509 	u_char *p = buf;
510 
511 	if (doi != IPSEC_DOI)
512 		return;
513 
514 	printf(" \"");
515 	for (p = buf; (int)(p - buf) < len; p++)
516 		printf("%c",(isprint(*p) ? *p : '.'));
517 	printf("\"");
518 }
519 
520 /* IKE mode-config. */
521 int
522 ike_cfg_attribute_print (u_char *buf, int attr_type, int maxlen)
523 {
524 	static char *attrs[] = IKE_CFG_ATTRIBUTE_INITIALIZER;
525 	char ntop_buf[INET6_ADDRSTRLEN];
526 	struct in_addr in;
527 
528 	u_char    af   = buf[0] >> 7;
529 	u_int16_t type = (buf[0] & 0x7f) << 8 | buf[1];
530 	u_int16_t len  = af ? 2 : buf[2] << 8 | buf[3], p;
531 	u_char   *val  = af ? buf + 2 : buf + 4;
532 
533 	printf("\n\t\%sattribute %s = ", ike_tab_offset(),
534 	    type < (sizeof attrs / sizeof attrs[0]) ? attrs[type] :
535 	    "<unknown>");
536 
537 	if ((af == 1 && maxlen < 4) ||
538 	    (af == 0 && maxlen < (len + 4))) {
539 		printf("\n\t%s[|attr]", ike_tab_offset());
540 		return maxlen;
541 	}
542 
543 	/* XXX The 2nd term is for bug compatibility with PGPnet.  */
544 	if (len == 0 || (af && !val[0] && !val[1])) {
545 		printf("<none>");
546 		return 4;
547 	}
548 
549 	/* XXX Generally lengths are not checked well below.  */
550 	switch (type) {
551 	case IKE_CFG_ATTR_INTERNAL_IP4_ADDRESS:
552 	case IKE_CFG_ATTR_INTERNAL_IP4_NETMASK:
553 	case IKE_CFG_ATTR_INTERNAL_IP4_DNS:
554 	case IKE_CFG_ATTR_INTERNAL_IP4_NBNS:
555 	case IKE_CFG_ATTR_INTERNAL_IP4_DHCP:
556 		memcpy (&in.s_addr, val, sizeof in);
557 		printf("%s", inet_ntoa (in));
558 		break;
559 
560 	case IKE_CFG_ATTR_INTERNAL_IP6_ADDRESS:
561 	case IKE_CFG_ATTR_INTERNAL_IP6_NETMASK:
562 	case IKE_CFG_ATTR_INTERNAL_IP6_DNS:
563 	case IKE_CFG_ATTR_INTERNAL_IP6_NBNS:
564 	case IKE_CFG_ATTR_INTERNAL_IP6_DHCP:
565 		printf("%s", inet_ntop (AF_INET6, val, ntop_buf,
566 		    sizeof ntop_buf));
567 		break;
568 
569 	case IKE_CFG_ATTR_INTERNAL_IP4_SUBNET:
570 		memcpy(&in.s_addr, val, sizeof in);
571 		printf("%s/", inet_ntoa (in));
572 		memcpy(&in.s_addr, val + sizeof in, sizeof in);
573 		printf("%s", inet_ntoa (in));
574 		break;
575 
576 	case IKE_CFG_ATTR_INTERNAL_IP6_SUBNET:
577 		printf("%s/%u", inet_ntop (AF_INET6, val, ntop_buf,
578 		    sizeof ntop_buf), val[16]);
579 		break;
580 
581 	case IKE_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
582 		printf("%u seconds",
583 		    val[0] << 24 | val[1] << 16 | val[2] << 8 | val[3]);
584 		break;
585 
586 	case IKE_CFG_ATTR_APPLICATION_VERSION:
587 		for (p = 0; p < len; p++)
588 			printf("%c", isprint(val[p]) ? val[p] : '.');
589 		break;
590 
591 	case IKE_CFG_ATTR_SUPPORTED_ATTRIBUTES:
592 		printf("<%d attributes>", len / 2);
593 		ike_tab_level++;
594 		for (p = 0; p < len; p += 2) {
595 			type = (val[p] << 8 | val[p + 1]) & 0x7fff;
596 			printf("\n\t%s%s", ike_tab_offset(),
597 			    type < (sizeof attrs/sizeof attrs[0]) ?
598 			    attrs[type] : "<unknown>");
599 		}
600 		ike_tab_level--;
601 		break;
602 
603 	default:
604 		break;
605 	}
606 	return af ? 4 : len + 4;
607 }
608 
609 void
610 ike_pl_attribute_print (u_char *buf, int len)
611 {
612 	static const char *pl_attr[] = IKE_CFG_ATTRIBUTE_TYPE_INITIALIZER;
613 	u_char type, *attr;
614 	u_int16_t id;
615 
616 	type = buf[0];
617 	id = buf[2]<<8 | buf[3];
618 	attr = buf + 4;
619 
620 	printf(" type: %s Id: %d",
621 	    type < (sizeof pl_attr/sizeof pl_attr[0]) ? pl_attr[type] :
622 	    "<unknown>", id);
623 
624 	while ((int)(attr - buf) < len - 4)
625 		attr += ike_cfg_attribute_print(attr, type, len - (attr-buf));
626 }
627 
628 void
629 ike_pl_print (u_char type, u_char *buf, u_char doi)
630 {
631 	static const char *pltypes[] = IKE_PAYLOAD_TYPES_INITIALIZER;
632 	int next_type = buf[0];
633 	int this_len = buf[2]<<8 | buf[3];
634 
635 	printf("\n\t%spayload: %s len: %d", ike_tab_offset(),
636 	    (type < (sizeof pltypes/sizeof pltypes[0]) ?
637 	    pltypes[type] : "<unknown>"), this_len);
638 
639 	if ((u_char *)&(buf[0]) > snapend - this_len)
640 		goto pltrunc;
641 
642 	ike_tab_level++;
643 	switch (type) {
644 	case PAYLOAD_NONE:
645 		return;
646 
647 	case PAYLOAD_SA:
648 		ike_pl_sa_print(buf+4, this_len);
649 		break;
650 
651 	case PAYLOAD_PROPOSAL:
652 		ike_pl_proposal_print(buf+4, this_len, doi);
653 		break;
654 
655 	case PAYLOAD_TRANSFORM:
656 		ike_pl_transform_print(buf+4, this_len, doi);
657 		break;
658 
659 	case PAYLOAD_KE:
660 		ike_pl_ke_print(buf+4, this_len, doi);
661 		break;
662 
663 	case PAYLOAD_ID:
664 		/* Should only happen with IPsec DOI */
665 		ipsec_id_print(buf+4, this_len, doi);
666 		break;
667 
668 	case PAYLOAD_CERT:
669 	case PAYLOAD_CERTREQUEST:
670 	case PAYLOAD_HASH:
671 	case PAYLOAD_SIG:
672 	case PAYLOAD_NONCE:
673 	case PAYLOAD_DELETE:
674 		break;
675 
676 	case PAYLOAD_NOTIFICATION:
677 	  	ike_pl_notification_print(buf, this_len);
678 		break;
679 
680 	case PAYLOAD_VENDOR:
681 		ike_pl_vendor_print(buf+4, this_len, doi);
682 		break;
683 
684 	case PAYLOAD_ATTRIBUTE:
685 		ike_pl_attribute_print(buf+4, this_len);
686 		break;
687 
688 	case PAYLOAD_NAT_D:
689 	case PAYLOAD_NAT_OA:
690 		break;
691 
692 	default:
693 		break;
694 	}
695 	ike_tab_level--;
696 
697 	if (next_type)  /* Recurse over next payload */
698 		ike_pl_print(next_type, buf + this_len, doi);
699 
700 	return;
701 
702 pltrunc:
703 	if (doi == ISAKMP_DOI)
704 		fputs(" [|isakmp]", stdout);
705 	else
706 		fputs(" [|ipsec]", stdout);
707 }
708