]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-tcp.c
Add changes in 4.2.1.
[tcpdump] / print-tcp.c
index a4ddfeb29131532d87e0eb223a1cf91ad8127ae9..88b461576df9a2cfe8d12d74ca87f91faff141cd 100644 (file)
@@ -25,8 +25,8 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-"@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.130 2007-08-29 02:31:44 mcr Exp $ (LBL)";
-  #else
+"@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.135 2008-11-09 23:35:03 mcr Exp $ (LBL)";
+#else
 __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
 #endif
 
@@ -58,10 +58,7 @@ __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
 
 #ifdef HAVE_LIBCRYPTO
 #include <openssl/md5.h>
-
-#define SIGNATURE_VALID                0
-#define SIGNATURE_INVALID      1
-#define CANT_CHECK_SIGNATURE   2
+#include <signature.h>
 
 static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
                                 const u_char *data, int length, const u_char *rcvsig);
@@ -124,6 +121,7 @@ struct tok tcp_option_values[] = {
         { TCPOPT_CCECHO, "" },
         { TCPOPT_SIGNATURE, "md5" },
         { TCPOPT_AUTH, "enhanced auth" },
+        { TCPOPT_UTO, "uto" },
         { 0, NULL }
 };
 
@@ -131,64 +129,10 @@ static int tcp_cksum(register const struct ip *ip,
                     register const struct tcphdr *tp,
                     register u_int len)
 {
-        union phu {
-                struct phdr {
-                        u_int32_t src;
-                        u_int32_t dst;
-                        u_char mbz;
-                        u_char proto;
-                        u_int16_t len;
-                } ph;
-                u_int16_t pa[6];
-        } phu;
-        const u_int16_t *sp;
-
-        /* pseudo-header.. */
-        phu.ph.len = htons((u_int16_t)len);
-        phu.ph.mbz = 0;
-        phu.ph.proto = IPPROTO_TCP;
-        memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
-        if (IP_HL(ip) == 5)
-                memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
-        else
-                phu.ph.dst = ip_finddst(ip);
-
-        sp = &phu.pa[0];
-        return in_cksum((u_short *)tp, len,
-                        sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
+       return (nextproto4_cksum(ip, (const u_int8_t *)tp, len,
+           IPPROTO_TCP));
 }
 
-#ifdef INET6
-static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp,
-                      u_int len)
-{
-        size_t i;
-        u_int32_t sum = 0;
-        union {
-                struct {
-                        struct in6_addr ph_src;
-                        struct in6_addr ph_dst;
-                        u_int32_t      ph_len;
-                        u_int8_t       ph_zero[3];
-                        u_int8_t       ph_nxt;
-                } ph;
-                u_int16_t pa[20];
-        } phu;
-
-        /* pseudo-header */
-        memset(&phu, 0, sizeof(phu));
-        phu.ph.ph_src = ip6->ip6_src;
-        phu.ph.ph_dst = ip6->ip6_dst;
-        phu.ph.ph_len = htonl(len);
-        phu.ph.ph_nxt = IPPROTO_TCP;
-
-        for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
-                sum += phu.pa[i];
-
-        return in_cksum((u_short *)tp, len, sum);
-}
-#endif
-
 void
 tcp_print(register const u_char *bp, register u_int length,
          register const u_char *bp2, int fragmented)
@@ -200,6 +144,7 @@ tcp_print(register const u_char *bp, register u_int length,
         register char ch;
         u_int16_t sport, dport, win, urp;
         u_int32_t seq, ack, thseq, thack;
+        u_int utoval;
         int threv;
 #ifdef INET6
         register const struct ip6_hdr *ip6;
@@ -227,23 +172,39 @@ tcp_print(register const u_char *bp, register u_int length,
         hlen = TH_OFF(tp) * 4;
 
         /*
-         * If data present, header length valid, and NFS port used,
-         * assume NFS.
-         * Pass offset of data plus 4 bytes for RPC TCP msg length
-         * to NFS print routines.
-         */
-        if (!qflag && hlen >= sizeof(*tp) && hlen <= length) {
-                if ((u_char *)tp + 4 + sizeof(struct sunrpc_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 sunrpc_msg)
-                           <= snapend &&
-                           sport == NFS_PORT) {
-                        nfsreply_print((u_char *)tp + hlen + 4, length - hlen,
-                                       (u_char *)ip);
-                        return;
+        * If data present, header length valid, and NFS port used,
+        * assume NFS.
+        * Pass offset of data plus 4 bytes for RPC TCP msg length
+        * to NFS print routines.
+        */
+       if (!qflag && hlen >= sizeof(*tp) && hlen <= length &&
+           (length - hlen) >= 4) {
+               u_char *fraglenp;
+               u_int32_t fraglen;
+               register struct sunrpc_msg *rp;
+               enum sunrpc_msg_type direction;
+
+               fraglenp = (u_char *)tp + hlen;
+               if (TTEST2(*fraglenp, 4)) {
+                       fraglen = EXTRACT_32BITS(fraglenp) & 0x7FFFFFFF;
+                       if (fraglen > (length - hlen) - 4)
+                               fraglen = (length - hlen) - 4;
+                       rp = (struct sunrpc_msg *)(fraglenp + 4);
+                       if (TTEST(rp->rm_direction)) {
+                               direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction);
+                               if (dport == NFS_PORT &&
+                                   direction == SUNRPC_CALL) {
+                                       nfsreq_print((u_char *)rp, fraglen,
+                                           (u_char *)ip);
+                                       return;
+                               }
+                               if (sport == NFS_PORT &&
+                                   direction == SUNRPC_REPLY) {
+                                       nfsreply_print((u_char *)rp, fraglen,
+                                           (u_char *)ip);
+                                       return;
+                               }
+                       }
                 }
         }
 #ifdef INET6
@@ -310,7 +271,6 @@ tcp_print(register const u_char *bp, register u_int length,
                  * both directions).
                  */
 #ifdef INET6
-                memset(&tha, 0, sizeof(tha));
                 rev = 0;
                 if (ip6) {
                         src = &ip6->ip6_src;
@@ -331,6 +291,27 @@ tcp_print(register const u_char *bp, register u_int length,
                                 tha.port = sport << 16 | dport;
                         }
                 } else {
+                        /*
+                         * Zero out the tha structure; the src and dst
+                         * fields are big enough to hold an IPv6
+                         * address, but we only have IPv4 addresses
+                         * and thus must clear out the remaining 124
+                         * bits.
+                         *
+                         * XXX - should we just clear those bytes after
+                         * copying the IPv4 addresses, rather than
+                         * zeroing out the entire structure and then
+                         * overwriting some of the zeroes?
+                         *
+                         * XXX - this could fail if we see TCP packets
+                         * with an IPv6 address with the lower 124 bits
+                         * all zero and also see TCP packes with an
+                         * IPv4 address with the same 32 bits as the
+                         * upper 32 bits of the IPv6 address in question.
+                         * Can that happen?  Is it likely enough to be
+                         * an issue?
+                         */
+                        memset(&tha, 0, sizeof(tha));
                         src = &ip->ip_src;
                         dst = &ip->ip_dst;
                         if (sport > dport)
@@ -409,37 +390,43 @@ tcp_print(register const u_char *bp, register u_int length,
                 return;
         }
 
-        if (IP_V(ip) == 4 && vflag && !Kflag && !fragmented) {
+        if (vflag && !Kflag && !fragmented) {
+                /* Check the checksum, if possible. */
                 u_int16_t sum, tcp_sum;
-                if (TTEST2(tp->th_sport, length)) {
-                        sum = tcp_cksum(ip, tp, length);
 
-                        (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum));
-                        if (sum != 0) {
+                if (IP_V(ip) == 4) {
+                        if (TTEST2(tp->th_sport, length)) {
+                                sum = tcp_cksum(ip, tp, length);
                                 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
-                                (void)printf(" (incorrect -> 0x%04x)",in_cksum_shouldbe(tcp_sum, sum));
-                        } else
-                                (void)printf(" (correct)");
+
+                                (void)printf(", cksum 0x%04x", tcp_sum);
+                                if (sum != 0)
+                                        (void)printf(" (incorrect -> 0x%04x)",
+                                            in_cksum_shouldbe(tcp_sum, sum));
+                                else
+                                        (void)printf(" (correct)");
+                        }
                 }
-        }
 #ifdef INET6
-        if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !Kflag && !fragmented) {
-                u_int16_t sum,tcp_sum;
-                if (TTEST2(tp->th_sport, length)) {
-                        sum = tcp6_cksum(ip6, tp, length);
-                        (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum));
-                        if (sum != 0) {
+                else if (IP_V(ip) == 6 && ip6->ip6_plen) {
+                        if (TTEST2(tp->th_sport, length)) {
+                                sum = nextproto6_cksum(ip6, (const u_int8_t *)tp, length, IPPROTO_TCP);
                                 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
-                                (void)printf(" (incorrect (-> 0x%04x)",in_cksum_shouldbe(tcp_sum, sum));
-                        } else
-                                (void)printf(" (correct)");
 
+                                (void)printf(", cksum 0x%04x", tcp_sum);
+                                if (sum != 0)
+                                        (void)printf(" (incorrect -> 0x%04x)",
+                                            in_cksum_shouldbe(tcp_sum, sum));
+                                else
+                                        (void)printf(" (correct)");
+
+                        }
                 }
-        }
 #endif
+        }
 
         length -= hlen;
-        if (vflag > 1 || flags & (TH_SYN | TH_FIN | TH_RST)) {
+        if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
                 (void)printf(", seq %u", seq);
 
                 if (length > 0) {
@@ -597,6 +584,18 @@ tcp_print(register const u_char *bp, register u_int length,
                                  */
                                 break;
 
+                        case TCPOPT_UTO:
+                                datalen = 2;
+                                LENCHECK(datalen);
+                                utoval = EXTRACT_16BITS(cp);
+                                (void)printf("0x%x", utoval);
+                                if (utoval & 0x0001)
+                                        utoval = (utoval >> 1) * 60;
+                                else
+                                        utoval >>= 1;
+                                (void)printf(" %u", utoval);
+                                break;
+
                         default:
                                 datalen = len - 2;
                                 for (i = 0; i < datalen; ++i) {
@@ -650,6 +649,8 @@ tcp_print(register const u_char *bp, register u_int length,
 #ifdef TCPDUMP_DO_SMB
         else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
                 nbt_tcp_print(bp, length);
+       else if (sport == SMB_PORT || dport == SMB_PORT)
+               smb_tcp_print(bp, length);
 #endif
         else if (sport == BEEP_PORT || dport == BEEP_PORT)
                 beep_print(bp, length);
@@ -663,6 +664,8 @@ tcp_print(register const u_char *bp, register u_int length,
                 ns_print(bp + 2, length - 2, 0);
         } else if (sport == MSDP_PORT || dport == MSDP_PORT) {
                 msdp_print(bp, length);
+        } else if (sport == RPKI_RTR_PORT || dport == RPKI_RTR_PORT) {
+                rpki_rtr_print(bp, length);
         }
         else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) {
                 ldp_print(bp, length);
@@ -732,10 +735,17 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
         u_int8_t nxt;
 #endif
 
+       if (data + length > snapend) {
+               printf("snaplen too short, ");
+               return (CANT_CHECK_SIGNATURE);
+       }
+
         tp1 = *tp;
 
-        if (tcpmd5secret == NULL)
+        if (sigsecret == NULL) {
+               printf("shared secret not supplied with -M, ");
                 return (CANT_CHECK_SIGNATURE);
+        }
 
         MD5_Init(&ctx);
         /*
@@ -754,7 +764,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
                 ip6 = (struct ip6_hdr *)ip;
                 MD5_Update(&ctx, (char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
                 MD5_Update(&ctx, (char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
-                len32 = htonl(ntohs(ip6->ip6_plen));
+                len32 = htonl(EXTRACT_16BITS(&ip6->ip6_plen));
                 MD5_Update(&ctx, (char *)&len32, sizeof(len32));
                 nxt = 0;
                 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
@@ -763,8 +773,14 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
                 nxt = IPPROTO_TCP;
                 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
 #endif
-        } else
+        } else {
+#ifdef INET6
+               printf("IP version not 4 or 6, ");
+#else
+               printf("IP version not 4, ");
+#endif
                 return (CANT_CHECK_SIGNATURE);
+        }
 
         /*
          * Step 2: Update MD5 hash with TCP header, excluding options.
@@ -782,7 +798,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
         /*
          * Step 4: Update MD5 hash with shared secret.
          */
-        MD5_Update(&ctx, tcpmd5secret, strlen(tcpmd5secret));
+        MD5_Update(&ctx, sigsecret, strlen(sigsecret));
         MD5_Final(sig, &ctx);
 
         if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)