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