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