xref: /openbsd/usr.sbin/tcpdump/print-tcp.c (revision 9b7c3dbb)
1 /*	$OpenBSD: print-tcp.c,v 1.35 2015/11/16 00:16:39 mmcc Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
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 
24 #include <sys/time.h>
25 #include <sys/socket.h>
26 
27 #include <netinet/in.h>
28 #include <netinet/ip.h>
29 #include <netinet/ip_var.h>
30 #include <netinet/tcp.h>
31 #include <net/if.h>
32 #include <net/pfvar.h>
33 
34 #include <rpc/rpc.h>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #ifdef INET6
42 #include <netinet/ip6.h>
43 #endif
44 
45 #include "interface.h"
46 #include "addrtoname.h"
47 #include "extract.h"
48 
49 #include "nfs.h"
50 
51 static void print_tcp_rst_data(const u_char *sp, u_int length);
52 
53 #define MAX_RST_DATA_LEN	30
54 
55 /* Compatibility */
56 #ifndef TCPOPT_WSCALE
57 #define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
58 #endif
59 #ifndef TCPOPT_SACKOK
60 #define	TCPOPT_SACKOK		4	/* selective ack ok (rfc2018) */
61 #endif
62 #ifndef TCPOPT_SACK
63 #define	TCPOPT_SACK		5	/* selective ack (rfc2018) */
64 #endif
65 #ifndef TCPOLEN_SACK
66 #define TCPOLEN_SACK		8	/* length of a SACK block */
67 #endif
68 #ifndef TCPOPT_ECHO
69 #define	TCPOPT_ECHO		6	/* echo (rfc1072) */
70 #endif
71 #ifndef TCPOPT_ECHOREPLY
72 #define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
73 #endif
74 #ifndef TCPOPT_TIMESTAMP
75 #define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
76 #endif
77 #ifndef TCPOPT_CC
78 #define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
79 #endif
80 #ifndef TCPOPT_CCNEW
81 #define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
82 #endif
83 #ifndef TCPOPT_CCECHO
84 #define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
85 #endif
86 
87 /* Definitions required for ECN
88    for use if the OS running tcpdump does not have ECN */
89 #ifndef TH_ECNECHO
90 #define TH_ECNECHO		0x40	/* ECN Echo in tcp header */
91 #endif
92 #ifndef TH_CWR
93 #define TH_CWR			0x80	/* ECN Cwnd Reduced in tcp header*/
94 #endif
95 
96 struct tha {
97 #ifndef INET6
98 	struct in_addr src;
99 	struct in_addr dst;
100 #else
101 	struct in6_addr src;
102 	struct in6_addr dst;
103 #endif /*INET6*/
104 	u_int port;
105 };
106 
107 struct tcp_seq_hash {
108 	struct tcp_seq_hash *nxt;
109 	struct tha addr;
110 	tcp_seq seq;
111 	tcp_seq ack;
112 };
113 
114 #define TSEQ_HASHSIZE 919
115 
116 /* These tcp optinos do not have the size octet */
117 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
118 
119 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
120 
121 #ifndef BGP_PORT
122 #define BGP_PORT        179
123 #endif
124 #define NETBIOS_SSN_PORT 139
125 
126 static int tcp_cksum(const struct ip *ip, const struct tcphdr *tp, int len)
127 {
128 	union phu {
129 		struct phdr {
130 			u_int32_t src;
131 			u_int32_t dst;
132 			u_char mbz;
133 			u_char proto;
134 			u_int16_t len;
135 		} ph;
136 		u_int16_t pa[6];
137 	} phu;
138 	const u_int16_t *sp;
139 	u_int32_t sum;
140 
141 	/* pseudo-header.. */
142 	phu.ph.len = htons((u_int16_t)len);
143 	phu.ph.mbz = 0;
144 	phu.ph.proto = IPPROTO_TCP;
145 	memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
146 	memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
147 
148 	sp = &phu.pa[0];
149 	sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5];
150 
151 	return in_cksum((u_short *)tp, len, sum);
152 }
153 
154 #ifdef INET6
155 static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp,
156 		      u_int len)
157 {
158 	union {
159 		struct {
160 			struct in6_addr ph_src;
161 			struct in6_addr ph_dst;
162 			u_int32_t       ph_len;
163 			u_int8_t        ph_zero[3];
164 			u_int8_t        ph_nxt;
165 		} ph;
166 		u_int16_t pa[20];
167 	} phu;
168 	size_t i;
169 	u_int32_t sum = 0;
170 
171 	/* pseudo-header */
172 	memset(&phu, 0, sizeof(phu));
173 	phu.ph.ph_src = ip6->ip6_src;
174 	phu.ph.ph_dst = ip6->ip6_dst;
175 	phu.ph.ph_len = htonl(len);
176 	phu.ph.ph_nxt = IPPROTO_TCP;
177 
178 	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
179 		sum += phu.pa[i];
180 
181 	return in_cksum((u_short *)tp, len, sum);
182 }
183 #endif
184 
185 
186 void
187 tcp_print(const u_char *bp, u_int length, const u_char *bp2)
188 {
189 	const struct tcphdr *tp;
190 	const struct ip *ip;
191 	u_char flags;
192 	int hlen;
193 	char ch;
194 	struct tcp_seq_hash *th = NULL;
195 	int rev = 0;
196 	u_int16_t sport, dport, win, urp;
197 	tcp_seq seq, ack;
198 #ifdef INET6
199 	const struct ip6_hdr *ip6;
200 #endif
201 
202 	tp = (struct tcphdr *)bp;
203 	switch (((struct ip *)bp2)->ip_v) {
204 	case 4:
205 		ip = (struct ip *)bp2;
206 #ifdef INET6
207 		ip6 = NULL;
208 #endif
209 		break;
210 #ifdef INET6
211 	case 6:
212 		ip = NULL;
213 		ip6 = (struct ip6_hdr *)bp2;
214 		break;
215 #endif
216 	default:
217 		(void)printf("invalid ip version");
218 		return;
219 	}
220 
221 	ch = '\0';
222 	if (length < sizeof(*tp)) {
223 		(void)printf("truncated-tcp %u", length);
224 		return;
225 	}
226 
227 	if (!TTEST(tp->th_dport)) {
228 #ifdef INET6
229 		if (ip6) {
230 			(void)printf("%s > %s: [|tcp]",
231 				ip6addr_string(&ip6->ip6_src),
232 				ip6addr_string(&ip6->ip6_dst));
233 		} else
234 #endif /*INET6*/
235 		{
236 			(void)printf("%s > %s: [|tcp]",
237 				ipaddr_string(&ip->ip_src),
238 				ipaddr_string(&ip->ip_dst));
239 		}
240 		return;
241 	}
242 
243 	sport = ntohs(tp->th_sport);
244 	dport = ntohs(tp->th_dport);
245 
246 #ifdef INET6
247 	if (ip6) {
248 		if (ip6->ip6_nxt == IPPROTO_TCP) {
249 			(void)printf("%s.%s > %s.%s: ",
250 				ip6addr_string(&ip6->ip6_src),
251 				tcpport_string(sport),
252 				ip6addr_string(&ip6->ip6_dst),
253 				tcpport_string(dport));
254 		} else {
255 			(void)printf("%s > %s: ",
256 				tcpport_string(sport), tcpport_string(dport));
257 		}
258 	} else
259 #endif /*INET6*/
260 	{
261 		if (ip->ip_p == IPPROTO_TCP) {
262 			(void)printf("%s.%s > %s.%s: ",
263 				ipaddr_string(&ip->ip_src),
264 				tcpport_string(sport),
265 				ipaddr_string(&ip->ip_dst),
266 				tcpport_string(dport));
267 		} else {
268 			(void)printf("%s > %s: ",
269 				tcpport_string(sport), tcpport_string(dport));
270 		}
271 	}
272 
273 	if (!qflag && TTEST(tp->th_seq) && !TTEST(tp->th_ack))
274 		(void)printf("%u ", ntohl(tp->th_seq));
275 
276 	TCHECK(*tp);
277 	seq = ntohl(tp->th_seq);
278 	ack = ntohl(tp->th_ack);
279 	win = ntohs(tp->th_win);
280 	urp = ntohs(tp->th_urp);
281 	hlen = tp->th_off * 4;
282 
283 	if (qflag) {
284 		(void)printf("tcp %d", length - tp->th_off * 4);
285 		return;
286 	} else if (packettype != PT_TCP) {
287 
288 		/*
289 		 * If data present and NFS port used, assume NFS.
290 		 * Pass offset of data plus 4 bytes for RPC TCP msg length
291 		 * to NFS print routines.
292 		 */
293 		u_int len = length - hlen;
294 		if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend &&
295 		    dport == NFS_PORT) {
296 			nfsreq_print((u_char *)tp + hlen + 4, len, bp2);
297 			return;
298 		} else if ((u_char *)tp + 4 +
299 		    sizeof(struct rpc_msg) <= snapend && sport == NFS_PORT) {
300 			nfsreply_print((u_char *)tp + hlen + 4, len, bp2);
301 			return;
302 		}
303 	}
304 	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
305 				      TH_ECNECHO|TH_CWR)) {
306 		if (flags & TH_SYN)
307 			putchar('S');
308 		if (flags & TH_FIN)
309 			putchar('F');
310 		if (flags & TH_RST)
311 			putchar('R');
312 		if (flags & TH_PUSH)
313 			putchar('P');
314 		if (flags & TH_CWR)
315 			putchar('W');	/* congestion _W_indow reduced (ECN) */
316 		if (flags & TH_ECNECHO)
317 			putchar('E');	/* ecn _E_cho sent (ECN) */
318 	} else
319 		putchar('.');
320 
321 	if (!Sflag && (flags & TH_ACK)) {
322 		struct tha tha;
323 		/*
324 		 * Find (or record) the initial sequence numbers for
325 		 * this conversation.  (we pick an arbitrary
326 		 * collating order so there's only one entry for
327 		 * both directions).
328 		 */
329 #ifdef INET6
330 		bzero(&tha, sizeof(tha));
331 		rev = 0;
332 		if (ip6) {
333 			if (sport > dport) {
334 				rev = 1;
335 			} else if (sport == dport) {
336 			    int i;
337 
338 			    for (i = 0; i < 4; i++) {
339 				if (((u_int32_t *)(&ip6->ip6_src))[i] >
340 				    ((u_int32_t *)(&ip6->ip6_dst))[i]) {
341 					rev = 1;
342 					break;
343 				}
344 			    }
345 			}
346 			if (rev) {
347 				tha.src = ip6->ip6_dst;
348 				tha.dst = ip6->ip6_src;
349 				tha.port = dport << 16 | sport;
350 			} else {
351 				tha.dst = ip6->ip6_dst;
352 				tha.src = ip6->ip6_src;
353 				tha.port = sport << 16 | dport;
354 			}
355 		} else {
356 			if (sport > dport ||
357 			    (sport == dport &&
358 			     ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
359 				rev = 1;
360 			}
361 			if (rev) {
362 				*(struct in_addr *)&tha.src = ip->ip_dst;
363 				*(struct in_addr *)&tha.dst = ip->ip_src;
364 				tha.port = dport << 16 | sport;
365 			} else {
366 				*(struct in_addr *)&tha.dst = ip->ip_dst;
367 				*(struct in_addr *)&tha.src = ip->ip_src;
368 				tha.port = sport << 16 | dport;
369 			}
370 		}
371 #else
372 		if (sport < dport ||
373 		    (sport == dport &&
374 		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
375 			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
376 			tha.port = sport << 16 | dport;
377 			rev = 0;
378 		} else {
379 			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
380 			tha.port = dport << 16 | sport;
381 			rev = 1;
382 		}
383 #endif
384 
385 		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
386 		     th->nxt; th = th->nxt)
387 			if (!memcmp((char *)&tha, (char *)&th->addr,
388 				  sizeof(th->addr)))
389 				break;
390 
391 		if (!th->nxt || flags & TH_SYN) {
392 			/* didn't find it or new conversation */
393 			if (th->nxt == NULL) {
394 				th->nxt = calloc(1, sizeof(*th));
395 				if (th->nxt == NULL)
396 					error("tcp_print: calloc");
397 			}
398 			th->addr = tha;
399 			if (rev)
400 				th->ack = seq, th->seq = ack - 1;
401 			else
402 				th->seq = seq, th->ack = ack - 1;
403 		} else {
404 			if (rev)
405 				seq -= th->ack, ack -= th->seq;
406 			else
407 				seq -= th->seq, ack -= th->ack;
408 		}
409 	}
410 	hlen = tp->th_off * 4;
411 	if (hlen > length) {
412 		(void)printf(" [bad hdr length]");
413 		return;
414 	}
415 
416 	if (ip && ip->ip_v == 4 && vflag) {
417 		if (TTEST2(tp->th_sport, length)) {
418 			u_int16_t sum, tcp_sum;
419 			sum = tcp_cksum(ip, tp, length);
420 			if (sum != 0) {
421 				tcp_sum = EXTRACT_16BITS(&tp->th_sum);
422 				(void)printf(" [bad tcp cksum %x! -> %x]", tcp_sum,
423 				    in_cksum_shouldbe(tcp_sum, sum));
424 			} else
425 				(void)printf(" [tcp sum ok]");
426 		}
427 	}
428 #ifdef INET6
429 	if (ip6 && ip6->ip6_plen && vflag) {
430 		if (TTEST2(tp->th_sport, length)) {
431 			u_int16_t sum, tcp_sum;
432 			sum = tcp6_cksum(ip6, tp, length);
433 			if (sum != 0) {
434 				tcp_sum = EXTRACT_16BITS(&tp->th_sum);
435 				(void)printf(" [bad tcp cksum %x! -> %x]", tcp_sum,
436 				    in_cksum_shouldbe(tcp_sum, sum));
437 			} else
438 				(void)printf(" [tcp sum ok]");
439 		}
440 	}
441 #endif
442 
443 	/* OS Fingerprint */
444 	if (oflag && (flags & (TH_SYN|TH_ACK)) == TH_SYN) {
445 		struct pf_osfp_enlist *head = NULL;
446 		struct pf_osfp_entry *fp;
447 		unsigned long left;
448 		left = (unsigned long)(snapend - (const u_char *)tp);
449 
450 		if (left >= hlen)
451 			head = pf_osfp_fingerprint_hdr(ip, ip6, tp);
452 		if (head) {
453 			int prev = 0;
454 			printf(" (src OS:");
455 			SLIST_FOREACH(fp, head, fp_entry) {
456 				if (fp->fp_enflags & PF_OSFP_EXPANDED)
457 					continue;
458 				if (prev)
459 					printf(",");
460 				printf(" %s", fp->fp_class_nm);
461 				if (fp->fp_version_nm[0])
462 					printf(" %s", fp->fp_version_nm);
463 				if (fp->fp_subtype_nm[0])
464 					printf(" %s", fp->fp_subtype_nm);
465 				prev = 1;
466 			}
467 			printf(")");
468 		} else {
469 			if (left < hlen)
470 				printf(" (src OS: short-pkt)");
471 			else
472 				printf(" (src OS: unknown)");
473 		}
474 	}
475 
476 	length -= hlen;
477 	if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
478 		(void)printf(" %u:%u(%u)", seq, seq + length, length);
479 	if (flags & TH_ACK)
480 		(void)printf(" ack %u", ack);
481 
482 	(void)printf(" win %u", win);
483 
484 	if (flags & TH_URG)
485 		(void)printf(" urg %u", urp);
486 	/*
487 	 * Handle any options.
488 	 */
489 	if ((hlen -= sizeof(*tp)) > 0) {
490 		const u_char *cp;
491 		int i, opt, len, datalen;
492 
493 		cp = (const u_char *)tp + sizeof(*tp);
494 		putchar(' ');
495 		ch = '<';
496 		while (hlen > 0) {
497 			putchar(ch);
498 			TCHECK(*cp);
499 			opt = *cp++;
500 			if (ZEROLENOPT(opt))
501 				len = 1;
502 			else {
503 				TCHECK(*cp);
504 				len = *cp++;	/* total including type, len */
505 				if (len < 2 || len > hlen)
506 					goto bad;
507 				--hlen;		/* account for length byte */
508 			}
509 			--hlen;			/* account for type byte */
510 			datalen = 0;
511 
512 /* Bail if "l" bytes of data are not left or were not captured  */
513 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
514 
515 			switch (opt) {
516 
517 			case TCPOPT_MAXSEG:
518 				(void)printf("mss");
519 				datalen = 2;
520 				LENCHECK(datalen);
521 				(void)printf(" %u", EXTRACT_16BITS(cp));
522 
523 				break;
524 
525 			case TCPOPT_EOL:
526 				(void)printf("eol");
527 				break;
528 
529 			case TCPOPT_NOP:
530 				(void)printf("nop");
531 				break;
532 
533 			case TCPOPT_WSCALE:
534 				(void)printf("wscale");
535 				datalen = 1;
536 				LENCHECK(datalen);
537 				(void)printf(" %u", *cp);
538 				break;
539 
540 			case TCPOPT_SACKOK:
541 				(void)printf("sackOK");
542 				if (len != 2)
543 					(void)printf("[len %d]", len);
544 				break;
545 
546 			case TCPOPT_SACK:
547 			{
548 				u_long s, e;
549 
550 				datalen = len - 2;
551 				if ((datalen % TCPOLEN_SACK) != 0 ||
552 				    !(flags & TH_ACK)) {
553 				         (void)printf("malformed sack ");
554 					 (void)printf("[len %d] ", datalen);
555 					 break;
556 				}
557 				printf("sack %d ", datalen/TCPOLEN_SACK);
558 				for (i = 0; i < datalen; i += TCPOLEN_SACK) {
559 					LENCHECK (i + TCPOLEN_SACK);
560 					s = EXTRACT_32BITS(cp + i);
561 					e = EXTRACT_32BITS(cp + i + 4);
562 					if (!Sflag) {
563 						if (rev) {
564 							s -= th->seq;
565 							e -= th->seq;
566 						} else {
567 							s -= th->ack;
568 							e -= th->ack;
569 						}
570 					}
571 					(void) printf("{%lu:%lu} ", s, e);
572 				}
573 				break;
574 			}
575 			case TCPOPT_ECHO:
576 				(void)printf("echo");
577 				datalen = 4;
578 				LENCHECK(datalen);
579 				(void)printf(" %u", EXTRACT_32BITS(cp));
580 				break;
581 
582 			case TCPOPT_ECHOREPLY:
583 				(void)printf("echoreply");
584 				datalen = 4;
585 				LENCHECK(datalen);
586 				(void)printf(" %u", EXTRACT_32BITS(cp));
587 				break;
588 
589 			case TCPOPT_TIMESTAMP:
590 				(void)printf("timestamp");
591 				datalen = 8;
592 				LENCHECK(4);
593 				(void)printf(" %u", EXTRACT_32BITS(cp));
594 				LENCHECK(datalen);
595 				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
596 				break;
597 
598 			case TCPOPT_CC:
599 				(void)printf("cc");
600 				datalen = 4;
601 				LENCHECK(datalen);
602 				(void)printf(" %u", EXTRACT_32BITS(cp));
603 				break;
604 
605 			case TCPOPT_CCNEW:
606 				(void)printf("ccnew");
607 				datalen = 4;
608 				LENCHECK(datalen);
609 				(void)printf(" %u", EXTRACT_32BITS(cp));
610 				break;
611 
612 			case TCPOPT_CCECHO:
613 				(void)printf("ccecho");
614 				datalen = 4;
615 				LENCHECK(datalen);
616 				(void)printf(" %u", EXTRACT_32BITS(cp));
617 				break;
618 
619 			case TCPOPT_SIGNATURE:
620 				(void)printf("tcpmd5:");
621 				datalen = len - 2;
622 				for (i = 0; i < datalen; ++i) {
623 					LENCHECK(i+1);
624 					(void)printf("%02x", cp[i]);
625 				}
626 				break;
627 
628 			default:
629 				(void)printf("opt-%d:", opt);
630 				datalen = len - 2;
631 				for (i = 0; i < datalen; ++i) {
632 					LENCHECK(i+1);
633 					(void)printf("%02x", cp[i]);
634 				}
635 				break;
636 			}
637 
638 			/* Account for data printed */
639 			cp += datalen;
640 			hlen -= datalen;
641 
642 			/* Check specification against observed length */
643 			++datalen;			/* option octet */
644 			if (!ZEROLENOPT(opt))
645 				++datalen;		/* size octet */
646 			if (datalen != len)
647 				(void)printf("[len %d]", len);
648 			ch = ',';
649 			if (opt == TCPOPT_EOL)
650 				break;
651 		}
652 		putchar('>');
653 	}
654 
655 	if (length <= 0)
656 		return;
657 
658 	/*
659 	 * Decode payload if necessary.
660 	*/
661 	bp += (tp->th_off * 4);
662 	if (flags & TH_RST) {
663 		if (vflag)
664 			print_tcp_rst_data(bp, length);
665 	} else {
666 		if (sport == BGP_PORT || dport == BGP_PORT)
667 			bgp_print(bp, length);
668 #if 0
669 		else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
670 			nbt_tcp_print(bp, length);
671 #endif
672 	}
673 	return;
674 bad:
675 	fputs("[bad opt]", stdout);
676 	if (ch != '\0')
677 		putchar('>');
678 	return;
679 trunc:
680 	fputs("[|tcp]", stdout);
681 	if (ch != '\0')
682 		putchar('>');
683 }
684 
685 
686 /*
687  * RFC1122 says the following on data in RST segments:
688  *
689  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
690  *
691  *            A TCP SHOULD allow a received RST segment to include data.
692  *
693  *            DISCUSSION
694  *                 It has been suggested that a RST segment could contain
695  *                 ASCII text that encoded and explained the cause of the
696  *                 RST.  No standard has yet been established for such
697  *                 data.
698  *
699  */
700 
701 static void
702 print_tcp_rst_data(const u_char *sp, u_int length)
703 {
704 	int c;
705 
706 	if (TTEST2(*sp, length))
707 		printf(" [RST");
708 	else
709 		printf(" [!RST");
710 	if (length > MAX_RST_DATA_LEN) {
711 		length = MAX_RST_DATA_LEN;	/* can use -X for longer */
712 		putchar('+');			/* indicate we truncate */
713 	}
714 	putchar(' ');
715 	while (length-- && sp < snapend) {
716 		c = *sp++;
717 		safeputchar(c);
718 	}
719 	putchar(']');
720 }
721