xref: /netbsd-src/external/bsd/tcpdump/dist/print-tcp.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	NetBSD: print-tcp.c,v 1.9 2007/07/26 18:15:12 plunky 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  * Copyright (c) 1999-2004 The tcpdump.org project
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that: (1) source code distributions
11  * retain the above copyright notice and this paragraph in its entirety, (2)
12  * distributions including binary code include the above copyright notice and
13  * this paragraph in its entirety in the documentation or other materials
14  * provided with the distribution, and (3) all advertising materials mentioning
15  * features or use of this software display the following acknowledgement:
16  * ``This product includes software developed by the University of California,
17  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
18  * the University nor the names of its contributors may be used to endorse
19  * or promote products derived from this software without specific prior
20  * written permission.
21  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24  */
25 
26 #include <sys/cdefs.h>
27 #ifndef lint
28 #if 0
29 static const char rcsid[] _U_ =
30 "@(#) Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.135 2008-11-09 23:35:03 mcr Exp  (LBL)";
31 #else
32 __RCSID("$NetBSD: print-tcp.c,v 1.3 2013/04/06 19:33:08 christos Exp $");
33 #endif
34 #endif
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <tcpdump-stdinc.h>
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "extract.h"
49 
50 #include "tcp.h"
51 
52 #include "ip.h"
53 #ifdef INET6
54 #include "ip6.h"
55 #endif
56 #include "ipproto.h"
57 #include "rpc_auth.h"
58 #include "rpc_msg.h"
59 
60 #include "nameser.h"
61 
62 #ifdef HAVE_LIBCRYPTO
63 #include <openssl/md5.h>
64 #include <signature.h>
65 
66 static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
67                                 const u_char *data, int length, const u_char *rcvsig);
68 #endif
69 
70 static void print_tcp_rst_data(register const u_char *sp, u_int length);
71 
72 #define MAX_RST_DATA_LEN	30
73 
74 
75 struct tha {
76 #ifndef INET6
77         struct in_addr src;
78         struct in_addr dst;
79 #else
80         struct in6_addr src;
81         struct in6_addr dst;
82 #endif /*INET6*/
83         u_int port;
84 };
85 
86 struct tcp_seq_hash {
87         struct tcp_seq_hash *nxt;
88         struct tha addr;
89         tcp_seq seq;
90         tcp_seq ack;
91 };
92 
93 #define TSEQ_HASHSIZE 919
94 
95 /* These tcp optinos do not have the size octet */
96 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
97 
98 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
99 
100 struct tok tcp_flag_values[] = {
101         { TH_FIN, "F" },
102         { TH_SYN, "S" },
103         { TH_RST, "R" },
104         { TH_PUSH, "P" },
105         { TH_ACK, "." },
106         { TH_URG, "U" },
107         { TH_ECNECHO, "E" },
108         { TH_CWR, "W" },
109         { 0, NULL }
110 };
111 
112 struct tok tcp_option_values[] = {
113         { TCPOPT_EOL, "eol" },
114         { TCPOPT_NOP, "nop" },
115         { TCPOPT_MAXSEG, "mss" },
116         { TCPOPT_WSCALE, "wscale" },
117         { TCPOPT_SACKOK, "sackOK" },
118         { TCPOPT_SACK, "sack" },
119         { TCPOPT_ECHO, "echo" },
120         { TCPOPT_ECHOREPLY, "echoreply" },
121         { TCPOPT_TIMESTAMP, "TS" },
122         { TCPOPT_CC, "cc" },
123         { TCPOPT_CCNEW, "ccnew" },
124         { TCPOPT_CCECHO, "" },
125         { TCPOPT_SIGNATURE, "md5" },
126         { TCPOPT_AUTH, "enhanced auth" },
127         { TCPOPT_UTO, "uto" },
128         { 0, NULL }
129 };
130 
131 static int tcp_cksum(register const struct ip *ip,
132 		     register const struct tcphdr *tp,
133 		     register u_int len)
134 {
135 	return (nextproto4_cksum(ip, (const u_int8_t *)tp, len,
136 	    IPPROTO_TCP));
137 }
138 
139 void
140 tcp_print(register const u_char *bp, register u_int length,
141 	  register const u_char *bp2, int fragmented)
142 {
143         register const struct tcphdr *tp;
144         register const struct ip *ip;
145         register u_char flags;
146         register u_int hlen;
147         register char ch;
148         u_int16_t sport, dport, win, urp;
149         u_int32_t seq, ack, thseq, thack;
150         u_int utoval;
151         int threv;
152 #ifdef INET6
153         register const struct ip6_hdr *ip6;
154 #endif
155 
156         tp = (struct tcphdr *)bp;
157         ip = (struct ip *)bp2;
158 #ifdef INET6
159         if (IP_V(ip) == 6)
160                 ip6 = (struct ip6_hdr *)bp2;
161         else
162                 ip6 = NULL;
163 #endif /*INET6*/
164         ch = '\0';
165         if (!TTEST(tp->th_dport)) {
166                 (void)printf("%s > %s: [|tcp]",
167                              ipaddr_string(&ip->ip_src),
168                              ipaddr_string(&ip->ip_dst));
169                 return;
170         }
171 
172         sport = EXTRACT_16BITS(&tp->th_sport);
173         dport = EXTRACT_16BITS(&tp->th_dport);
174 
175         hlen = TH_OFF(tp) * 4;
176 
177         /*
178 	 * If data present, header length valid, and NFS port used,
179 	 * assume NFS.
180 	 * Pass offset of data plus 4 bytes for RPC TCP msg length
181 	 * to NFS print routines.
182 	 */
183 	if (!qflag && hlen >= sizeof(*tp) && hlen <= length &&
184 	    (length - hlen) >= 4) {
185 		u_char *fraglenp;
186 		u_int32_t fraglen;
187 		register struct sunrpc_msg *rp;
188 		enum sunrpc_msg_type direction;
189 
190 		fraglenp = (u_char *)tp + hlen;
191 		if (TTEST2(*fraglenp, 4)) {
192 			fraglen = EXTRACT_32BITS(fraglenp) & 0x7FFFFFFF;
193 			if (fraglen > (length - hlen) - 4)
194 				fraglen = (length - hlen) - 4;
195 			rp = (struct sunrpc_msg *)(fraglenp + 4);
196 			if (TTEST(rp->rm_direction)) {
197 				direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction);
198 				if (dport == NFS_PORT &&
199 				    direction == SUNRPC_CALL) {
200 					nfsreq_print((u_char *)rp, fraglen,
201 					    (u_char *)ip);
202 					return;
203 				}
204 				if (sport == NFS_PORT &&
205 				    direction == SUNRPC_REPLY) {
206 					nfsreply_print((u_char *)rp, fraglen,
207 					    (u_char *)ip);
208 					return;
209 				}
210 			}
211                 }
212         }
213 #ifdef INET6
214         if (ip6) {
215                 if (ip6->ip6_nxt == IPPROTO_TCP) {
216                         (void)printf("%s.%s > %s.%s: ",
217                                      ip6addr_string(&ip6->ip6_src),
218                                      tcpport_string(sport),
219                                      ip6addr_string(&ip6->ip6_dst),
220                                      tcpport_string(dport));
221                 } else {
222                         (void)printf("%s > %s: ",
223                                      tcpport_string(sport), tcpport_string(dport));
224                 }
225         } else
226 #endif /*INET6*/
227         {
228                 if (ip->ip_p == IPPROTO_TCP) {
229                         (void)printf("%s.%s > %s.%s: ",
230                                      ipaddr_string(&ip->ip_src),
231                                      tcpport_string(sport),
232                                      ipaddr_string(&ip->ip_dst),
233                                      tcpport_string(dport));
234                 } else {
235                         (void)printf("%s > %s: ",
236                                      tcpport_string(sport), tcpport_string(dport));
237                 }
238         }
239 
240         if (hlen < sizeof(*tp)) {
241                 (void)printf(" tcp %d [bad hdr length %u - too short, < %lu]",
242                              length - hlen, hlen, (unsigned long)sizeof(*tp));
243                 return;
244         }
245 
246         TCHECK(*tp);
247 
248         seq = EXTRACT_32BITS(&tp->th_seq);
249         ack = EXTRACT_32BITS(&tp->th_ack);
250         win = EXTRACT_16BITS(&tp->th_win);
251         urp = EXTRACT_16BITS(&tp->th_urp);
252 
253         if (qflag) {
254                 (void)printf("tcp %d", length - hlen);
255                 if (hlen > length) {
256                         (void)printf(" [bad hdr length %u - too long, > %u]",
257                                      hlen, length);
258                 }
259                 return;
260         }
261 
262         flags = tp->th_flags;
263         printf("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags));
264 
265         if (!Sflag && (flags & TH_ACK)) {
266                 register struct tcp_seq_hash *th;
267                 const void *src, *dst;
268                 register int rev;
269                 struct tha tha;
270                 /*
271                  * Find (or record) the initial sequence numbers for
272                  * this conversation.  (we pick an arbitrary
273                  * collating order so there's only one entry for
274                  * both directions).
275                  */
276 #ifdef INET6
277                 rev = 0;
278                 if (ip6) {
279                         src = &ip6->ip6_src;
280                         dst = &ip6->ip6_dst;
281                         if (sport > dport)
282                                 rev = 1;
283                         else if (sport == dport) {
284                                 if (memcmp(src, dst, sizeof ip6->ip6_dst) > 0)
285                                         rev = 1;
286                         }
287                         if (rev) {
288                                 memcpy(&tha.src, dst, sizeof ip6->ip6_dst);
289                                 memcpy(&tha.dst, src, sizeof ip6->ip6_src);
290                                 tha.port = dport << 16 | sport;
291                         } else {
292                                 memcpy(&tha.dst, dst, sizeof ip6->ip6_dst);
293                                 memcpy(&tha.src, src, sizeof ip6->ip6_src);
294                                 tha.port = sport << 16 | dport;
295                         }
296                 } else {
297                         /*
298                          * Zero out the tha structure; the src and dst
299                          * fields are big enough to hold an IPv6
300                          * address, but we only have IPv4 addresses
301                          * and thus must clear out the remaining 124
302                          * bits.
303                          *
304                          * XXX - should we just clear those bytes after
305                          * copying the IPv4 addresses, rather than
306                          * zeroing out the entire structure and then
307                          * overwriting some of the zeroes?
308                          *
309                          * XXX - this could fail if we see TCP packets
310                          * with an IPv6 address with the lower 124 bits
311                          * all zero and also see TCP packes with an
312                          * IPv4 address with the same 32 bits as the
313                          * upper 32 bits of the IPv6 address in question.
314                          * Can that happen?  Is it likely enough to be
315                          * an issue?
316                          */
317                         memset(&tha, 0, sizeof(tha));
318                         src = &ip->ip_src;
319                         dst = &ip->ip_dst;
320                         if (sport > dport)
321                                 rev = 1;
322                         else if (sport == dport) {
323                                 if (memcmp(src, dst, sizeof ip->ip_dst) > 0)
324                                         rev = 1;
325                         }
326                         if (rev) {
327                                 memcpy(&tha.src, dst, sizeof ip->ip_dst);
328                                 memcpy(&tha.dst, src, sizeof ip->ip_src);
329                                 tha.port = dport << 16 | sport;
330                         } else {
331                                 memcpy(&tha.dst, dst, sizeof ip->ip_dst);
332                                 memcpy(&tha.src, src, sizeof ip->ip_src);
333                                 tha.port = sport << 16 | dport;
334                         }
335                 }
336 #else
337                 rev = 0;
338                 src = &ip->ip_src;
339                 dst = &ip->ip_dst;
340                 if (sport > dport)
341                         rev = 1;
342                 else if (sport == dport) {
343                         if (memcmp(src, dst, sizeof ip->ip_dst) > 0)
344                                 rev = 1;
345                 }
346                 if (rev) {
347                         memcpy(&tha.src, dst, sizeof ip->ip_dst);
348                         memcpy(&tha.dst, src, sizeof ip->ip_src);
349                         tha.port = dport << 16 | sport;
350                 } else {
351                         memcpy(&tha.dst, dst, sizeof ip->ip_dst);
352                         memcpy(&tha.src, src, sizeof ip->ip_src);
353                         tha.port = sport << 16 | dport;
354                 }
355 #endif
356 
357                 threv = rev;
358                 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
359                      th->nxt; th = th->nxt)
360                         if (memcmp((char *)&tha, (char *)&th->addr,
361                                    sizeof(th->addr)) == 0)
362                                 break;
363 
364                 if (!th->nxt || (flags & TH_SYN)) {
365                         /* didn't find it or new conversation */
366                         if (th->nxt == NULL) {
367                                 th->nxt = (struct tcp_seq_hash *)
368                                         calloc(1, sizeof(*th));
369                                 if (th->nxt == NULL)
370                                         error("tcp_print: calloc");
371                         }
372                         th->addr = tha;
373                         if (rev)
374                                 th->ack = seq, th->seq = ack - 1;
375                         else
376                                 th->seq = seq, th->ack = ack - 1;
377                 } else {
378                         if (rev)
379                                 seq -= th->ack, ack -= th->seq;
380                         else
381                                 seq -= th->seq, ack -= th->ack;
382                 }
383 
384                 thseq = th->seq;
385                 thack = th->ack;
386         } else {
387                 /*fool gcc*/
388                 thseq = thack = threv = 0;
389         }
390         if (hlen > length) {
391                 (void)printf(" [bad hdr length %u - too long, > %u]",
392                              hlen, length);
393                 return;
394         }
395 
396         if (vflag && !Kflag && !fragmented) {
397                 /* Check the checksum, if possible. */
398                 u_int16_t sum, tcp_sum;
399 
400                 if (IP_V(ip) == 4) {
401                         if (TTEST2(tp->th_sport, length)) {
402                                 sum = tcp_cksum(ip, tp, length);
403                                 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
404 
405                                 (void)printf(", cksum 0x%04x", tcp_sum);
406                                 if (sum != 0)
407                                         (void)printf(" (incorrect -> 0x%04x)",
408                                             in_cksum_shouldbe(tcp_sum, sum));
409                                 else
410                                         (void)printf(" (correct)");
411                         }
412                 }
413 #ifdef INET6
414                 else if (IP_V(ip) == 6 && ip6->ip6_plen) {
415                         if (TTEST2(tp->th_sport, length)) {
416                                 sum = nextproto6_cksum(ip6, (const u_int8_t *)tp, length, IPPROTO_TCP);
417                                 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
418 
419                                 (void)printf(", cksum 0x%04x", tcp_sum);
420                                 if (sum != 0)
421                                         (void)printf(" (incorrect -> 0x%04x)",
422                                             in_cksum_shouldbe(tcp_sum, sum));
423                                 else
424                                         (void)printf(" (correct)");
425 
426                         }
427                 }
428 #endif
429         }
430 
431         length -= hlen;
432         if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
433                 (void)printf(", seq %u", seq);
434 
435                 if (length > 0) {
436                         (void)printf(":%u", seq + length);
437                 }
438         }
439 
440         if (flags & TH_ACK) {
441                 (void)printf(", ack %u", ack);
442         }
443 
444         (void)printf(", win %d", win);
445 
446         if (flags & TH_URG)
447                 (void)printf(", urg %d", urp);
448         /*
449          * Handle any options.
450          */
451         if (hlen > sizeof(*tp)) {
452                 register const u_char *cp;
453                 register u_int i, opt, datalen;
454                 register u_int len;
455 
456                 hlen -= sizeof(*tp);
457                 cp = (const u_char *)tp + sizeof(*tp);
458                 printf(", options [");
459                 while (hlen > 0) {
460                         if (ch != '\0')
461                                 putchar(ch);
462                         TCHECK(*cp);
463                         opt = *cp++;
464                         if (ZEROLENOPT(opt))
465                                 len = 1;
466                         else {
467                                 TCHECK(*cp);
468                                 len = *cp++;	/* total including type, len */
469                                 if (len < 2 || len > hlen)
470                                         goto bad;
471                                 --hlen;		/* account for length byte */
472                         }
473                         --hlen;			/* account for type byte */
474                         datalen = 0;
475 
476 /* Bail if "l" bytes of data are not left or were not captured  */
477 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
478 
479 
480                         printf("%s", tok2str(tcp_option_values, "Unknown Option %u", opt));
481 
482                         switch (opt) {
483 
484                         case TCPOPT_MAXSEG:
485                                 datalen = 2;
486                                 LENCHECK(datalen);
487                                 (void)printf(" %u", EXTRACT_16BITS(cp));
488                                 break;
489 
490                         case TCPOPT_WSCALE:
491                                 datalen = 1;
492                                 LENCHECK(datalen);
493                                 (void)printf(" %u", *cp);
494                                 break;
495 
496                         case TCPOPT_SACK:
497                                 datalen = len - 2;
498                                 if (datalen % 8 != 0) {
499                                         (void)printf("malformed sack");
500                                 } else {
501                                         u_int32_t s, e;
502 
503                                         (void)printf(" %d ", datalen / 8);
504                                         for (i = 0; i < datalen; i += 8) {
505                                                 LENCHECK(i + 4);
506                                                 s = EXTRACT_32BITS(cp + i);
507                                                 LENCHECK(i + 8);
508                                                 e = EXTRACT_32BITS(cp + i + 4);
509                                                 if (threv) {
510                                                         s -= thseq;
511                                                         e -= thseq;
512                                                 } else {
513                                                         s -= thack;
514                                                         e -= thack;
515                                                 }
516                                                 (void)printf("{%u:%u}", s, e);
517                                         }
518                                 }
519                                 break;
520 
521                         case TCPOPT_CC:
522                         case TCPOPT_CCNEW:
523                         case TCPOPT_CCECHO:
524                         case TCPOPT_ECHO:
525                         case TCPOPT_ECHOREPLY:
526 
527                                 /*
528                                  * those options share their semantics.
529                                  * fall through
530                                  */
531                                 datalen = 4;
532                                 LENCHECK(datalen);
533                                 (void)printf(" %u", EXTRACT_32BITS(cp));
534                                 break;
535 
536                         case TCPOPT_TIMESTAMP:
537                                 datalen = 8;
538                                 LENCHECK(datalen);
539                                 (void)printf(" val %u ecr %u",
540                                              EXTRACT_32BITS(cp),
541                                              EXTRACT_32BITS(cp + 4));
542                                 break;
543 
544                         case TCPOPT_SIGNATURE:
545                                 datalen = TCP_SIGLEN;
546                                 LENCHECK(datalen);
547 #ifdef HAVE_LIBCRYPTO
548                                 switch (tcp_verify_signature(ip, tp,
549                                                              bp + TH_OFF(tp) * 4, length, cp)) {
550 
551                                 case SIGNATURE_VALID:
552                                         (void)printf("valid");
553                                         break;
554 
555                                 case SIGNATURE_INVALID:
556                                         (void)printf("invalid");
557                                         break;
558 
559                                 case CANT_CHECK_SIGNATURE:
560                                         (void)printf("can't check - ");
561                                         for (i = 0; i < TCP_SIGLEN; ++i)
562                                                 (void)printf("%02x", cp[i]);
563                                         break;
564                                 }
565 #else
566                                 for (i = 0; i < TCP_SIGLEN; ++i)
567                                         (void)printf("%02x", cp[i]);
568 #endif
569                                 break;
570 
571                         case TCPOPT_AUTH:
572                                 (void)printf("keyid %d", *cp++);
573                                 datalen = len - 3;
574                                 for (i = 0; i < datalen; ++i) {
575                                         LENCHECK(i);
576                                         (void)printf("%02x", cp[i]);
577                                 }
578                                 break;
579 
580 
581                         case TCPOPT_EOL:
582                         case TCPOPT_NOP:
583                         case TCPOPT_SACKOK:
584                                 /*
585                                  * Nothing interesting.
586                                  * fall through
587                                  */
588                                 break;
589 
590                         case TCPOPT_UTO:
591                                 datalen = 2;
592                                 LENCHECK(datalen);
593                                 utoval = EXTRACT_16BITS(cp);
594                                 (void)printf("0x%x", utoval);
595                                 if (utoval & 0x0001)
596                                         utoval = (utoval >> 1) * 60;
597                                 else
598                                         utoval >>= 1;
599                                 (void)printf(" %u", utoval);
600                                 break;
601 
602                         default:
603                                 datalen = len - 2;
604                                 for (i = 0; i < datalen; ++i) {
605                                         LENCHECK(i);
606                                         (void)printf("%02x", cp[i]);
607                                 }
608                                 break;
609                         }
610 
611                         /* Account for data printed */
612                         cp += datalen;
613                         hlen -= datalen;
614 
615                         /* Check specification against observed length */
616                         ++datalen;			/* option octet */
617                         if (!ZEROLENOPT(opt))
618                                 ++datalen;		/* size octet */
619                         if (datalen != len)
620                                 (void)printf("[len %d]", len);
621                         ch = ',';
622                         if (opt == TCPOPT_EOL)
623                                 break;
624                 }
625                 putchar(']');
626         }
627 
628         /*
629          * Print length field before crawling down the stack.
630          */
631         printf(", length %u", length);
632 
633         if (length <= 0)
634                 return;
635 
636         /*
637          * Decode payload if necessary.
638          */
639         bp += TH_OFF(tp) * 4;
640         if ((flags & TH_RST) && vflag) {
641                 print_tcp_rst_data(bp, length);
642                 return;
643         }
644 
645         if (sport == TELNET_PORT || dport == TELNET_PORT) {
646                 if (!qflag && vflag)
647                         telnet_print(bp, length);
648         } else if (sport == BGP_PORT || dport == BGP_PORT)
649                 bgp_print(bp, length);
650         else if (sport == PPTP_PORT || dport == PPTP_PORT)
651                 pptp_print(bp);
652 #ifdef TCPDUMP_DO_SMB
653         else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
654                 nbt_tcp_print(bp, length);
655 	else if (sport == SMB_PORT || dport == SMB_PORT)
656 		smb_tcp_print(bp, length);
657 #endif
658         else if (sport == BEEP_PORT || dport == BEEP_PORT)
659                 beep_print(bp, length);
660         else if (length > 2 &&
661                  (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT ||
662                   sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) {
663                 /*
664                  * TCP DNS query has 2byte length at the head.
665                  * XXX packet could be unaligned, it can go strange
666                  */
667                 ns_print(bp + 2, length - 2, 0);
668         } else if (sport == MSDP_PORT || dport == MSDP_PORT) {
669                 msdp_print(bp, length);
670         } else if (sport == RPKI_RTR_PORT || dport == RPKI_RTR_PORT) {
671                 rpki_rtr_print(bp, length);
672         }
673         else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) {
674                 ldp_print(bp, length);
675         }
676 
677         return;
678  bad:
679         fputs("[bad opt]", stdout);
680         if (ch != '\0')
681                 putchar('>');
682         return;
683  trunc:
684         fputs("[|tcp]", stdout);
685         if (ch != '\0')
686                 putchar('>');
687 }
688 
689 /*
690  * RFC1122 says the following on data in RST segments:
691  *
692  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
693  *
694  *            A TCP SHOULD allow a received RST segment to include data.
695  *
696  *            DISCUSSION
697  *                 It has been suggested that a RST segment could contain
698  *                 ASCII text that encoded and explained the cause of the
699  *                 RST.  No standard has yet been established for such
700  *                 data.
701  *
702  */
703 
704 static void
705 print_tcp_rst_data(register const u_char *sp, u_int length)
706 {
707         int c;
708 
709         if (TTEST2(*sp, length))
710                 printf(" [RST");
711         else
712                 printf(" [!RST");
713         if (length > MAX_RST_DATA_LEN) {
714                 length = MAX_RST_DATA_LEN;	/* can use -X for longer */
715                 putchar('+');			/* indicate we truncate */
716         }
717         putchar(' ');
718         while (length-- && sp <= snapend) {
719                 c = *sp++;
720                 safeputchar(c);
721         }
722         putchar(']');
723 }
724 
725 #ifdef HAVE_LIBCRYPTO
726 static int
727 tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
728                      const u_char *data, int length, const u_char *rcvsig)
729 {
730         struct tcphdr tp1;
731         u_char sig[TCP_SIGLEN];
732         char zero_proto = 0;
733         MD5_CTX ctx;
734         u_int16_t savecsum, tlen;
735 #ifdef INET6
736         struct ip6_hdr *ip6;
737         u_int32_t len32;
738         u_int8_t nxt;
739 #endif
740 
741 	if (data + length > snapend) {
742 		printf("snaplen too short, ");
743 		return (CANT_CHECK_SIGNATURE);
744 	}
745 
746         tp1 = *tp;
747 
748         if (sigsecret == NULL) {
749 		printf("shared secret not supplied with -M, ");
750                 return (CANT_CHECK_SIGNATURE);
751         }
752 
753         MD5_Init(&ctx);
754         /*
755          * Step 1: Update MD5 hash with IP pseudo-header.
756          */
757         if (IP_V(ip) == 4) {
758                 MD5_Update(&ctx, (char *)&ip->ip_src, sizeof(ip->ip_src));
759                 MD5_Update(&ctx, (char *)&ip->ip_dst, sizeof(ip->ip_dst));
760                 MD5_Update(&ctx, (char *)&zero_proto, sizeof(zero_proto));
761                 MD5_Update(&ctx, (char *)&ip->ip_p, sizeof(ip->ip_p));
762                 tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4;
763                 tlen = htons(tlen);
764                 MD5_Update(&ctx, (char *)&tlen, sizeof(tlen));
765 #ifdef INET6
766         } else if (IP_V(ip) == 6) {
767                 ip6 = (struct ip6_hdr *)ip;
768                 MD5_Update(&ctx, (char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
769                 MD5_Update(&ctx, (char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
770                 len32 = htonl(EXTRACT_16BITS(&ip6->ip6_plen));
771                 MD5_Update(&ctx, (char *)&len32, sizeof(len32));
772                 nxt = 0;
773                 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
774                 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
775                 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
776                 nxt = IPPROTO_TCP;
777                 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
778 #endif
779         } else {
780 #ifdef INET6
781 		printf("IP version not 4 or 6, ");
782 #else
783 		printf("IP version not 4, ");
784 #endif
785                 return (CANT_CHECK_SIGNATURE);
786         }
787 
788         /*
789          * Step 2: Update MD5 hash with TCP header, excluding options.
790          * The TCP checksum must be set to zero.
791          */
792         savecsum = tp1.th_sum;
793         tp1.th_sum = 0;
794         MD5_Update(&ctx, (char *)&tp1, sizeof(struct tcphdr));
795         tp1.th_sum = savecsum;
796         /*
797          * Step 3: Update MD5 hash with TCP segment data, if present.
798          */
799         if (length > 0)
800                 MD5_Update(&ctx, data, length);
801         /*
802          * Step 4: Update MD5 hash with shared secret.
803          */
804         MD5_Update(&ctx, sigsecret, strlen(sigsecret));
805         MD5_Final(sig, &ctx);
806 
807         if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
808                 return (SIGNATURE_VALID);
809         else
810                 return (SIGNATURE_INVALID);
811 }
812 #endif /* HAVE_LIBCRYPTO */
813 
814 /*
815  * Local Variables:
816  * c-style: whitesmith
817  * c-basic-offset: 8
818  * End:
819  */
820