]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-tcp.c
Fix the pointer tests in the non-ndoified TTEST2() macro as well.
[tcpdump] / print-tcp.c
index 86195a856086405f0ae1c78da8f3f3f7c76e41e7..5b1133a6c30a451d0f944cae8f2b9a7aaea72d02 100644 (file)
@@ -1,7 +1,11 @@
+/*     $NetBSD: print-tcp.c,v 1.9 2007/07/26 18:15:12 plunky Exp $     */
+
 /*
  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
  *     The Regents of the University of California.  All rights reserved.
  *
+ * Copyright (c) 1999-2004 The tcpdump.org project
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that: (1) source code distributions
  * retain the above copyright notice and this paragraph in its entirety, (2)
  */
 
 #ifndef lint
-static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.112 2004-04-05 00:12:54 mcr Exp $ (LBL)";
+#else
+__RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
 #endif
 
+#define NETDISSECT_REWORKED
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include <tcpdump-stdinc.h>
 
-#include <rpc/rpc.h>
-
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -47,622 +49,705 @@ static const char rcsid[] _U_ =
 #include "ip6.h"
 #endif
 #include "ipproto.h"
+#include "rpc_auth.h"
+#include "rpc_msg.h"
 
 #include "nameser.h"
 
 #ifdef HAVE_LIBCRYPTO
 #include <openssl/md5.h>
+#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);
+static int tcp_verify_signature(netdissect_options *ndo,
+                                const struct ip *ip, const struct tcphdr *tp,
+                                const u_char *data, int length, const u_char *rcvsig);
 #endif
 
-static void print_tcp_rst_data(register const u_char *sp, u_int length);
+static void print_tcp_rst_data(netdissect_options *, register const u_char *sp, u_int length);
 
 #define MAX_RST_DATA_LEN       30
 
 
 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;
+        struct in_addr src;
+        struct in_addr dst;
+        u_int port;
 };
 
 struct tcp_seq_hash {
-       struct tcp_seq_hash *nxt;
-       struct tha addr;
-       tcp_seq seq;
-       tcp_seq ack;
+        struct tcp_seq_hash *nxt;
+        struct tha addr;
+        tcp_seq seq;
+        tcp_seq ack;
+};
+
+#ifdef INET6
+struct tha6 {
+        struct in6_addr src;
+        struct in6_addr dst;
+        u_int port;
+};
+
+struct tcp_seq_hash6 {
+        struct tcp_seq_hash6 *nxt;
+        struct tha6 addr;
+        tcp_seq seq;
+        tcp_seq ack;
 };
+#endif
 
 #define TSEQ_HASHSIZE 919
 
 /* These tcp optinos do not have the size octet */
 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
 
-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 PPTP_PORT
-#define PPTP_PORT      1723
-#endif
-#define BEEP_PORT        10288
-#ifndef NFS_PORT
-#define NFS_PORT       2049
+static struct tcp_seq_hash tcp_seq_hash4[TSEQ_HASHSIZE];
+#ifdef INET6
+static struct tcp_seq_hash6 tcp_seq_hash6[TSEQ_HASHSIZE];
 #endif
-#define MSDP_PORT      639
-#define LDP_PORT        646
 
-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]);
-}
+static const struct tok tcp_flag_values[] = {
+        { TH_FIN, "F" },
+        { TH_SYN, "S" },
+        { TH_RST, "R" },
+        { TH_PUSH, "P" },
+        { TH_ACK, "." },
+        { TH_URG, "U" },
+        { TH_ECNECHO, "E" },
+        { TH_CWR, "W" },
+        { 0, NULL }
+};
 
-#ifdef INET6
-static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp,
-       u_int len)
+static const struct tok tcp_option_values[] = {
+        { TCPOPT_EOL, "eol" },
+        { TCPOPT_NOP, "nop" },
+        { TCPOPT_MAXSEG, "mss" },
+        { TCPOPT_WSCALE, "wscale" },
+        { TCPOPT_SACKOK, "sackOK" },
+        { TCPOPT_SACK, "sack" },
+        { TCPOPT_ECHO, "echo" },
+        { TCPOPT_ECHOREPLY, "echoreply" },
+        { TCPOPT_TIMESTAMP, "TS" },
+        { TCPOPT_CC, "cc" },
+        { TCPOPT_CCNEW, "ccnew" },
+        { TCPOPT_CCECHO, "" },
+        { TCPOPT_SIGNATURE, "md5" },
+        { TCPOPT_AUTH, "enhanced auth" },
+        { TCPOPT_UTO, "uto" },
+        { TCPOPT_MPTCP, "mptcp" },
+        { TCPOPT_EXPERIMENT2, "exp" },
+        { 0, NULL }
+};
+
+static int
+tcp_cksum(netdissect_options *ndo,
+          register const struct ip *ip,
+          register const struct tcphdr *tp,
+          register u_int len)
 {
-       size_t i;
-       register const u_int16_t *sp;
-       u_int32_t sum;
-       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;
-
-       sum = 0;
-       for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
-               sum += phu.pa[i];
-
-       sp = (const u_int16_t *)tp;
-
-       for (i = 0; i < (len & ~1); i += 2)
-               sum += *sp++;
-
-       if (len & 1)
-               sum += htons((*(const u_int8_t *)sp) << 8);
-
-       while (sum > 0xffff)
-               sum = (sum & 0xffff) + (sum >> 16);
-       sum = ~sum & 0xffff;
-
-       return (sum);
+       return nextproto4_cksum(ndo, ip, (const uint8_t *)tp, len, len,
+                               IPPROTO_TCP);
 }
-#endif
 
 void
-tcp_print(register const u_char *bp, register u_int length,
-         register const u_char *bp2, int fragmented)
+tcp_print(netdissect_options *ndo,
+          register const u_char *bp, register u_int length,
+          register const u_char *bp2, int fragmented)
 {
-       register const struct tcphdr *tp;
-       register const struct ip *ip;
-       register u_char flags;
-       register u_int hlen;
-       register char ch;
-       u_int16_t sport, dport, win, urp;
-       u_int32_t seq, ack, thseq, thack;
-       int threv;
+        register const struct tcphdr *tp;
+        register const struct ip *ip;
+        register u_char flags;
+        register u_int hlen;
+        register char ch;
+        uint16_t sport, dport, win, urp;
+        uint32_t seq, ack, thseq, thack;
+        u_int utoval;
+        uint16_t magic;
+        register int rev;
 #ifdef INET6
-       register const struct ip6_hdr *ip6;
+        register const struct ip6_hdr *ip6;
 #endif
 
-       tp = (struct tcphdr *)bp;
-       ip = (struct ip *)bp2;
-#ifdef INET6
-       if (IP_V(ip) == 6)
-               ip6 = (struct ip6_hdr *)bp2;
-       else
-               ip6 = NULL;
-#endif /*INET6*/
-       ch = '\0';
-       if (!TTEST(tp->th_dport)) {
-               (void)printf("%s > %s: [|tcp]",
-                       ipaddr_string(&ip->ip_src),
-                       ipaddr_string(&ip->ip_dst));
-               return;
-       }
-
-       sport = EXTRACT_16BITS(&tp->th_sport);
-       dport = EXTRACT_16BITS(&tp->th_dport);
-
-       hlen = TH_OFF(tp) * 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;
-               }
-       }
+        tp = (struct tcphdr *)bp;
+        ip = (struct ip *)bp2;
 #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
+        if (IP_V(ip) == 6)
+                ip6 = (struct ip6_hdr *)bp2;
+        else
+                ip6 = NULL;
 #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));
-               }
-       }
+        ch = '\0';
+        if (!ND_TTEST(tp->th_dport)) {
+                ND_PRINT((ndo, "%s > %s: [|tcp]",
+                             ipaddr_string(ndo, &ip->ip_src),
+                             ipaddr_string(ndo, &ip->ip_dst)));
+                return;
+        }
 
-       TCHECK(*tp);
+        sport = EXTRACT_16BITS(&tp->th_sport);
+        dport = EXTRACT_16BITS(&tp->th_dport);
 
-       seq = EXTRACT_32BITS(&tp->th_seq);
-       ack = EXTRACT_32BITS(&tp->th_ack);
-       win = EXTRACT_16BITS(&tp->th_win);
-       urp = EXTRACT_16BITS(&tp->th_urp);
+        hlen = TH_OFF(tp) * 4;
 
-       if (qflag) {
-               (void)printf("tcp %d", length - TH_OFF(tp) * 4);
-               return;
-       }
-       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)
-                       putchar('F');
-               if (flags & TH_RST)
-                       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('.');
-
-       if (!Sflag && (flags & TH_ACK)) {
-               register struct tcp_seq_hash *th;
-               const void *src, *dst;
-               register int rev;
-               struct tha tha;
-               /*
-                * Find (or record) the initial sequence numbers for
-                * this conversation.  (we pick an arbitrary
-                * collating order so there's only one entry for
-                * both directions).
-                */
 #ifdef INET6
-               memset(&tha, 0, sizeof(tha));
-               rev = 0;
-               if (ip6) {
-                       src = &ip6->ip6_src;
-                       dst = &ip6->ip6_dst;
-                       if (sport > dport)
-                               rev = 1;
-                       else if (sport == dport) {
-                               if (memcmp(src, dst, sizeof ip6->ip6_dst) > 0)
-                                       rev = 1;
-                       }
-                       if (rev) {
-                               memcpy(&tha.src, dst, sizeof ip6->ip6_dst);
-                               memcpy(&tha.dst, src, sizeof ip6->ip6_src);
-                               tha.port = dport << 16 | sport;
-                       } else {
-                               memcpy(&tha.dst, dst, sizeof ip6->ip6_dst);
-                               memcpy(&tha.src, src, sizeof ip6->ip6_src);
-                               tha.port = sport << 16 | dport;
-                       }
-               } else {
-                       src = &ip->ip_src;
-                       dst = &ip->ip_dst;
-                       if (sport > dport)
-                               rev = 1;
-                       else if (sport == dport) {
-                               if (memcmp(src, dst, sizeof ip->ip_dst) > 0)
-                                       rev = 1;
-                       }
-                       if (rev) {
-                               memcpy(&tha.src, dst, sizeof ip->ip_dst);
-                               memcpy(&tha.dst, src, sizeof ip->ip_src);
-                               tha.port = dport << 16 | sport;
-                       } else {
-                               memcpy(&tha.dst, dst, sizeof ip->ip_dst);
-                               memcpy(&tha.src, src, sizeof ip->ip_src);
-                               tha.port = sport << 16 | dport;
-                       }
-               }
-#else
-               rev = 0;
-               src = &ip->ip_src;
-               dst = &ip->ip_dst;
-               if (sport > dport)
-                       rev = 1;
-               else if (sport == dport) {
-                       if (memcmp(src, dst, sizeof ip->ip_dst) > 0)
-                               rev = 1;
-               }
-               if (rev) {
-                       memcpy(&tha.src, dst, sizeof ip->ip_dst);
-                       memcpy(&tha.dst, src, sizeof ip->ip_src);
-                       tha.port = dport << 16 | sport;
-               } else {
-                       memcpy(&tha.dst, dst, sizeof ip->ip_dst);
-                       memcpy(&tha.src, src, sizeof ip->ip_src);
-                       tha.port = sport << 16 | dport;
-               }
-#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)) == 0)
-                               break;
-
-               if (!th->nxt || (flags & TH_SYN)) {
-                       /* didn't find it or new conversation */
-                       if (th->nxt == NULL) {
-                               th->nxt = (struct tcp_seq_hash *)
-                                       calloc(1, sizeof(*th));
-                               if (th->nxt == NULL)
-                                       error("tcp_print: calloc");
-                       }
-                       th->addr = tha;
-                       if (rev)
-                               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;
-       }
-       if (hlen > length) {
-               (void)printf(" [bad hdr length]");
-               return;
-       }
-
-       if (IP_V(ip) == 4 && vflag && !fragmented) {
-               u_int16_t sum, tcp_sum;
-               if (TTEST2(tp->th_sport, length)) {
-                       sum = tcp_cksum(ip, tp, length);
-                       if (sum != 0) {
-                               tcp_sum = EXTRACT_16BITS(&tp->th_sum);
-                               (void)printf(" [bad tcp cksum %x (->%x)!]",
-                                   tcp_sum, in_cksum_shouldbe(tcp_sum, sum));
-                       } else
-                               (void)printf(" [tcp sum ok]");
-               }
-       }
+        if (ip6) {
+                if (ip6->ip6_nxt == IPPROTO_TCP) {
+                        ND_PRINT((ndo, "%s.%s > %s.%s: ",
+                                     ip6addr_string(ndo, &ip6->ip6_src),
+                                     tcpport_string(sport),
+                                     ip6addr_string(ndo, &ip6->ip6_dst),
+                                     tcpport_string(dport)));
+                } else {
+                        ND_PRINT((ndo, "%s > %s: ",
+                                     tcpport_string(sport), tcpport_string(dport)));
+                }
+        } else
+#endif /*INET6*/
+        {
+                if (ip->ip_p == IPPROTO_TCP) {
+                        ND_PRINT((ndo, "%s.%s > %s.%s: ",
+                                     ipaddr_string(ndo, &ip->ip_src),
+                                     tcpport_string(sport),
+                                     ipaddr_string(ndo, &ip->ip_dst),
+                                     tcpport_string(dport)));
+                } else {
+                        ND_PRINT((ndo, "%s > %s: ",
+                                     tcpport_string(sport), tcpport_string(dport)));
+                }
+        }
+
+        if (hlen < sizeof(*tp)) {
+                ND_PRINT((ndo, " tcp %d [bad hdr length %u - too short, < %lu]",
+                             length - hlen, hlen, (unsigned long)sizeof(*tp)));
+                return;
+        }
+
+        ND_TCHECK(*tp);
+
+        seq = EXTRACT_32BITS(&tp->th_seq);
+        ack = EXTRACT_32BITS(&tp->th_ack);
+        win = EXTRACT_16BITS(&tp->th_win);
+        urp = EXTRACT_16BITS(&tp->th_urp);
+
+        if (ndo->ndo_qflag) {
+                ND_PRINT((ndo, "tcp %d", length - hlen));
+                if (hlen > length) {
+                        ND_PRINT((ndo, " [bad hdr length %u - too long, > %u]",
+                                     hlen, length));
+                }
+                return;
+        }
+
+        flags = tp->th_flags;
+        ND_PRINT((ndo, "Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags)));
+
+        if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
+                /*
+                 * Find (or record) the initial sequence numbers for
+                 * this conversation.  (we pick an arbitrary
+                 * collating order so there's only one entry for
+                 * both directions).
+                 */
+                rev = 0;
 #ifdef INET6
-       if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !fragmented) {
-               int sum;
-               if (TTEST2(tp->th_sport, length)) {
-                       sum = tcp6_cksum(ip6, tp, length);
-                       if (sum != 0)
-                               (void)printf(" [bad tcp cksum %x!]", sum);
-                       else
-                               (void)printf(" [tcp sum ok]");
-               }
-       }
+                if (ip6) {
+                        register struct tcp_seq_hash6 *th;
+                        struct tcp_seq_hash6 *tcp_seq_hash;
+                        const struct in6_addr *src, *dst;
+                        struct tha6 tha;
+
+                        tcp_seq_hash = tcp_seq_hash6;
+                        src = &ip6->ip6_src;
+                        dst = &ip6->ip6_dst;
+                        if (sport > dport)
+                                rev = 1;
+                        else if (sport == dport) {
+                                if (UNALIGNED_MEMCMP(src, dst, sizeof ip6->ip6_dst) > 0)
+                                        rev = 1;
+                        }
+                        if (rev) {
+                                UNALIGNED_MEMCPY(&tha.src, dst, sizeof ip6->ip6_dst);
+                                UNALIGNED_MEMCPY(&tha.dst, src, sizeof ip6->ip6_src);
+                                tha.port = dport << 16 | sport;
+                        } else {
+                                UNALIGNED_MEMCPY(&tha.dst, dst, sizeof ip6->ip6_dst);
+                                UNALIGNED_MEMCPY(&tha.src, src, sizeof ip6->ip6_src);
+                                tha.port = sport << 16 | dport;
+                        }
+
+                        for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
+                             th->nxt; th = th->nxt)
+                                if (memcmp((char *)&tha, (char *)&th->addr,
+                                           sizeof(th->addr)) == 0)
+                                        break;
+
+                        if (!th->nxt || (flags & TH_SYN)) {
+                                /* didn't find it or new conversation */
+                                if (th->nxt == NULL) {
+                                        th->nxt = (struct tcp_seq_hash6 *)
+                                                calloc(1, sizeof(*th));
+                                        if (th->nxt == NULL)
+                                                error("tcp_print: calloc");
+                                }
+                                th->addr = tha;
+                                if (rev)
+                                        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 {
+#else  /*INET6*/
+                {
+#endif /*INET6*/
+                        register struct tcp_seq_hash *th;
+                        struct tcp_seq_hash *tcp_seq_hash;
+                        const struct in_addr *src, *dst;
+                        struct tha tha;
+
+                        tcp_seq_hash = tcp_seq_hash4;
+                        src = &ip->ip_src;
+                        dst = &ip->ip_dst;
+                        if (sport > dport)
+                                rev = 1;
+                        else if (sport == dport) {
+                                if (UNALIGNED_MEMCMP(src, dst, sizeof ip->ip_dst) > 0)
+                                        rev = 1;
+                        }
+                        if (rev) {
+                                UNALIGNED_MEMCPY(&tha.src, dst, sizeof ip->ip_dst);
+                                UNALIGNED_MEMCPY(&tha.dst, src, sizeof ip->ip_src);
+                                tha.port = dport << 16 | sport;
+                        } else {
+                                UNALIGNED_MEMCPY(&tha.dst, dst, sizeof ip->ip_dst);
+                                UNALIGNED_MEMCPY(&tha.src, src, sizeof ip->ip_src);
+                                tha.port = sport << 16 | dport;
+                        }
+
+                        for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
+                             th->nxt; th = th->nxt)
+                                if (memcmp((char *)&tha, (char *)&th->addr,
+                                           sizeof(th->addr)) == 0)
+                                        break;
+
+                        if (!th->nxt || (flags & TH_SYN)) {
+                                /* didn't find it or new conversation */
+                                if (th->nxt == NULL) {
+                                        th->nxt = (struct tcp_seq_hash *)
+                                                calloc(1, sizeof(*th));
+                                        if (th->nxt == NULL)
+                                                error("tcp_print: calloc");
+                                }
+                                th->addr = tha;
+                                if (rev)
+                                        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 = rev = 0;
+        }
+        if (hlen > length) {
+                ND_PRINT((ndo, " [bad hdr length %u - too long, > %u]",
+                             hlen, length));
+                return;
+        }
+
+        if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
+                /* Check the checksum, if possible. */
+                uint16_t sum, tcp_sum;
+
+                if (IP_V(ip) == 4) {
+                        if (ND_TTEST2(tp->th_sport, length)) {
+                                sum = tcp_cksum(ndo, ip, tp, length);
+                                tcp_sum = EXTRACT_16BITS(&tp->th_sum);
+
+                                ND_PRINT((ndo, ", cksum 0x%04x", tcp_sum));
+                                if (sum != 0)
+                                        ND_PRINT((ndo, " (incorrect -> 0x%04x)",
+                                            in_cksum_shouldbe(tcp_sum, sum)));
+                                else
+                                        ND_PRINT((ndo, " (correct)"));
+                        }
+                }
+#ifdef INET6
+                else if (IP_V(ip) == 6 && ip6->ip6_plen) {
+                        if (ND_TTEST2(tp->th_sport, length)) {
+                                sum = nextproto6_cksum(ip6, (const uint8_t *)tp,
+                                                       length, length, IPPROTO_TCP);
+                                tcp_sum = EXTRACT_16BITS(&tp->th_sum);
+
+                                ND_PRINT((ndo, ", cksum 0x%04x", tcp_sum));
+                                if (sum != 0)
+                                        ND_PRINT((ndo, " (incorrect -> 0x%04x)",
+                                            in_cksum_shouldbe(tcp_sum, sum)));
+                                else
+                                        ND_PRINT((ndo, " (correct)"));
+
+                        }
+                }
 #endif
-
-       length -= hlen;
-       if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
-               (void)printf(" %u:%u(%u)", seq, seq + length, length);
-       if (flags & TH_ACK)
-               (void)printf(" ack %u", ack);
-
-       (void)printf(" win %d", win);
-
-       if (flags & TH_URG)
-               (void)printf(" urg %d", urp);
-       /*
-        * Handle any options.
-        */
-       if (hlen > sizeof(*tp)) {
-               register const u_char *cp;
-               register u_int i, opt, datalen;
-               register u_int len;
-
-               hlen -= sizeof(*tp);
-               cp = (const u_char *)tp + sizeof(*tp);
-               putchar(' ');
-               ch = '<';
-               while (hlen > 0) {
-                       putchar(ch);
-                       TCHECK(*cp);
-                       opt = *cp++;
-                       if (ZEROLENOPT(opt))
-                               len = 1;
-                       else {
-                               TCHECK(*cp);
-                               len = *cp++;    /* total including type, len */
-                               if (len < 2 || len > hlen)
-                                       goto bad;
-                               --hlen;         /* account for length byte */
-                       }
-                       --hlen;                 /* account for type byte */
-                       datalen = 0;
+        }
+
+        length -= hlen;
+        if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
+                ND_PRINT((ndo, ", seq %u", seq));
+
+                if (length > 0) {
+                        ND_PRINT((ndo, ":%u", seq + length));
+                }
+        }
+
+        if (flags & TH_ACK) {
+                ND_PRINT((ndo, ", ack %u", ack));
+        }
+
+        ND_PRINT((ndo, ", win %d", win));
+
+        if (flags & TH_URG)
+                ND_PRINT((ndo, ", urg %d", urp));
+        /*
+         * Handle any options.
+         */
+        if (hlen > sizeof(*tp)) {
+                register const u_char *cp;
+                register u_int i, opt, datalen;
+                register u_int len;
+
+                hlen -= sizeof(*tp);
+                cp = (const u_char *)tp + sizeof(*tp);
+                ND_PRINT((ndo, ", options ["));
+                while (hlen > 0) {
+                        if (ch != '\0')
+                                ND_PRINT((ndo, "%c", ch));
+                        ND_TCHECK(*cp);
+                        opt = *cp++;
+                        if (ZEROLENOPT(opt))
+                                len = 1;
+                        else {
+                                ND_TCHECK(*cp);
+                                len = *cp++;   /* total including type, len */
+                                if (len < 2 || len > hlen)
+                                        goto bad;
+                                --hlen;                /* account for length byte */
+                        }
+                        --hlen;                        /* account for type byte */
+                        datalen = 0;
 
 /* Bail if "l" bytes of data are not left or were not captured  */
-#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
-
-                       switch (opt) {
-
-                       case TCPOPT_MAXSEG:
-                               (void)printf("mss");
-                               datalen = 2;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_16BITS(cp));
-
-                               break;
-
-                       case TCPOPT_EOL:
-                               (void)printf("eol");
-                               break;
-
-                       case TCPOPT_NOP:
-                               (void)printf("nop");
-                               break;
-
-                       case TCPOPT_WSCALE:
-                               (void)printf("wscale");
-                               datalen = 1;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", *cp);
-                               break;
-
-                       case TCPOPT_SACKOK:
-                               (void)printf("sackOK");
-                               break;
-
-                       case TCPOPT_SACK:
-                               (void)printf("sack");
-                               datalen = len - 2;
-                               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(" ");
-                               }
-                               break;
-
-                       case TCPOPT_ECHO:
-                               (void)printf("echo");
-                               datalen = 4;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_32BITS(cp));
-                               break;
-
-                       case TCPOPT_ECHOREPLY:
-                               (void)printf("echoreply");
-                               datalen = 4;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_32BITS(cp));
-                               break;
-
-                       case TCPOPT_TIMESTAMP:
-                               (void)printf("timestamp");
-                               datalen = 8;
-                               LENCHECK(4);
-                               (void)printf(" %u", EXTRACT_32BITS(cp));
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_32BITS(cp + 4));
-                               break;
-
-                       case TCPOPT_CC:
-                               (void)printf("cc");
-                               datalen = 4;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_32BITS(cp));
-                               break;
-
-                       case TCPOPT_CCNEW:
-                               (void)printf("ccnew");
-                               datalen = 4;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_32BITS(cp));
-                               break;
-
-                       case TCPOPT_CCECHO:
-                               (void)printf("ccecho");
-                               datalen = 4;
-                               LENCHECK(datalen);
-                               (void)printf(" %u", EXTRACT_32BITS(cp));
-                               break;
-
-                       case TCPOPT_SIGNATURE:
-                               (void)printf("md5:");
-                               if (IP_V(ip) != 4) {
-                                       (void)printf("!ipv4");
-                                       break;
-                               }
-                               datalen = TCP_SIGLEN;
-                               LENCHECK(datalen);
+#define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK2(*cp, l); }
+
+
+                        ND_PRINT((ndo, "%s", tok2str(tcp_option_values, "unknown-%u", opt)));
+
+                        switch (opt) {
+
+                        case TCPOPT_MAXSEG:
+                                datalen = 2;
+                                LENCHECK(datalen);
+                                ND_PRINT((ndo, " %u", EXTRACT_16BITS(cp)));
+                                break;
+
+                        case TCPOPT_WSCALE:
+                                datalen = 1;
+                                LENCHECK(datalen);
+                                ND_PRINT((ndo, " %u", *cp));
+                                break;
+
+                        case TCPOPT_SACK:
+                                datalen = len - 2;
+                                if (datalen % 8 != 0) {
+                                        ND_PRINT((ndo, "malformed sack"));
+                                } else {
+                                        uint32_t s, e;
+
+                                        ND_PRINT((ndo, " %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 (rev) {
+                                                        s -= thseq;
+                                                        e -= thseq;
+                                                } else {
+                                                        s -= thack;
+                                                        e -= thack;
+                                                }
+                                                ND_PRINT((ndo, "{%u:%u}", s, e));
+                                        }
+                                }
+                                break;
+
+                        case TCPOPT_CC:
+                        case TCPOPT_CCNEW:
+                        case TCPOPT_CCECHO:
+                        case TCPOPT_ECHO:
+                        case TCPOPT_ECHOREPLY:
+
+                                /*
+                                 * those options share their semantics.
+                                 * fall through
+                                 */
+                                datalen = 4;
+                                LENCHECK(datalen);
+                                ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
+                                break;
+
+                        case TCPOPT_TIMESTAMP:
+                                datalen = 8;
+                                LENCHECK(datalen);
+                                ND_PRINT((ndo, " val %u ecr %u",
+                                             EXTRACT_32BITS(cp),
+                                             EXTRACT_32BITS(cp + 4)));
+                                break;
+
+                        case TCPOPT_SIGNATURE:
+                                datalen = TCP_SIGLEN;
+                                LENCHECK(datalen);
 #ifdef HAVE_LIBCRYPTO
-                               if (tcp_verify_signature(ip, tp,
-                                   bp + TH_OFF(tp) * 4, length, cp) == 0)
-                                       (void)printf("valid");
-                               else
-                                       (void)printf("invalid");
+                                switch (tcp_verify_signature(ndo, ip, tp,
+                                                             bp + TH_OFF(tp) * 4, length, cp)) {
+
+                                case SIGNATURE_VALID:
+                                        ND_PRINT((ndo, "valid"));
+                                        break;
+
+                                case SIGNATURE_INVALID:
+                                        ND_PRINT((ndo, "invalid"));
+                                        break;
+
+                                case CANT_CHECK_SIGNATURE:
+                                        ND_PRINT((ndo, "can't check - "));
+                                        for (i = 0; i < TCP_SIGLEN; ++i)
+                                                ND_PRINT((ndo, "%02x", cp[i]));
+                                        break;
+                                }
 #else
-                               for (i = 0; i < TCP_SIGLEN; ++i)
-                                       (void)printf("%02x", cp[i]);
+                                for (i = 0; i < TCP_SIGLEN; ++i)
+                                        ND_PRINT((ndo, "%02x", cp[i]));
 #endif
-                               break;
-
-                       default:
-                               (void)printf("opt-%u:", opt);
-                               datalen = len - 2;
-                               for (i = 0; i < datalen; ++i) {
-                                       LENCHECK(i);
-                                       (void)printf("%02x", cp[i]);
-                               }
-                               break;
-                       }
-
-                       /* Account for data printed */
-                       cp += datalen;
-                       hlen -= datalen;
-
-                       /* Check specification against observed length */
-                       ++datalen;                      /* option octet */
-                       if (!ZEROLENOPT(opt))
-                               ++datalen;              /* size octet */
-                       if (datalen != len)
-                               (void)printf("[len %d]", len);
-                       ch = ',';
-                       if (opt == TCPOPT_EOL)
-                               break;
-               }
-               putchar('>');
-       }
-
-       if (length <= 0)
-               return;
-
-       /*
-        * Decode payload if necessary.
-        */
-       bp += TH_OFF(tp) * 4;
-       if (flags & TH_RST) {
-               if (vflag)
-                       print_tcp_rst_data(bp, length);
-       } else {
-               if (sport == TELNET_PORT || dport == TELNET_PORT) {
-                       if (!qflag && vflag)
-                               telnet_print(bp, length);
-               } else if (sport == BGP_PORT || dport == BGP_PORT)
-                       bgp_print(bp, length);
-               else if (sport == PPTP_PORT || dport == PPTP_PORT)
-                       pptp_print(bp);
+                                break;
+
+                        case TCPOPT_AUTH:
+                                ND_PRINT((ndo, "keyid %d", *cp++));
+                                datalen = len - 3;
+                                for (i = 0; i < datalen; ++i) {
+                                        LENCHECK(i);
+                                        ND_PRINT((ndo, "%02x", cp[i]));
+                                }
+                                break;
+
+
+                        case TCPOPT_EOL:
+                        case TCPOPT_NOP:
+                        case TCPOPT_SACKOK:
+                                /*
+                                 * Nothing interesting.
+                                 * fall through
+                                 */
+                                break;
+
+                        case TCPOPT_UTO:
+                                datalen = 2;
+                                LENCHECK(datalen);
+                                utoval = EXTRACT_16BITS(cp);
+                                ND_PRINT((ndo, "0x%x", utoval));
+                                if (utoval & 0x0001)
+                                        utoval = (utoval >> 1) * 60;
+                                else
+                                        utoval >>= 1;
+                                ND_PRINT((ndo, " %u", utoval));
+                                break;
+
+                        case TCPOPT_MPTCP:
+                                datalen = len - 2;
+                                LENCHECK(datalen);
+                                if (!mptcp_print(ndo, cp-2, len, flags))
+                                        goto bad;
+                                break;
+
+                        case TCPOPT_EXPERIMENT2:
+                                datalen = len - 2;
+                                LENCHECK(datalen);
+                                if (datalen < 2)
+                                        goto bad;
+                                /* RFC6994 */
+                                magic = EXTRACT_16BITS(cp);
+                                ND_PRINT((ndo, "-"));
+
+                                switch(magic) {
+
+                                case 0xf989:
+                                        /* TCP Fast Open: draft-ietf-tcpm-fastopen-04 */
+                                        if (datalen == 2) {
+                                                /* Fast Open Cookie Request */
+                                                ND_PRINT((ndo, "tfo cookiereq"));
+                                        } else {
+                                                /* Fast Open Cookie */
+                                                if (datalen % 2 != 0 || datalen < 6 || datalen > 18) {
+                                                        ND_PRINT((ndo, "tfo malformed"));
+                                                } else {
+                                                        ND_PRINT((ndo, "tfo cookie "));
+                                                        for (i = 2; i < datalen; ++i)
+                                                                ND_PRINT((ndo, "%02x", cp[i]));
+                                                }
+                                        }
+                                        break;
+
+                                default:
+                                        /* Unknown magic number */
+                                        ND_PRINT((ndo, "%04x", magic));
+                                        break;
+                                }
+                                break;
+
+                        default:
+                                datalen = len - 2;
+                                if (datalen)
+                                        ND_PRINT((ndo, " 0x"));
+                                for (i = 0; i < datalen; ++i) {
+                                        LENCHECK(i);
+                                        ND_PRINT((ndo, "%02x", cp[i]));
+                                }
+                                break;
+                        }
+
+                        /* Account for data printed */
+                        cp += datalen;
+                        hlen -= datalen;
+
+                        /* Check specification against observed length */
+                        ++datalen;                     /* option octet */
+                        if (!ZEROLENOPT(opt))
+                                ++datalen;             /* size octet */
+                        if (datalen != len)
+                                ND_PRINT((ndo, "[len %d]", len));
+                        ch = ',';
+                        if (opt == TCPOPT_EOL)
+                                break;
+                }
+                ND_PRINT((ndo, "]"));
+        }
+
+        /*
+         * Print length field before crawling down the stack.
+         */
+        ND_PRINT((ndo, ", length %u", length));
+
+        if (length <= 0)
+                return;
+
+        /*
+         * Decode payload if necessary.
+         */
+        bp += TH_OFF(tp) * 4;
+        if ((flags & TH_RST) && ndo->ndo_vflag) {
+                print_tcp_rst_data(ndo, bp, length);
+                return;
+        }
+
+        if (ndo->ndo_packettype) {
+                switch (ndo->ndo_packettype) {
+                case PT_ZMTP1:
+                        zmtp1_print(ndo, bp, length);
+                        break;
+                }
+                return;
+        }
+
+        if (sport == TELNET_PORT || dport == TELNET_PORT) {
+                if (!ndo->ndo_qflag && ndo->ndo_vflag)
+                        telnet_print(ndo, bp, length);
+        } else if (sport == BGP_PORT || dport == BGP_PORT)
+                bgp_print(ndo, bp, length);
+        else if (sport == PPTP_PORT || dport == PPTP_PORT)
+                pptp_print(ndo, bp);
 #ifdef TCPDUMP_DO_SMB
-               else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
-                       nbt_tcp_print(bp, length);
+        else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
+                nbt_tcp_print(ndo, bp, length);
+       else if (sport == SMB_PORT || dport == SMB_PORT)
+               smb_tcp_print(ndo, bp, length);
 #endif
-               else if (sport == BEEP_PORT || dport == BEEP_PORT)
-                       beep_print(bp, length);
-               else if (length > 2 &&
-                   (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT ||
-                    sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) {
-                       /*
-                        * TCP DNS query has 2byte length at the head.
-                        * XXX packet could be unaligned, it can go strange
-                        */
-                       ns_print(bp + 2, length - 2, 0);
-               } else if (sport == MSDP_PORT || dport == MSDP_PORT) {
-                       msdp_print(bp, length);
-               }
-                else if (sport == LDP_PORT || dport == LDP_PORT)
-                        printf(": LDP, length: %u", length);
-       }
-       return;
-bad:
-       fputs("[bad opt]", stdout);
-       if (ch != '\0')
-               putchar('>');
-       return;
-trunc:
-       fputs("[|tcp]", stdout);
-       if (ch != '\0')
-               putchar('>');
+        else if (sport == BEEP_PORT || dport == BEEP_PORT)
+                beep_print(ndo, bp, length);
+        else if (sport == OPENFLOW_PORT_OLD || dport == OPENFLOW_PORT_OLD ||
+                 sport == OPENFLOW_PORT_IANA || dport == OPENFLOW_PORT_IANA)
+                openflow_print(ndo, bp, length);
+        else if (length > 2 &&
+                 (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT ||
+                  sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) {
+                /*
+                 * TCP DNS query has 2byte length at the head.
+                 * XXX packet could be unaligned, it can go strange
+                 */
+                ns_print(ndo, bp + 2, length - 2, 0);
+        } else if (sport == MSDP_PORT || dport == MSDP_PORT) {
+                msdp_print(ndo, bp, length);
+        } else if (sport == RPKI_RTR_PORT || dport == RPKI_RTR_PORT) {
+                rpki_rtr_print(ndo, bp, length);
+        }
+        else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) {
+                ldp_print(ndo, bp, length);
+        }
+        else if ((sport == NFS_PORT || dport == NFS_PORT) &&
+                 length >= 4 && ND_TTEST2(*bp, 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.
+                 */
+                uint32_t fraglen;
+                register struct sunrpc_msg *rp;
+                enum sunrpc_msg_type direction;
+
+                fraglen = EXTRACT_32BITS(bp) & 0x7FFFFFFF;
+                if (fraglen > (length) - 4)
+                        fraglen = (length) - 4;
+                rp = (struct sunrpc_msg *)(bp + 4);
+                if (ND_TTEST(rp->rm_direction)) {
+                        direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction);
+                        if (dport == NFS_PORT && direction == SUNRPC_CALL) {
+                                ND_PRINT((ndo, ": NFS request xid %u ", EXTRACT_32BITS(&rp->rm_xid)));
+                                nfsreq_print_noaddr(ndo, (u_char *)rp, fraglen, (u_char *)ip);
+                                return;
+                        }
+                        if (sport == NFS_PORT && direction == SUNRPC_REPLY) {
+                                ND_PRINT((ndo, ": NFS reply xid %u ", EXTRACT_32BITS(&rp->rm_xid)));
+                                nfsreply_print_noaddr(ndo, (u_char *)rp, fraglen, (u_char *)ip);
+                                return;
+                        }
+                }
+        }
+
+        return;
+ bad:
+        ND_PRINT((ndo, "[bad opt]"));
+        if (ch != '\0')
+                ND_PRINT((ndo, ">"));
+        return;
+ trunc:
+        ND_PRINT((ndo, "[|tcp]"));
+        if (ch != '\0')
+                ND_PRINT((ndo, ">"));
 }
 
 /*
@@ -681,73 +766,119 @@ trunc:
  */
 
 static void
-print_tcp_rst_data(register const u_char *sp, u_int length)
+print_tcp_rst_data(netdissect_options *ndo,
+                   register const u_char *sp, u_int length)
 {
-       int c;
-
-       if (TTEST2(*sp, length))
-               printf(" [RST");
-       else
-               printf(" [!RST");
-       if (length > MAX_RST_DATA_LEN) {
-               length = MAX_RST_DATA_LEN;      /* can use -X for longer */
-               putchar('+');                   /* indicate we truncate */
-       }
-       putchar(' ');
-       while (length-- && sp <= snapend) {
-               c = *sp++;
-               safeputchar(c);
-       }
-       putchar(']');
+        int c;
+
+        ND_PRINT((ndo, ND_TTEST2(*sp, length) ? " [RST" : " [!RST"));
+        if (length > MAX_RST_DATA_LEN) {
+                length = MAX_RST_DATA_LEN;     /* can use -X for longer */
+                ND_PRINT((ndo, "+"));                  /* indicate we truncate */
+        }
+        ND_PRINT((ndo, " "));
+        while (length-- && sp <= ndo->ndo_snapend) {
+                c = *sp++;
+                safeputchar(ndo, c);
+        }
+        ND_PRINT((ndo, "]"));
 }
 
 #ifdef HAVE_LIBCRYPTO
+USES_APPLE_DEPRECATED_API
 static int
-tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
-    const u_char *data, int length, const u_char *rcvsig)
+tcp_verify_signature(netdissect_options *ndo,
+                     const struct ip *ip, const struct tcphdr *tp,
+                     const u_char *data, int length, const u_char *rcvsig)
 {
         struct tcphdr tp1;
-       char sig[TCP_SIGLEN];
-       char zero_proto = 0;
-       MD5_CTX ctx;
-       u_short savecsum, tlen;
-
-       tp1 = *tp;
-
-       if (tcpmd5secret == NULL)
-               return (-1);
-
-       MD5_Init(&ctx);
-       /*
-        * Step 1: Update MD5 hash with IP pseudo-header.
-        */
-       MD5_Update(&ctx, (char *)&ip->ip_src, sizeof(ip->ip_src));
-       MD5_Update(&ctx, (char *)&ip->ip_dst, sizeof(ip->ip_dst));
-       MD5_Update(&ctx, (char *)&zero_proto, sizeof(zero_proto));
-       MD5_Update(&ctx, (char *)&ip->ip_p, sizeof(ip->ip_p));
-       tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4;
-       tlen = htons(tlen);
-       MD5_Update(&ctx, (char *)&tlen, sizeof(tlen));
-
-       /*
-        * Step 2: Update MD5 hash with TCP header, excluding options.
-        * The TCP checksum must be set to zero.
-        */
-       savecsum = tp1.th_sum;
-       tp1.th_sum = 0;
-       MD5_Update(&ctx, (char *)&tp1, sizeof(struct tcphdr));
-       tp1.th_sum = savecsum;
-       /*
-        * Step 3: Update MD5 hash with TCP segment data, if present.
-        */
-       if (length > 0)
-               MD5_Update(&ctx, data, length);
-       /*
-        * Step 4: Update MD5 hash with shared secret.
-        */
-       MD5_Update(&ctx, tcpmd5secret, strlen(tcpmd5secret));
-       MD5_Final(sig, &ctx);
-
-       return (memcmp(rcvsig, sig, 16));
+        u_char sig[TCP_SIGLEN];
+        char zero_proto = 0;
+        MD5_CTX ctx;
+        uint16_t savecsum, tlen;
+#ifdef INET6
+        struct ip6_hdr *ip6;
+        uint32_t len32;
+        uint8_t nxt;
+#endif
+
+       if (data + length > ndo->ndo_snapend) {
+               ND_PRINT((ndo, "snaplen too short, "));
+               return (CANT_CHECK_SIGNATURE);
+       }
+
+        tp1 = *tp;
+
+        if (ndo->ndo_sigsecret == NULL) {
+               ND_PRINT((ndo, "shared secret not supplied with -M, "));
+                return (CANT_CHECK_SIGNATURE);
+        }
+
+        MD5_Init(&ctx);
+        /*
+         * Step 1: Update MD5 hash with IP pseudo-header.
+         */
+        if (IP_V(ip) == 4) {
+                MD5_Update(&ctx, (char *)&ip->ip_src, sizeof(ip->ip_src));
+                MD5_Update(&ctx, (char *)&ip->ip_dst, sizeof(ip->ip_dst));
+                MD5_Update(&ctx, (char *)&zero_proto, sizeof(zero_proto));
+                MD5_Update(&ctx, (char *)&ip->ip_p, sizeof(ip->ip_p));
+                tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4;
+                tlen = htons(tlen);
+                MD5_Update(&ctx, (char *)&tlen, sizeof(tlen));
+#ifdef INET6
+        } else if (IP_V(ip) == 6) {
+                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(EXTRACT_16BITS(&ip6->ip6_plen));
+                MD5_Update(&ctx, (char *)&len32, sizeof(len32));
+                nxt = 0;
+                MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
+                MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
+                MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
+                nxt = IPPROTO_TCP;
+                MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
+#endif
+        } else {
+#ifdef INET6
+               ND_PRINT((ndo, "IP version not 4 or 6, "));
+#else
+               ND_PRINT((ndo, "IP version not 4, "));
+#endif
+                return (CANT_CHECK_SIGNATURE);
+        }
+
+        /*
+         * Step 2: Update MD5 hash with TCP header, excluding options.
+         * The TCP checksum must be set to zero.
+         */
+        savecsum = tp1.th_sum;
+        tp1.th_sum = 0;
+        MD5_Update(&ctx, (char *)&tp1, sizeof(struct tcphdr));
+        tp1.th_sum = savecsum;
+        /*
+         * Step 3: Update MD5 hash with TCP segment data, if present.
+         */
+        if (length > 0)
+                MD5_Update(&ctx, data, length);
+        /*
+         * Step 4: Update MD5 hash with shared secret.
+         */
+        MD5_Update(&ctx, ndo->ndo_sigsecret, strlen(ndo->ndo_sigsecret));
+        MD5_Final(sig, &ctx);
+
+        if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
+                return (SIGNATURE_VALID);
+        else
+                return (SIGNATURE_INVALID);
 }
+USES_APPLE_RST
 #endif /* HAVE_LIBCRYPTO */
+
+/*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 8
+ * End:
+ */