]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-tcp.c
bpf_dump.c moved to libpcap
[tcpdump] / print-tcp.c
index f841a63714f4dea05e9d79cdd0c6b191e5d5a898..fe8f5eabce82a0f788eee4d3a97be2e56242b6fc 100644 (file)
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.55 1999-10-07 23:47:12 mcr Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.66 2000-06-01 01:09:32 assar Exp $ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #include <sys/param.h>
 #include <sys/time.h>
 
+#include <rpc/rpc.h>
+
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
 #include <netinet/tcp.h>
-#include <netinet/tcpip.h>
 
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
@@ -42,6 +47,10 @@ static const char rcsid[] =
 #include <string.h>
 #include <unistd.h>
 
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+
 #include "interface.h"
 #include "addrtoname.h"
 #include "extract.h"
@@ -75,9 +84,25 @@ static const char rcsid[] =
 #define TCPOPT_CCECHO          13      /* T/TCP CC options (rfc1644) */
 #endif
 
+/*
+ * Definitions required for ECN
+ * for use if the OS running tcpdump does not have ECN
+ */
+#ifndef TH_ECNECHO
+#define TH_ECNECHO             0x40    /* ECN Echo in tcp header */
+#endif
+#ifndef TH_CWR
+#define TH_CWR                 0x80    /* ECN Cwnd Reduced in tcp header*/
+#endif
+
 struct tha {
+#ifndef INET6
        struct in_addr src;
        struct in_addr dst;
+#else
+       struct in6_addr src;
+       struct in6_addr dst;
+#endif /*INET6*/
        u_int port;
 };
 
@@ -96,6 +121,17 @@ struct tcp_seq_hash {
 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
 
 
+#ifndef TELNET_PORT
+#define TELNET_PORT    23
+#endif
+#ifndef BGP_PORT
+#define BGP_PORT       179
+#endif
+#define NETBIOS_SSN_PORT 139
+#ifndef NFS_PORT
+#define NFS_PORT       2049
+#endif
+
 void
 tcp_print(register const u_char *bp, register u_int length,
          register const u_char *bp2)
@@ -105,34 +141,94 @@ tcp_print(register const u_char *bp, register u_int length,
        register u_char flags;
        register int hlen;
        register char ch;
-       u_short sport, dport, win, urp;
-       u_int32_t seq, ack;
+       u_int16_t sport, dport, win, urp;
+       u_int32_t seq, ack, thseq, thack;
+       int threv;
+#ifdef INET6
+       register const struct ip6_hdr *ip6;
+#endif
 
        tp = (struct tcphdr *)bp;
        ip = (struct ip *)bp2;
+#ifdef INET6
+       if (ip->ip_v == 6)
+               ip6 = (struct ip6_hdr *)bp2;
+       else
+               ip6 = NULL;
+#endif /*INET6*/
        ch = '\0';
-       TCHECK(*tp);
-       if (length < sizeof(*tp)) {
-               (void)printf("truncated-tcp %d", length);
+       if (!TTEST(tp->th_dport)) {
+               (void)printf("%s > %s: [|tcp]",
+                       ipaddr_string(&ip->ip_src),
+                       ipaddr_string(&ip->ip_dst));
                return;
        }
 
        sport = ntohs(tp->th_sport);
        dport = ntohs(tp->th_dport);
-       seq = ntohl(tp->th_seq);
-       ack = ntohl(tp->th_ack);
+
+
+       hlen = tp->th_off * 4;
+
+       /*
+        * If data present and NFS port used, assume NFS.
+        * Pass offset of data plus 4 bytes for RPC TCP msg length
+        * to NFS print routines.
+        */
+       if (!qflag) {
+               if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend &&
+                   dport == NFS_PORT) {
+                       nfsreq_print((u_char *)tp + hlen + 4, length-hlen,
+                                    (u_char *)ip);
+                       return;
+               } else if ((u_char *)tp + 4 + sizeof(struct rpc_msg)
+                          <= snapend &&
+                          sport == NFS_PORT) {
+                       nfsreply_print((u_char *)tp + hlen + 4,length-hlen,
+                                      (u_char *)ip);
+                       return;
+               }
+       }
+#ifdef INET6
+       if (ip6) {
+               if (ip6->ip6_nxt == IPPROTO_TCP) {
+                       (void)printf("%s.%s > %s.%s: ",
+                               ip6addr_string(&ip6->ip6_src),
+                               tcpport_string(sport),
+                               ip6addr_string(&ip6->ip6_dst),
+                               tcpport_string(dport));
+               } else {
+                       (void)printf("%s > %s: ",
+                               tcpport_string(sport), tcpport_string(dport));
+               }
+       } else
+#endif /*INET6*/
+       {
+               if (ip->ip_p == IPPROTO_TCP) {
+                       (void)printf("%s.%s > %s.%s: ",
+                               ipaddr_string(&ip->ip_src),
+                               tcpport_string(sport),
+                               ipaddr_string(&ip->ip_dst),
+                               tcpport_string(dport));
+               } else {
+                       (void)printf("%s > %s: ",
+                               tcpport_string(sport), tcpport_string(dport));
+               }
+       }
+
+       TCHECK(*tp);
+
+       seq = (u_int32_t)ntohl(tp->th_seq);
+       ack = (u_int32_t)ntohl(tp->th_ack);
        win = ntohs(tp->th_win);
        urp = ntohs(tp->th_urp);
 
-       (void)printf("%s.%s > %s.%s: ",
-               ipaddr_string(&ip->ip_src), tcpport_string(sport),
-               ipaddr_string(&ip->ip_dst), tcpport_string(dport));
-
        if (qflag) {
                (void)printf("tcp %d", length - tp->th_off * 4);
                return;
        }
-       if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
+       if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
+                                     TH_ECNECHO|TH_CWR)) {
                if (flags & TH_SYN)
                        putchar('S');
                if (flags & TH_FIN)
@@ -141,6 +237,10 @@ tcp_print(register const u_char *bp, register u_int length,
                        putchar('R');
                if (flags & TH_PUSH)
                        putchar('P');
+               if (flags & TH_CWR)
+                       putchar('W');   /* congestion _W_indow reduced (ECN) */
+               if (flags & TH_ECNECHO)
+                       putchar('E');   /* ecn _E_cho sent (ECN) */
        } else
                putchar('.');
 
@@ -154,6 +254,49 @@ tcp_print(register const u_char *bp, register u_int length,
                 * collating order so there's only one entry for
                 * both directions).
                 */
+#ifdef INET6
+               bzero(&tha, sizeof(tha));
+               rev = 0;
+               if (ip6) {
+                       if (sport > dport) {
+                               rev = 1;
+                       } else if (sport == dport) {
+                           int i;
+
+                           for (i = 0; i < 4; i++) {
+                               if (((u_int32_t *)(&ip6->ip6_src))[i] >
+                                   ((u_int32_t *)(&ip6->ip6_dst))[i]) {
+                                       rev = 1;
+                                       break;
+                               }
+                           }
+                       }
+                       if (rev) {
+                               tha.src = ip6->ip6_dst;
+                               tha.dst = ip6->ip6_src;
+                               tha.port = dport << 16 | sport;
+                       } else {
+                               tha.dst = ip6->ip6_dst;
+                               tha.src = ip6->ip6_src;
+                               tha.port = sport << 16 | dport;
+                       }
+               } else {
+                       if (sport > dport ||
+                           (sport == dport &&
+                            ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
+                               rev = 1;
+                       }
+                       if (rev) {
+                               *(struct in_addr *)&tha.src = ip->ip_dst;
+                               *(struct in_addr *)&tha.dst = ip->ip_src;
+                               tha.port = dport << 16 | sport;
+                       } else {
+                               *(struct in_addr *)&tha.dst = ip->ip_dst;
+                               *(struct in_addr *)&tha.src = ip->ip_src;
+                               tha.port = sport << 16 | dport;
+                       }
+               }
+#else
                if (sport < dport ||
                    (sport == dport &&
                     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
@@ -165,14 +308,16 @@ tcp_print(register const u_char *bp, register u_int length,
                        tha.port = dport << 16 | sport;
                        rev = 1;
                }
+#endif
 
+               threv = rev;
                for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
                     th->nxt; th = th->nxt)
                        if (!memcmp((char *)&tha, (char *)&th->addr,
                                  sizeof(th->addr)))
                                break;
 
-               if (!th->nxt || flags & TH_SYN) {
+               if (!th->nxt || (flags & TH_SYN)) {
                        /* didn't find it or new conversation */
                        if (th->nxt == NULL) {
                                th->nxt = (struct tcp_seq_hash *)
@@ -185,20 +330,26 @@ tcp_print(register const u_char *bp, register u_int length,
                                th->ack = seq, th->seq = ack - 1;
                        else
                                th->seq = seq, th->ack = ack - 1;
+
                } else {
                        if (rev)
                                seq -= th->ack, ack -= th->seq;
                        else
                                seq -= th->seq, ack -= th->ack;
                }
+
+               thseq = th->seq;
+               thack = th->ack;
+       } else {
+               /*fool gcc*/
+               thseq = thack = threv = 0;
        }
-       hlen = tp->th_off * 4;
        if (hlen > length) {
                (void)printf(" [bad hdr length]");
                return;
        }
        length -= hlen;
-       if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
+       if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
                (void)printf(" %u:%u(%d)", seq, seq + length, length);
        if (flags & TH_ACK)
                (void)printf(" ack %u", ack);
@@ -268,15 +419,28 @@ tcp_print(register const u_char *bp, register u_int length,
                        case TCPOPT_SACK:
                                (void)printf("sack");
                                datalen = len - 2;
-                               for (i = 0; i < datalen; i += 4) {
-                                       LENCHECK(i + 4);
-                                       /* block-size@relative-origin */
-                                       (void)printf(" %u@%u",
-                                           EXTRACT_16BITS(cp + i + 2),
-                                           EXTRACT_16BITS(cp + i));
+                               if (datalen % 8 != 0) {
+                                       (void)printf(" malformed sack ");
+                               } else {
+                                       u_int32_t s, e;
+
+                                       (void)printf(" sack %d ", datalen / 8);
+                                       for (i = 0; i < datalen; i += 8) {
+                                               LENCHECK(i + 4);
+                                               s = EXTRACT_32BITS(cp + i);
+                                               LENCHECK(i + 8);
+                                               e = EXTRACT_32BITS(cp + i + 4);
+                                               if (threv) {
+                                                       s -= thseq;
+                                                       e -= thseq;
+                                               } else {
+                                                       s -= thack;
+                                                       e -= thack;
+                                               }
+                                               (void)printf("{%u:%u}", s, e);
+                                       }
+                                       (void)printf(" ");
                                }
-                               if (datalen % 4)
-                                       (void)printf("[len %d]", len);
                                break;
 
                        case TCPOPT_ECHO:
@@ -349,6 +513,21 @@ tcp_print(register const u_char *bp, register u_int length,
                }
                putchar('>');
        }
+
+       if (length <= 0)
+               return;
+
+       /*
+        * Decode payload if necessary.
+        */
+       bp += (tp->th_off * 4);
+       if (!qflag && vflag && length > 0
+        && (sport == TELNET_PORT || dport == TELNET_PORT))
+               telnet_print(bp, length);
+       else if (sport == BGP_PORT || dport == BGP_PORT)
+               bgp_print(bp, length);
+       else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
+               nbt_tcp_print(bp, length);
        return;
 bad:
        fputs("[bad opt]", stdout);