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