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