xref: /openbsd-src/usr.sbin/tcpdump/print-ike.c (revision fcde59b201a29a2b4570b00b71e7aa25d61cb5c1)
1 /*	$OpenBSD: print-ike.c,v 1.39 2020/01/24 22:46:36 procter 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 #include <sys/time.h>
31 #include <sys/socket.h>
32 
33 struct mbuf;
34 struct rtentry;
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include "interface.h"
44 #include "addrtoname.h"
45 #include "ike.h"
46 
47 struct isakmp_header {
48 	u_int8_t	init_cookie[8];
49 	u_int8_t	resp_cookie[8];
50 	u_int8_t	next_payload;
51 	u_int8_t	version;
52 	u_int8_t	exgtype;
53 	u_int8_t	flags;
54 	u_int8_t	msgid[4];
55 	u_int32_t	length;
56 	u_int8_t	payloads[0];
57 };
58 
59 struct sa_payload {
60 	u_int8_t	next_payload;
61 	u_int8_t	reserved;
62 	u_int16_t	payload_length;
63 	u_int32_t	doi;
64 	u_int8_t	situation[0];
65 };
66 
67 struct proposal_payload {
68 	u_int8_t	next_payload;
69 	u_int8_t	reserved;
70 	u_int16_t	payload_length;
71 	u_int8_t	nprop;
72 	u_int8_t	proto;
73 	u_int8_t	spi_size;
74 	u_int8_t	nspis;
75 	u_int8_t	spi[0];
76 };
77 
78 struct transform_payload {
79 	u_int8_t	next_payload;
80 	u_int8_t	reserved;
81 	u_int16_t	payload_length;
82 	u_int8_t	ntrans;
83 	u_int8_t	transform;
84 	u_int16_t	reserved2;
85 	u_int8_t	attribute[0];
86 };
87 
88 struct ke_payload {
89 	u_int8_t	next_payload;
90 	u_int8_t	reserved;
91 	u_int16_t	payload_length;
92 	u_int8_t	data[0];
93 };
94 
95 struct id_payload {
96 	u_int8_t	next_payload;
97 	u_int8_t	reserved;
98 	u_int16_t	payload_length;
99 	u_int8_t	type;
100 	u_int8_t	id_data[3];
101 	u_int8_t	data[0];
102 };
103 
104 struct notification_payload {
105 	u_int8_t	next_payload;
106 	u_int8_t	reserved;
107 	u_int16_t	payload_length;
108 	u_int32_t	doi;
109 	u_int8_t	protocol_id;
110   	u_int8_t	spi_size;
111   	u_int16_t	type;
112 	u_int8_t	data[0];
113 };
114 
115 struct delete_payload {
116 	u_int8_t	next_payload;
117 	u_int8_t	reserved;
118 	u_int16_t	payload_length;
119 	u_int32_t	doi;
120 	u_int8_t	proto;
121 	u_int8_t	spi_size;
122 	u_int16_t	nspis;
123 	u_int8_t	spi[0];
124 };
125 
126 struct vendor_payload {
127 	u_int8_t	next_payload;
128 	u_int8_t	reserved;
129 	u_int16_t	payload_length;
130 	u_int8_t	vid[0];
131 };
132 
133 struct attribute_payload {
134 	u_int8_t	next_payload;
135 	u_int8_t	reserved;
136 	u_int16_t	payload_length;
137 	u_int8_t	type;
138 	u_int8_t	reserved2;
139 	u_int16_t	id;
140 };
141 
142 static void ike_pl_print(u_int8_t, u_int8_t *, u_int8_t);
143 
144 int ike_tab_level = 0;
145 u_int8_t xform_proto;
146 
147 static const char *ike[] = IKE_PROTO_INITIALIZER;
148 
149 #define SMALL_TABS 4
150 #define SPACES "                                                   "
151 const char *
152 ike_tab_offset(void)
153 {
154 	const char *p, *endline;
155 	static const char line[] = SPACES;
156 
157 	endline = line + sizeof line - 1;
158 	p = endline - SMALL_TABS * (ike_tab_level);
159 
160 	return (p > line ? p : line);
161 }
162 
163 static char *
164 ike_get_cookie (u_int8_t *ic, u_int8_t *rc)
165 {
166 	static char cookie_jar[35];
167 	int i;
168 
169 	for (i = 0; i < 8; i++)
170 		snprintf(cookie_jar + i*2, sizeof(cookie_jar) - i*2,
171 		    "%02x", *(ic + i));
172 	strlcat(cookie_jar, "->", sizeof(cookie_jar));
173 	for (i = 0; i < 8; i++)
174 		snprintf(cookie_jar + 18 + i*2, sizeof(cookie_jar) - 18 - i*2,
175 		    "%02x", *(rc + i));
176 	return cookie_jar;
177 }
178 
179 /*
180  * Print isakmp requests
181  */
182 void
183 ike_print (const u_int8_t *cp, u_int length)
184 {
185 	struct isakmp_header *ih;
186 	const u_int8_t *ep;
187 	u_int8_t *payload, next_payload;
188 	int encrypted;
189 	static const char *exgtypes[] = IKE_EXCHANGE_TYPES_INITIALIZER;
190 
191 	encrypted = 0;
192 
193 #ifdef TCHECK
194 #undef TCHECK
195 #endif
196 #define TCHECK(var, l) if ((u_int8_t *)&(var) > ep - l) goto trunc
197 
198 	ih = (struct isakmp_header *)cp;
199 
200 	if (length < sizeof (struct isakmp_header))
201 		goto trunc;
202 
203 	/* 'ep' points to the end of avaible data. */
204 	ep = snapend;
205 
206 	printf("isakmp v%u.%u", ih->version >> 4, ih->version & 0xf);
207 
208 	printf(" exchange ");
209 	if (ih->exgtype < (sizeof exgtypes/sizeof exgtypes[0]))
210 		printf("%s", exgtypes[ih->exgtype]);
211 	else
212 		printf("%d (unknown)", ih->exgtype);
213 
214 	if (ih->flags & FLAGS_ENCRYPTION) {
215 		printf(" encrypted");
216 		encrypted = 1;
217 	}
218 
219 	if (ih->flags & FLAGS_COMMIT) {
220 		printf(" commit");
221 	}
222 
223 	printf("\n\tcookie: %s", ike_get_cookie (ih->init_cookie,
224 						 ih->resp_cookie));
225 
226 	TCHECK(ih->msgid, sizeof(ih->msgid));
227 	printf(" msgid: %02x%02x%02x%02x", ih->msgid[0], ih->msgid[1],
228 	    ih->msgid[2], ih->msgid[3]);
229 
230 	TCHECK(ih->length, sizeof(ih->length));
231 	printf(" len: %d", ntohl(ih->length));
232 
233 	if (ih->version > IKE_VERSION_2) {
234 		printf(" new version");
235 		return;
236 	}
237 
238 	payload = ih->payloads;
239 	next_payload = ih->next_payload;
240 
241 	/* if encrypted, then open special file for encryption keys */
242 	if (encrypted) {
243 		/* decrypt XXX */
244 		return;
245 	}
246 
247 	/* if verbose, print payload data */
248 	if (vflag)
249 		ike_pl_print(next_payload, payload, ISAKMP_DOI);
250 
251 	return;
252 
253 trunc:
254 	printf(" [|isakmp]");
255 }
256 
257 void
258 ike_pl_sa_print (u_int8_t *buf, int len)
259 {
260 	struct sa_payload *sp = (struct sa_payload *)buf;
261 	u_int32_t sit_ipsec, doi;
262 
263 	if (len < sizeof(struct sa_payload)) {
264 		printf(" [|payload]");
265 		return;
266 	}
267 
268 	doi = ntohl(sp->doi);
269 	printf(" DOI: %d", doi);
270 
271 	if (doi == IPSEC_DOI) {
272 		if ((sp->situation + sizeof(u_int32_t)) > (buf + len)) {
273 			printf(" [|payload]");
274 			return;
275 		}
276 		printf("(IPSEC) situation: ");
277 		sit_ipsec = ntohl(*(u_int32_t *)sp->situation);
278 		if (sit_ipsec & IKE_SITUATION_IDENTITY_ONLY)
279 			printf("IDENTITY_ONLY ");
280 		if (sit_ipsec & IKE_SITUATION_SECRECY)
281 			printf("SECRECY ");
282 		if (sit_ipsec & IKE_SITUATION_INTEGRITY)
283 			printf("INTEGRITY ");
284 		if ((sit_ipsec & IKE_SITUATION_MASK) == 0)
285 			printf("0x%x (unknown)", sit_ipsec);
286 		ike_pl_print (PAYLOAD_PROPOSAL, buf +
287 		    sizeof(struct sa_payload) + sizeof(u_int32_t), IPSEC_DOI);
288 	} else
289 		printf(" situation: (unknown)");
290 }
291 
292 int
293 ike_attribute_print (u_int8_t *buf, u_int8_t doi, int maxlen)
294 {
295 	static char *attrs[] = IKE_ATTR_INITIALIZER;
296 	static char *attr_enc[] = IKE_ATTR_ENCRYPT_INITIALIZER;
297 	static char *attr_hash[] = IKE_ATTR_HASH_INITIALIZER;
298 	static char *attr_auth[] = IKE_ATTR_AUTH_INITIALIZER;
299 	static char *attr_gdesc[] = IKE_ATTR_GROUP_DESC_INITIALIZER;
300 	static char *attr_gtype[] = IKE_ATTR_GROUP_INITIALIZER;
301 	static char *attr_ltype[] = IKE_ATTR_SA_DURATION_INITIALIZER;
302 	static char *ipsec_attrs[] = IPSEC_ATTR_INITIALIZER;
303 	static char *ipsec_attr_auth[] = IPSEC_ATTR_AUTH_INITIALIZER;
304 	static char *ipsec_attr_ltype[] = IPSEC_ATTR_DURATION_INITIALIZER;
305 
306 	u_int8_t af   = buf[0] >> 7;
307 	u_int16_t type = (buf[0] & 0x7f) << 8 | buf[1];
308 	u_int16_t len  = buf[2] << 8 | buf[3], val;
309 
310 	if (doi == ISAKMP_DOI)
311 		printf("\n\t%sattribute %s = ", ike_tab_offset(),
312 		    (type < sizeof attrs / sizeof attrs[0] ?
313 		    attrs[type] : "<unknown>"));
314 	else
315 		printf("\n\t%sattribute %s = ", ike_tab_offset(),
316 		    (type < (sizeof ipsec_attrs / sizeof ipsec_attrs[0]) ?
317 		    ipsec_attrs[type] : "<unknown>"));
318 
319 	if ((af == 1 && maxlen < 4) || (af == 0 && maxlen < (len + 4))) {
320 		printf("\n\t%s[|attr]", ike_tab_offset());
321 		return maxlen;
322 	}
323 
324 	if (af == 0) {
325 		/* AF=0; print the variable length attribute value */
326 		for (val = 0; val < len; val++)
327 			printf("%02x", *(buf + 4 + val));
328 		return len + 4;
329 	}
330 
331 	val = len;	/* For AF=1, this field is the "VALUE" */
332 	len = 4; 	/* and with AF=1, length is always 4 */
333 
334 #define CASE_PRINT(TYPE, var) \
335 	case TYPE : \
336 		if (val < sizeof var / sizeof var [0]) \
337 			printf("%s", var [val]); \
338 		else \
339 			printf("%d (unknown)", val); \
340 		break;
341 
342 	if (doi == ISAKMP_DOI)
343 		switch(type) {
344 			CASE_PRINT(IKE_ATTR_ENCRYPTION_ALGORITHM, attr_enc);
345 			CASE_PRINT(IKE_ATTR_HASH_ALGORITHM, attr_hash);
346 			CASE_PRINT(IKE_ATTR_AUTHENTICATION_METHOD, attr_auth);
347 			CASE_PRINT(IKE_ATTR_GROUP_DESC, attr_gdesc);
348 			CASE_PRINT(IKE_ATTR_GROUP_TYPE, attr_gtype);
349 			CASE_PRINT(IKE_ATTR_LIFE_TYPE, attr_ltype);
350 		default:
351 			printf("%d", val);
352 		}
353 	else
354 		switch(type) {
355 			CASE_PRINT(IPSEC_ATTR_SA_LIFE_TYPE, ipsec_attr_ltype);
356 			CASE_PRINT(IPSEC_ATTR_AUTHENTICATION_ALGORITHM,
357 			    ipsec_attr_auth);
358 			case IPSEC_ATTR_ENCAPSULATION_MODE:
359 				printf("%s", tok2str(ipsec_attr_encap,
360 				    "%d", val));
361 				break;
362 		default:
363 			printf("%d", val);
364 		}
365 
366 #undef CASE_PRINT
367 	return len;
368 }
369 
370 void
371 ike_pl_transform_print (u_int8_t *buf, int len, u_int8_t doi)
372 {
373 	struct transform_payload *tp = (struct transform_payload *)buf;
374 	const char *ah[] = IPSEC_AH_INITIALIZER;
375 	const char *esp[] = IPSEC_ESP_INITIALIZER;
376 	const char *ipcomp[] = IPCOMP_INITIALIZER;
377 	u_int8_t *attr = tp->attribute;
378 
379 	if (len < sizeof(struct transform_payload)) {
380 		printf(" [|payload]");
381 		return;
382 	}
383 
384 	printf("\n\t%stransform: %u ID: ", ike_tab_offset(), tp->ntrans);
385 
386 	switch (doi) {
387 	case ISAKMP_DOI:
388 		if (tp->transform < (sizeof ike / sizeof ike[0]))
389 			printf("%s", ike[tp->transform]);
390 		else
391 			printf("%d(unknown)", tp->transform);
392 		break;
393 
394 	default: /* IPSEC_DOI */
395 		switch (xform_proto) { /* from ike_proposal_print */
396 		case PROTO_IPSEC_AH:
397 			if (tp->transform < (sizeof ah / sizeof ah[0]))
398 				printf("%s", ah[tp->transform]);
399 			else
400 				printf("%d(unknown)", tp->transform);
401 			break;
402 		case PROTO_IPSEC_ESP:
403 			if (tp->transform < (sizeof esp / sizeof esp[0]))
404 				printf("%s", esp[tp->transform]);
405 			else
406 				printf("%d(unknown)", tp->transform);
407 			break;
408 		case PROTO_IPCOMP:
409 			if (tp->transform < (sizeof ipcomp / sizeof ipcomp[0]))
410 				printf("%s", ipcomp[tp->transform]);
411 			else
412 				printf("%d(unknown)", tp->transform);
413 			break;
414 		default:
415 			printf("%d(unknown)", tp->transform);
416 		}
417 		break;
418 	}
419 
420 	ike_tab_level++;
421 	while ((int)(attr - buf) < len) /* Skip last 'NONE' attr */
422 		attr += ike_attribute_print(attr, doi, len - (attr - buf));
423 	ike_tab_level--;
424 }
425 
426 void
427 ike_pl_proposal_print (u_int8_t *buf, int len, u_int8_t doi)
428 {
429 	struct proposal_payload *pp = (struct proposal_payload *)buf;
430 	int i;
431 
432 	if (len < sizeof(struct proposal_payload)) {
433 		printf(" [|payload]");
434 		return;
435 	}
436 
437 	printf(" proposal: %d proto: %s spisz: %d xforms: %d",
438 	    pp->nprop, (pp->proto < (sizeof ike / sizeof ike[0]) ?
439 	    ike[pp->proto] : "(unknown)"), pp->spi_size, pp->nspis);
440 
441 	xform_proto = pp->proto;
442 
443 	if (pp->spi_size) {
444 		if ((pp->spi + pp->spi_size) > (buf + len)) {
445 			printf(" [|payload]");
446 			return;
447 		}
448 		if (pp->proto == PROTO_IPCOMP)
449 			printf(" CPI: 0x");
450 		else
451 			printf(" SPI: 0x");
452 		for (i = 0; i < pp->spi_size; i++)
453 			printf("%02x", pp->spi[i]);
454 	}
455 
456 	/* Reset to sane value. */
457 	if (pp->proto == PROTO_ISAKMP)
458 		doi = ISAKMP_DOI;
459 	else
460 		doi = IPSEC_DOI;
461 
462 	if (pp->nspis > 0)
463 		ike_pl_print(PAYLOAD_TRANSFORM, pp->spi + pp->spi_size, doi);
464 }
465 
466 void
467 ike_pl_ke_print (u_int8_t *buf, int len, u_int8_t doi)
468 {
469 	if (len < sizeof(struct ke_payload)) {
470 		printf(" [|payload]");
471 		return;
472 	}
473 
474 	if (doi != IPSEC_DOI)
475 		return;
476 
477 	/* XXX ... */
478 }
479 
480 void
481 ipsec_id_print (u_int8_t *buf, int len, u_int8_t doi)
482 {
483 	struct id_payload *ip = (struct id_payload *)buf;
484 	static const char *idtypes[] = IPSEC_ID_TYPE_INITIALIZER;
485 	char ntop_buf[INET6_ADDRSTRLEN];
486 	struct in_addr in;
487 	u_int8_t *p;
488 
489 	if (len < sizeof (struct id_payload)) {
490 		printf(" [|payload]");
491 		return;
492 	}
493 
494 	if (doi != ISAKMP_DOI)
495 		return;
496 
497 	/* Don't print proto+port unless actually used */
498 	if (ip->id_data[0] | ip->id_data[1] | ip->id_data[2])
499 		printf(" proto: %d port: %d", ip->id_data[0],
500 		    (ip->id_data[1] << 8) + ip->id_data[2]);
501 
502 	printf(" type: %s = ", ip->type < (sizeof idtypes/sizeof idtypes[0]) ?
503 	    idtypes[ip->type] : "<unknown>");
504 
505 	switch (ip->type) {
506 	case IPSEC_ID_IPV4_ADDR:
507 		if ((ip->data + sizeof in) > (buf + len)) {
508 			printf(" [|payload]");
509 			return;
510 		}
511 		memcpy (&in.s_addr, ip->data, sizeof in);
512 		printf("%s", inet_ntoa (in));
513 		break;
514 
515 	case IPSEC_ID_IPV4_ADDR_SUBNET:
516 	case IPSEC_ID_IPV4_ADDR_RANGE:
517 		if ((ip->data + 2 * (sizeof in)) > (buf + len)) {
518 			printf(" [|payload]");
519 			return;
520 		}
521 		memcpy (&in.s_addr, ip->data, sizeof in);
522 		printf("%s%s", inet_ntoa (in),
523 		    ip->type == IPSEC_ID_IPV4_ADDR_SUBNET ? "/" : "-");
524 		memcpy (&in.s_addr, ip->data + sizeof in, sizeof in);
525 		printf("%s", inet_ntoa (in));
526 		break;
527 
528 	case IPSEC_ID_IPV6_ADDR:
529 		if ((ip->data + sizeof ntop_buf) > (buf + len)) {
530 			printf(" [|payload]");
531 			return;
532 		}
533 		printf("%s", inet_ntop (AF_INET6, ip->data, ntop_buf,
534 		    sizeof ntop_buf));
535 		break;
536 
537 	case IPSEC_ID_IPV6_ADDR_SUBNET:
538 	case IPSEC_ID_IPV6_ADDR_RANGE:
539 		if ((ip->data + 2 * sizeof ntop_buf) > (buf + len)) {
540 			printf(" [|payload]");
541 			return;
542 		}
543 		printf("%s%s", inet_ntop (AF_INET6, ip->data, ntop_buf,
544 		    sizeof ntop_buf),
545 		    ip->type == IPSEC_ID_IPV6_ADDR_SUBNET ? "/" : "-");
546 		printf("%s", inet_ntop (AF_INET6, ip->data + sizeof ntop_buf,
547 		    ntop_buf, sizeof ntop_buf));
548 		break;
549 
550 	case IPSEC_ID_FQDN:
551 	case IPSEC_ID_USER_FQDN:
552 		printf("\"");
553 		for (p = ip->data; (int)(p - buf) < len; p++)
554 			printf("%c",(isprint(*p) ? *p : '.'));
555 		printf("\"");
556 		break;
557 
558 	case IPSEC_ID_DER_ASN1_DN:
559 	case IPSEC_ID_DER_ASN1_GN:
560 	case IPSEC_ID_KEY_ID:
561 	default:
562 		printf("\"(not shown)\"");
563 		break;
564 	}
565 }
566 
567 void
568 ike_pl_delete_print (u_int8_t *buf, int len)
569 {
570   	struct delete_payload *dp = (struct delete_payload *)buf;
571 	u_int32_t doi;
572 	u_int16_t s, nspis;
573 	u_int8_t *data;
574 
575 	if (len < sizeof (struct delete_payload)) {
576 		printf(" [|payload]");
577 		return;
578 	}
579 
580 	doi   = ntohl(dp->doi);
581 	nspis = ntohs(dp->nspis);
582 
583 	if (doi != ISAKMP_DOI && doi != IPSEC_DOI) {
584 		printf(" (unknown DOI)");
585 		return;
586 	}
587 
588 	printf(" DOI: %u(%s) proto: %s nspis: %u", doi,
589 	    doi == ISAKMP_DOI ? "ISAKMP" : "IPSEC",
590 	    dp->proto < (sizeof ike / sizeof ike[0]) ? ike[dp->proto] :
591 	    "(unknown)", nspis);
592 
593 	if ((dp->spi + nspis * dp->spi_size) > (buf + len)) {
594 		printf(" [|payload]");
595 		return;
596 	}
597 
598 	for (s = 0; s < nspis; s++) {
599 		data = dp->spi + s * dp->spi_size;
600 		if (dp->spi_size == 16)
601 			printf("\n\t%scookie: %s", ike_tab_offset(),
602 			    ike_get_cookie(&data[0], &data[8]));
603 		else
604 			printf("\n\t%sSPI: 0x%08x", ike_tab_offset(),
605 			    data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3]);
606 	}
607 }
608 
609 void
610 ike_pl_notification_print (u_int8_t *buf, int len)
611 {
612   	static const char *nftypes[] = IKE_NOTIFY_TYPES_INITIALIZER;
613   	struct notification_payload *np = (struct notification_payload *)buf;
614 	u_int32_t *replay, *seq;
615 	u_int32_t doi;
616 	u_int16_t type;
617 	u_int8_t *attr;
618 
619 	if (len < sizeof (struct notification_payload)) {
620 		printf(" [|payload]");
621 		return;
622 	}
623 
624 	doi  = ntohl (np->doi);
625 	type = ntohs (np->type);
626 
627 	if (doi != ISAKMP_DOI && doi != IPSEC_DOI) {
628 		printf(" (unknown DOI)");
629 		return;
630 	}
631 
632 	printf("\n\t%snotification: ", ike_tab_offset());
633 
634 	if (type > 0 && type < (sizeof nftypes / sizeof nftypes[0])) {
635 		printf("%s", nftypes[type]);
636 		return;
637 	}
638 	switch (type) {
639 
640 	case NOTIFY_IPSEC_RESPONDER_LIFETIME:
641 		printf("RESPONDER LIFETIME ");
642 		if (np->spi_size == 16)
643 			printf("(%s)", ike_get_cookie (&np->data[0],
644 			    &np->data[8]));
645 		else
646 			printf("SPI: 0x%08x", np->data[0]<<24 |
647 			    np->data[1]<<16 | np->data[2]<<8 | np->data[3]);
648 		attr = &np->data[np->spi_size];
649 		ike_tab_level++;
650 		while ((int)(attr - buf) < len - 4)  /* Skip last 'NONE' attr */
651 			attr += ike_attribute_print(attr, IPSEC_DOI,
652 			    len - (attr-buf));
653 		ike_tab_level--;
654 		break;
655 
656 	case NOTIFY_IPSEC_REPLAY_STATUS:
657 		replay = (u_int32_t *)&np->data[np->spi_size];
658 		printf("REPLAY STATUS [%sabled] ", *replay ? "en" : "dis");
659 		if (np->spi_size == 16)
660 			printf("(%s)", ike_get_cookie (&np->data[0],
661 			    &np->data[8]));
662 		else
663 			printf("SPI: 0x%08x", np->data[0]<<24 |
664 			    np->data[1]<<16 | np->data[2]<<8 | np->data[3]);
665 		break;
666 
667 	case NOTIFY_IPSEC_INITIAL_CONTACT:
668 		printf("INITIAL CONTACT (%s)", ike_get_cookie (&np->data[0],
669 		    &np->data[8]));
670 		break;
671 
672 	case NOTIFY_STATUS_DPD_R_U_THERE:
673 	case NOTIFY_STATUS_DPD_R_U_THERE_ACK:
674 		printf("STATUS_DPD_R_U_THERE%s ",
675 		    type == NOTIFY_STATUS_DPD_R_U_THERE ? "" : "_ACK");
676 		if (np->spi_size != 16 ||
677 		    len < sizeof(struct notification_payload) +
678 		    sizeof(u_int32_t))
679 			printf("[bad notify]");
680 		else {
681 			seq = (u_int32_t *)&np->data[np->spi_size];
682 			printf("seq %u", ntohl(*seq));
683 		}
684 		break;
685 
686 
687 	default:
688 	  	printf("%d (unknown)", type);
689 		break;
690 	}
691 }
692 
693 void
694 ike_pl_vendor_print (u_int8_t *buf, int len, u_int8_t doi)
695 {
696 	struct vendor_payload *vp = (struct vendor_payload *)buf;
697 	u_int8_t *p;
698 	int i;
699 
700 	if (len < sizeof(struct vendor_payload)) {
701 		printf(" [|payload]");
702 		return;
703 	}
704 
705 	for (i = 0; i < sizeof vendor_ids / sizeof vendor_ids[0]; i ++)
706 		if (memcmp(vp->vid, vendor_ids[i].vid,
707 		    vendor_ids[i].len) == 0) {
708 			printf (" (supports %s)", vendor_ids[i].name);
709 			return;
710 		}
711 
712 	if (doi != IPSEC_DOI)
713 		return;
714 
715 	printf(" \"");
716 	for (p = vp->vid; (int)(p - buf) < len; p++)
717 		printf("%c", (isprint(*p) ? *p : '.'));
718 	printf("\"");
719 }
720 
721 /* IKE mode-config. */
722 int
723 ike_cfg_attribute_print (u_int8_t *buf, int attr_type, int maxlen)
724 {
725 	static char *attrs[] = IKE_CFG_ATTRIBUTE_INITIALIZER;
726 	char ntop_buf[INET6_ADDRSTRLEN];
727 	struct in_addr in;
728 
729 	u_int8_t af = buf[0] >> 7;
730 	u_int16_t type = (buf[0] & 0x7f) << 8 | buf[1];
731 	u_int16_t len = af ? 2 : buf[2] << 8 | buf[3], p;
732 	u_int8_t *val = af ? buf + 2 : buf + 4;
733 
734 	printf("\n\t%sattribute %s = ", ike_tab_offset(),
735 	    type < (sizeof attrs / sizeof attrs[0]) ? attrs[type] :
736 	    "<unknown>");
737 
738 	if ((af == 1 && maxlen < 4) ||
739 	    (af == 0 && maxlen < (len + 4))) {
740 		printf("\n\t%s[|attr]", ike_tab_offset());
741 		return maxlen;
742 	}
743 
744 	/* XXX The 2nd term is for bug compatibility with PGPnet.  */
745 	if (len == 0 || (af && !val[0] && !val[1])) {
746 		printf("<none>");
747 		return 4;
748 	}
749 
750 	/* XXX Generally lengths are not checked well below.  */
751 	switch (type) {
752 	case IKE_CFG_ATTR_INTERNAL_IP4_ADDRESS:
753 	case IKE_CFG_ATTR_INTERNAL_IP4_NETMASK:
754 	case IKE_CFG_ATTR_INTERNAL_IP4_DNS:
755 	case IKE_CFG_ATTR_INTERNAL_IP4_NBNS:
756 	case IKE_CFG_ATTR_INTERNAL_IP4_DHCP:
757 		memcpy (&in.s_addr, val, sizeof in);
758 		printf("%s", inet_ntoa (in));
759 		break;
760 
761 	case IKE_CFG_ATTR_INTERNAL_IP6_ADDRESS:
762 	case IKE_CFG_ATTR_INTERNAL_IP6_NETMASK:
763 	case IKE_CFG_ATTR_INTERNAL_IP6_DNS:
764 	case IKE_CFG_ATTR_INTERNAL_IP6_NBNS:
765 	case IKE_CFG_ATTR_INTERNAL_IP6_DHCP:
766 		printf("%s", inet_ntop (AF_INET6, val, ntop_buf,
767 		    sizeof ntop_buf));
768 		break;
769 
770 	case IKE_CFG_ATTR_INTERNAL_IP4_SUBNET:
771 		memcpy(&in.s_addr, val, sizeof in);
772 		printf("%s/", inet_ntoa (in));
773 		memcpy(&in.s_addr, val + sizeof in, sizeof in);
774 		printf("%s", inet_ntoa (in));
775 		break;
776 
777 	case IKE_CFG_ATTR_INTERNAL_IP6_SUBNET:
778 		printf("%s/%u", inet_ntop (AF_INET6, val, ntop_buf,
779 		    sizeof ntop_buf), val[16]);
780 		break;
781 
782 	case IKE_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
783 		printf("%u seconds",
784 		    val[0] << 24 | val[1] << 16 | val[2] << 8 | val[3]);
785 		break;
786 
787 	case IKE_CFG_ATTR_APPLICATION_VERSION:
788 		for (p = 0; p < len; p++)
789 			printf("%c", isprint(val[p]) ? val[p] : '.');
790 		break;
791 
792 	case IKE_CFG_ATTR_SUPPORTED_ATTRIBUTES:
793 		printf("<%d attributes>", len / 2);
794 		ike_tab_level++;
795 		for (p = 0; p < len; p += 2) {
796 			type = (val[p] << 8 | val[p + 1]) & 0x7fff;
797 			printf("\n\t%s%s", ike_tab_offset(),
798 			    type < (sizeof attrs/sizeof attrs[0]) ?
799 			    attrs[type] : "<unknown>");
800 		}
801 		ike_tab_level--;
802 		break;
803 
804 	default:
805 		break;
806 	}
807 	return af ? 4 : len + 4;
808 }
809 
810 void
811 ike_pl_attribute_print (u_int8_t *buf, int len)
812 {
813 	struct attribute_payload *ap = (struct attribute_payload *)buf;
814 	static const char *pl_attr[] = IKE_CFG_ATTRIBUTE_TYPE_INITIALIZER;
815 	u_int8_t *attr = buf + sizeof(struct attribute_payload);
816 
817 	if (len < sizeof(struct attribute_payload)) {
818 		printf(" [|payload]");
819 		return;
820 	}
821 
822 	printf(" type: %s Id: %d",
823 	    ap->type < (sizeof pl_attr/sizeof pl_attr[0]) ? pl_attr[ap->type] :
824 	    "<unknown>", ap->id);
825 
826 	while ((int)(attr - buf) < len)
827 		attr += ike_cfg_attribute_print(attr, ap->type,
828 		    len - (attr - buf));
829 }
830 
831 void
832 ike_pl_print (u_int8_t type, u_int8_t *buf, u_int8_t doi)
833 {
834 	static const char *pltypes[] = IKE_PAYLOAD_TYPES_INITIALIZER;
835 	static const char *plprivtypes[] =
836 	    IKE_PRIVATE_PAYLOAD_TYPES_INITIALIZER;
837 	static const char *plv2types[] = IKEV2_PAYLOAD_TYPES_INITIALIZER;
838 	u_int8_t next_type;
839 	u_int16_t this_len;
840 
841 	if (&buf[4] > snapend) {
842 		goto pltrunc;
843 	}
844 
845 	next_type = buf[0];
846 	this_len = buf[2]<<8 | buf[3];
847 
848 	if (type < PAYLOAD_PRIVATE_MIN && type >= PAYLOAD_IKEV2_SA)
849 		printf("\n\t%spayload: %s len: %hu", ike_tab_offset(),
850 		    plv2types[type - PAYLOAD_IKEV2_SA], this_len);
851 	else if (type < PAYLOAD_PRIVATE_MIN || type >= PAYLOAD_PRIVATE_MAX)
852 		printf("\n\t%spayload: %s len: %hu", ike_tab_offset(),
853 		    (type < (sizeof pltypes/sizeof pltypes[0]) ?
854 			pltypes[type] : "<unknown>"), this_len);
855 	else
856 		printf("\n\t%spayload: %s len: %hu", ike_tab_offset(),
857 		    plprivtypes[type - PAYLOAD_PRIVATE_MIN], this_len);
858 
859 	if ((type < PAYLOAD_RESERVED_MIN &&
860 	    (type < sizeof(min_payload_lengths)/sizeof(min_payload_lengths[0]) &&
861 	    this_len < min_payload_lengths[type])) ||
862 	    this_len == 0)
863 		goto pltrunc;
864 
865 	if ((type > PAYLOAD_PRIVATE_MIN && type < PAYLOAD_PRIVATE_MAX &&
866 	    this_len < min_priv_payload_lengths[type - PAYLOAD_PRIVATE_MIN]) ||
867 	    this_len == 0)
868 		goto pltrunc;
869 
870 	if (buf + this_len > snapend)
871 		goto pltrunc;
872 
873 	ike_tab_level++;
874 	switch (type) {
875 	case PAYLOAD_NONE:
876 		return;
877 
878 	case PAYLOAD_SA:
879 		ike_pl_sa_print(buf, this_len);
880 		break;
881 
882 	case PAYLOAD_PROPOSAL:
883 		ike_pl_proposal_print(buf, this_len, doi);
884 		break;
885 
886 	case PAYLOAD_TRANSFORM:
887 		ike_pl_transform_print(buf, this_len, doi);
888 		break;
889 
890 	case PAYLOAD_KE:
891 		ike_pl_ke_print(buf, this_len, doi);
892 		break;
893 
894 	case PAYLOAD_ID:
895 		/* Should only happen with IPsec DOI */
896 		ipsec_id_print(buf, this_len, doi);
897 		break;
898 
899 	case PAYLOAD_CERT:
900 	case PAYLOAD_CERTREQUEST:
901 	case PAYLOAD_HASH:
902 	case PAYLOAD_SIG:
903 	case PAYLOAD_NONCE:
904 		break;
905 
906 	case PAYLOAD_DELETE:
907 		ike_pl_delete_print(buf, this_len);
908 		break;
909 
910 	case PAYLOAD_NOTIFICATION:
911 	  	ike_pl_notification_print(buf, this_len);
912 		break;
913 
914 	case PAYLOAD_VENDOR:
915 		ike_pl_vendor_print(buf, this_len, doi);
916 		break;
917 
918 	case PAYLOAD_ATTRIBUTE:
919 		ike_pl_attribute_print(buf, this_len);
920 		break;
921 
922 	case PAYLOAD_SAK:
923 	case PAYLOAD_SAT:
924 	case PAYLOAD_KD:
925 	case PAYLOAD_SEQ:
926 	case PAYLOAD_POP:
927 	case PAYLOAD_NAT_D:
928 		break;
929 
930 	case PAYLOAD_NAT_OA:
931 		/* RFC3947 NAT-OA uses a subset of the ID payload */
932 		ipsec_id_print(buf, this_len, doi);
933 		break;
934 
935 	case PAYLOAD_NAT_D_DRAFT:
936 		break;
937 
938 	case PAYLOAD_NAT_OA_DRAFT:
939 		ipsec_id_print(buf, this_len, doi);
940 		break;
941 
942 	default:
943 		break;
944 	}
945 	ike_tab_level--;
946 
947 	if (next_type)  /* Recurse over next payload */
948 		ike_pl_print(next_type, buf + this_len, doi);
949 
950 	return;
951 
952 pltrunc:
953 	if (doi == ISAKMP_DOI)
954 		printf(" [|isakmp]");
955 	else
956 		printf(" [|ipsec]");
957 }
958