xref: /freebsd/contrib/tcpdump/print-tcp.c (revision 39e421e8)
1a5779b6eSRui Paulo /*	$NetBSD: print-tcp.c,v 1.9 2007/07/26 18:15:12 plunky Exp $	*/
2a5779b6eSRui Paulo 
34edb46e9SPaul Traina /*
44644f044SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
54edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
64edb46e9SPaul Traina  *
71de50e9fSSam Leffler  * Copyright (c) 1999-2004 The tcpdump.org project
81de50e9fSSam Leffler  *
94edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
104edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
114edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
124edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
134edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
144edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
154edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
164edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
174edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
184edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
194edb46e9SPaul Traina  * or promote products derived from this software without specific prior
204edb46e9SPaul Traina  * written permission.
214edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
224edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
234edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
244edb46e9SPaul Traina  */
254edb46e9SPaul Traina 
263340d773SGleb Smirnoff /* \summary: TCP printer */
273340d773SGleb Smirnoff 
284edb46e9SPaul Traina #ifndef lint
29a5779b6eSRui Paulo #else
30a5779b6eSRui Paulo __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
31b0453382SBill Fenner #endif
32b0453382SBill Fenner 
33b0453382SBill Fenner #ifdef HAVE_CONFIG_H
34b0453382SBill Fenner #include "config.h"
354edb46e9SPaul Traina #endif
364edb46e9SPaul Traina 
373340d773SGleb Smirnoff #include <netdissect-stdinc.h>
384edb46e9SPaul Traina 
394edb46e9SPaul Traina #include <stdlib.h>
404edb46e9SPaul Traina #include <string.h>
414edb46e9SPaul Traina 
423340d773SGleb Smirnoff #include "netdissect.h"
434edb46e9SPaul Traina #include "addrtoname.h"
444edb46e9SPaul Traina #include "extract.h"
454edb46e9SPaul Traina 
46685295f4SBill Fenner #include "tcp.h"
47685295f4SBill Fenner 
48685295f4SBill Fenner #include "ip.h"
49685295f4SBill Fenner #include "ip6.h"
505b0fe478SBruce M Simpson #include "ipproto.h"
511de50e9fSSam Leffler #include "rpc_auth.h"
521de50e9fSSam Leffler #include "rpc_msg.h"
53685295f4SBill Fenner 
541de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
551de50e9fSSam Leffler #include <openssl/md5.h>
563340d773SGleb Smirnoff #include "signature.h"
571de50e9fSSam Leffler 
583c602fabSXin LI static int tcp_verify_signature(netdissect_options *ndo,
593c602fabSXin LI                                 const struct ip *ip, const struct tcphdr *tp,
601de50e9fSSam Leffler                                 const u_char *data, int length, const u_char *rcvsig);
611de50e9fSSam Leffler #endif
621de50e9fSSam Leffler 
633c602fabSXin LI static void print_tcp_rst_data(netdissect_options *, register const u_char *sp, u_int length);
643340d773SGleb Smirnoff static void print_tcp_fastopen_option(netdissect_options *ndo, register const u_char *cp,
653340d773SGleb Smirnoff                                       u_int datalen, int exp);
66685295f4SBill Fenner 
67685295f4SBill Fenner #define MAX_RST_DATA_LEN	30
68685295f4SBill Fenner 
69685295f4SBill Fenner 
704edb46e9SPaul Traina struct tha {
714edb46e9SPaul Traina         struct in_addr src;
724edb46e9SPaul Traina         struct in_addr dst;
734edb46e9SPaul Traina         u_int port;
744edb46e9SPaul Traina };
754edb46e9SPaul Traina 
764edb46e9SPaul Traina struct tcp_seq_hash {
774edb46e9SPaul Traina         struct tcp_seq_hash *nxt;
784edb46e9SPaul Traina         struct tha addr;
794edb46e9SPaul Traina         tcp_seq seq;
804edb46e9SPaul Traina         tcp_seq ack;
814edb46e9SPaul Traina };
824edb46e9SPaul Traina 
833c602fabSXin LI struct tha6 {
843c602fabSXin LI         struct in6_addr src;
853c602fabSXin LI         struct in6_addr dst;
863c602fabSXin LI         u_int port;
873c602fabSXin LI };
883c602fabSXin LI 
893c602fabSXin LI struct tcp_seq_hash6 {
903c602fabSXin LI         struct tcp_seq_hash6 *nxt;
913c602fabSXin LI         struct tha6 addr;
923c602fabSXin LI         tcp_seq seq;
933c602fabSXin LI         tcp_seq ack;
943c602fabSXin LI };
953c602fabSXin LI 
964edb46e9SPaul Traina #define TSEQ_HASHSIZE 919
974edb46e9SPaul Traina 
984edb46e9SPaul Traina /* These tcp optinos do not have the size octet */
994edb46e9SPaul Traina #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
1004edb46e9SPaul Traina 
1013c602fabSXin LI static struct tcp_seq_hash tcp_seq_hash4[TSEQ_HASHSIZE];
1023c602fabSXin LI static struct tcp_seq_hash6 tcp_seq_hash6[TSEQ_HASHSIZE];
1034edb46e9SPaul Traina 
1043c602fabSXin LI static const struct tok tcp_flag_values[] = {
105a5779b6eSRui Paulo         { TH_FIN, "F" },
106a5779b6eSRui Paulo         { TH_SYN, "S" },
107a5779b6eSRui Paulo         { TH_RST, "R" },
108a5779b6eSRui Paulo         { TH_PUSH, "P" },
109a5779b6eSRui Paulo         { TH_ACK, "." },
110a5779b6eSRui Paulo         { TH_URG, "U" },
111a5779b6eSRui Paulo         { TH_ECNECHO, "E" },
112a5779b6eSRui Paulo         { TH_CWR, "W" },
113a5779b6eSRui Paulo         { 0, NULL }
114a5779b6eSRui Paulo };
1154edb46e9SPaul Traina 
1163c602fabSXin LI static const struct tok tcp_option_values[] = {
117a5779b6eSRui Paulo         { TCPOPT_EOL, "eol" },
118a5779b6eSRui Paulo         { TCPOPT_NOP, "nop" },
119a5779b6eSRui Paulo         { TCPOPT_MAXSEG, "mss" },
120a5779b6eSRui Paulo         { TCPOPT_WSCALE, "wscale" },
121a5779b6eSRui Paulo         { TCPOPT_SACKOK, "sackOK" },
122a5779b6eSRui Paulo         { TCPOPT_SACK, "sack" },
123a5779b6eSRui Paulo         { TCPOPT_ECHO, "echo" },
124a5779b6eSRui Paulo         { TCPOPT_ECHOREPLY, "echoreply" },
125a5779b6eSRui Paulo         { TCPOPT_TIMESTAMP, "TS" },
126a5779b6eSRui Paulo         { TCPOPT_CC, "cc" },
127a5779b6eSRui Paulo         { TCPOPT_CCNEW, "ccnew" },
128a5779b6eSRui Paulo         { TCPOPT_CCECHO, "" },
129a5779b6eSRui Paulo         { TCPOPT_SIGNATURE, "md5" },
1303340d773SGleb Smirnoff         { TCPOPT_SCPS, "scps" },
131ce3ed1caSRui Paulo         { TCPOPT_UTO, "uto" },
1323340d773SGleb Smirnoff         { TCPOPT_TCPAO, "tcp-ao" },
1333c602fabSXin LI         { TCPOPT_MPTCP, "mptcp" },
1343340d773SGleb Smirnoff         { TCPOPT_FASTOPEN, "tfo" },
1353c602fabSXin LI         { TCPOPT_EXPERIMENT2, "exp" },
136a5779b6eSRui Paulo         { 0, NULL }
137a5779b6eSRui Paulo };
138685295f4SBill Fenner 
1393c602fabSXin LI static int
1403c602fabSXin LI tcp_cksum(netdissect_options *ndo,
1413c602fabSXin LI           register const struct ip *ip,
142685295f4SBill Fenner           register const struct tcphdr *tp,
1435b0fe478SBruce M Simpson           register u_int len)
144685295f4SBill Fenner {
1453c602fabSXin LI 	return nextproto4_cksum(ndo, ip, (const uint8_t *)tp, len, len,
1463c602fabSXin LI 				IPPROTO_TCP);
147685295f4SBill Fenner }
148685295f4SBill Fenner 
1493340d773SGleb Smirnoff static int
1503340d773SGleb Smirnoff tcp6_cksum(netdissect_options *ndo,
1513340d773SGleb Smirnoff            register const struct ip6_hdr *ip6,
1523340d773SGleb Smirnoff            register const struct tcphdr *tp,
1533340d773SGleb Smirnoff            register u_int len)
1543340d773SGleb Smirnoff {
1553340d773SGleb Smirnoff 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)tp, len, len,
1563340d773SGleb Smirnoff 				IPPROTO_TCP);
1573340d773SGleb Smirnoff }
1583340d773SGleb Smirnoff 
1594edb46e9SPaul Traina void
1603c602fabSXin LI tcp_print(netdissect_options *ndo,
1613c602fabSXin LI           register const u_char *bp, register u_int length,
162685295f4SBill Fenner           register const u_char *bp2, int fragmented)
1634edb46e9SPaul Traina {
1644edb46e9SPaul Traina         register const struct tcphdr *tp;
1654edb46e9SPaul Traina         register const struct ip *ip;
1664edb46e9SPaul Traina         register u_char flags;
1675b0fe478SBruce M Simpson         register u_int hlen;
1684edb46e9SPaul Traina         register char ch;
1693c602fabSXin LI         uint16_t sport, dport, win, urp;
1703c602fabSXin LI         uint32_t seq, ack, thseq, thack;
17127df3f5dSRui Paulo         u_int utoval;
1723c602fabSXin LI         uint16_t magic;
1733c602fabSXin LI         register int rev;
174b0453382SBill Fenner         register const struct ip6_hdr *ip6;
1754edb46e9SPaul Traina 
1763340d773SGleb Smirnoff         tp = (const struct tcphdr *)bp;
1773340d773SGleb Smirnoff         ip = (const struct ip *)bp2;
178685295f4SBill Fenner         if (IP_V(ip) == 6)
1793340d773SGleb Smirnoff                 ip6 = (const struct ip6_hdr *)bp2;
180b0453382SBill Fenner         else
181b0453382SBill Fenner                 ip6 = NULL;
1824edb46e9SPaul Traina         ch = '\0';
1833c602fabSXin LI         if (!ND_TTEST(tp->th_dport)) {
1843c602fabSXin LI                 ND_PRINT((ndo, "%s > %s: [|tcp]",
1853c602fabSXin LI                              ipaddr_string(ndo, &ip->ip_src),
1863c602fabSXin LI                              ipaddr_string(ndo, &ip->ip_dst)));
1874edb46e9SPaul Traina                 return;
1884edb46e9SPaul Traina         }
1894edb46e9SPaul Traina 
1905b0fe478SBruce M Simpson         sport = EXTRACT_16BITS(&tp->th_sport);
1915b0fe478SBruce M Simpson         dport = EXTRACT_16BITS(&tp->th_dport);
192b0453382SBill Fenner 
193b0453382SBill Fenner         if (ip6) {
194b0453382SBill Fenner                 if (ip6->ip6_nxt == IPPROTO_TCP) {
1953c602fabSXin LI                         ND_PRINT((ndo, "%s.%s > %s.%s: ",
1963c602fabSXin LI                                      ip6addr_string(ndo, &ip6->ip6_src),
1973340d773SGleb Smirnoff                                      tcpport_string(ndo, sport),
1983c602fabSXin LI                                      ip6addr_string(ndo, &ip6->ip6_dst),
1993340d773SGleb Smirnoff                                      tcpport_string(ndo, dport)));
200b0453382SBill Fenner                 } else {
2013c602fabSXin LI                         ND_PRINT((ndo, "%s > %s: ",
2023340d773SGleb Smirnoff                                      tcpport_string(ndo, sport), tcpport_string(ndo, dport)));
203b0453382SBill Fenner                 }
2043340d773SGleb Smirnoff         } else {
205b0453382SBill Fenner                 if (ip->ip_p == IPPROTO_TCP) {
2063c602fabSXin LI                         ND_PRINT((ndo, "%s.%s > %s.%s: ",
2073c602fabSXin LI                                      ipaddr_string(ndo, &ip->ip_src),
2083340d773SGleb Smirnoff                                      tcpport_string(ndo, sport),
2093c602fabSXin LI                                      ipaddr_string(ndo, &ip->ip_dst),
2103340d773SGleb Smirnoff                                      tcpport_string(ndo, dport)));
211b0453382SBill Fenner                 } else {
2123c602fabSXin LI                         ND_PRINT((ndo, "%s > %s: ",
2133340d773SGleb Smirnoff                                      tcpport_string(ndo, sport), tcpport_string(ndo, dport)));
214b0453382SBill Fenner                 }
215b0453382SBill Fenner         }
216b0453382SBill Fenner 
2173340d773SGleb Smirnoff         ND_TCHECK(*tp);
2183340d773SGleb Smirnoff 
2193340d773SGleb Smirnoff         hlen = TH_OFF(tp) * 4;
2203340d773SGleb Smirnoff 
2211de50e9fSSam Leffler         if (hlen < sizeof(*tp)) {
2223c602fabSXin LI                 ND_PRINT((ndo, " tcp %d [bad hdr length %u - too short, < %lu]",
2233c602fabSXin LI                              length - hlen, hlen, (unsigned long)sizeof(*tp)));
2241de50e9fSSam Leffler                 return;
2251de50e9fSSam Leffler         }
2261de50e9fSSam Leffler 
2275b0fe478SBruce M Simpson         seq = EXTRACT_32BITS(&tp->th_seq);
2285b0fe478SBruce M Simpson         ack = EXTRACT_32BITS(&tp->th_ack);
2295b0fe478SBruce M Simpson         win = EXTRACT_16BITS(&tp->th_win);
2305b0fe478SBruce M Simpson         urp = EXTRACT_16BITS(&tp->th_urp);
2314edb46e9SPaul Traina 
2323c602fabSXin LI         if (ndo->ndo_qflag) {
2333c602fabSXin LI                 ND_PRINT((ndo, "tcp %d", length - hlen));
2341de50e9fSSam Leffler                 if (hlen > length) {
2353c602fabSXin LI                         ND_PRINT((ndo, " [bad hdr length %u - too long, > %u]",
2363c602fabSXin LI                                      hlen, length));
2371de50e9fSSam Leffler                 }
2384edb46e9SPaul Traina                 return;
2394edb46e9SPaul Traina         }
240a5779b6eSRui Paulo 
241a5779b6eSRui Paulo         flags = tp->th_flags;
2423c602fabSXin LI         ND_PRINT((ndo, "Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags)));
2434edb46e9SPaul Traina 
2443c602fabSXin LI         if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
2454edb46e9SPaul Traina                 /*
2464edb46e9SPaul Traina                  * Find (or record) the initial sequence numbers for
2474edb46e9SPaul Traina                  * this conversation.  (we pick an arbitrary
2484edb46e9SPaul Traina                  * collating order so there's only one entry for
2494edb46e9SPaul Traina                  * both directions).
2504edb46e9SPaul Traina                  */
251b0453382SBill Fenner                 rev = 0;
252b0453382SBill Fenner                 if (ip6) {
2533c602fabSXin LI                         register struct tcp_seq_hash6 *th;
2543c602fabSXin LI                         struct tcp_seq_hash6 *tcp_seq_hash;
2553340d773SGleb Smirnoff                         const struct in6_addr *src, *dst;
2563c602fabSXin LI                         struct tha6 tha;
2573c602fabSXin LI 
2583c602fabSXin LI                         tcp_seq_hash = tcp_seq_hash6;
2595b0fe478SBruce M Simpson                         src = &ip6->ip6_src;
2605b0fe478SBruce M Simpson                         dst = &ip6->ip6_dst;
261a90e161bSBill Fenner                         if (sport > dport)
262b0453382SBill Fenner                                 rev = 1;
263a90e161bSBill Fenner                         else if (sport == dport) {
2643c602fabSXin LI                                 if (UNALIGNED_MEMCMP(src, dst, sizeof ip6->ip6_dst) > 0)
265b0453382SBill Fenner                                         rev = 1;
266b0453382SBill Fenner                         }
267b0453382SBill Fenner                         if (rev) {
2683c602fabSXin LI                                 UNALIGNED_MEMCPY(&tha.src, dst, sizeof ip6->ip6_dst);
2693c602fabSXin LI                                 UNALIGNED_MEMCPY(&tha.dst, src, sizeof ip6->ip6_src);
27039e421e8SCy Schubert                                 tha.port = ((u_int)dport) << 16 | sport;
271b0453382SBill Fenner                         } else {
2723c602fabSXin LI                                 UNALIGNED_MEMCPY(&tha.dst, dst, sizeof ip6->ip6_dst);
2733c602fabSXin LI                                 UNALIGNED_MEMCPY(&tha.src, src, sizeof ip6->ip6_src);
27439e421e8SCy Schubert                                 tha.port = ((u_int)sport) << 16 | dport;
275b0453382SBill Fenner                         }
2764edb46e9SPaul Traina 
2773c602fabSXin LI                         for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
2783c602fabSXin LI                              th->nxt; th = th->nxt)
2793c602fabSXin LI                                 if (memcmp((char *)&tha, (char *)&th->addr,
2803c602fabSXin LI                                            sizeof(th->addr)) == 0)
2813c602fabSXin LI                                         break;
2823c602fabSXin LI 
2833c602fabSXin LI                         if (!th->nxt || (flags & TH_SYN)) {
2843c602fabSXin LI                                 /* didn't find it or new conversation */
2853c602fabSXin LI                                 if (th->nxt == NULL) {
2863c602fabSXin LI                                         th->nxt = (struct tcp_seq_hash6 *)
2873c602fabSXin LI                                                 calloc(1, sizeof(*th));
2883c602fabSXin LI                                         if (th->nxt == NULL)
2893340d773SGleb Smirnoff                                                 (*ndo->ndo_error)(ndo,
2903340d773SGleb Smirnoff 								  "tcp_print: calloc");
2913c602fabSXin LI                                 }
2923c602fabSXin LI                                 th->addr = tha;
2933c602fabSXin LI                                 if (rev)
2943c602fabSXin LI                                         th->ack = seq, th->seq = ack - 1;
2953c602fabSXin LI                                 else
2963c602fabSXin LI                                         th->seq = seq, th->ack = ack - 1;
2973c602fabSXin LI                         } else {
2983c602fabSXin LI                                 if (rev)
2993c602fabSXin LI                                         seq -= th->ack, ack -= th->seq;
3003c602fabSXin LI                                 else
3013c602fabSXin LI                                         seq -= th->seq, ack -= th->ack;
3023c602fabSXin LI                         }
3033c602fabSXin LI 
3043c602fabSXin LI                         thseq = th->seq;
3053c602fabSXin LI                         thack = th->ack;
3063c602fabSXin LI                 } else {
3073c602fabSXin LI                         register struct tcp_seq_hash *th;
3083c602fabSXin LI                         struct tcp_seq_hash *tcp_seq_hash;
3093c602fabSXin LI                         struct tha tha;
3103c602fabSXin LI 
3113c602fabSXin LI                         tcp_seq_hash = tcp_seq_hash4;
3123c602fabSXin LI                         if (sport > dport)
3133c602fabSXin LI                                 rev = 1;
3143c602fabSXin LI                         else if (sport == dport) {
3153340d773SGleb Smirnoff                                 if (UNALIGNED_MEMCMP(&ip->ip_src, &ip->ip_dst, sizeof ip->ip_dst) > 0)
3163c602fabSXin LI                                         rev = 1;
3173c602fabSXin LI                         }
3183c602fabSXin LI                         if (rev) {
3193340d773SGleb Smirnoff                                 UNALIGNED_MEMCPY(&tha.src, &ip->ip_dst, sizeof ip->ip_dst);
3203340d773SGleb Smirnoff                                 UNALIGNED_MEMCPY(&tha.dst, &ip->ip_src, sizeof ip->ip_src);
32139e421e8SCy Schubert                                 tha.port = ((u_int)dport) << 16 | sport;
3223c602fabSXin LI                         } else {
3233340d773SGleb Smirnoff                                 UNALIGNED_MEMCPY(&tha.dst, &ip->ip_dst, sizeof ip->ip_dst);
3243340d773SGleb Smirnoff                                 UNALIGNED_MEMCPY(&tha.src, &ip->ip_src, sizeof ip->ip_src);
32539e421e8SCy Schubert                                 tha.port = ((u_int)sport) << 16 | dport;
3263c602fabSXin LI                         }
3273c602fabSXin LI 
3284edb46e9SPaul Traina                         for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
3294edb46e9SPaul Traina                              th->nxt; th = th->nxt)
3305b0fe478SBruce M Simpson                                 if (memcmp((char *)&tha, (char *)&th->addr,
3315b0fe478SBruce M Simpson                                            sizeof(th->addr)) == 0)
3324edb46e9SPaul Traina                                         break;
3334edb46e9SPaul Traina 
334685295f4SBill Fenner                         if (!th->nxt || (flags & TH_SYN)) {
3354edb46e9SPaul Traina                                 /* didn't find it or new conversation */
3364edb46e9SPaul Traina                                 if (th->nxt == NULL) {
3374edb46e9SPaul Traina                                         th->nxt = (struct tcp_seq_hash *)
3384edb46e9SPaul Traina                                                 calloc(1, sizeof(*th));
3394edb46e9SPaul Traina                                         if (th->nxt == NULL)
3403340d773SGleb Smirnoff                                                 (*ndo->ndo_error)(ndo,
3413340d773SGleb Smirnoff 								  "tcp_print: calloc");
3424edb46e9SPaul Traina                                 }
3434edb46e9SPaul Traina                                 th->addr = tha;
3444edb46e9SPaul Traina                                 if (rev)
3454edb46e9SPaul Traina                                         th->ack = seq, th->seq = ack - 1;
3464edb46e9SPaul Traina                                 else
3474edb46e9SPaul Traina                                         th->seq = seq, th->ack = ack - 1;
3484edb46e9SPaul Traina                         } else {
3494edb46e9SPaul Traina                                 if (rev)
3504edb46e9SPaul Traina                                         seq -= th->ack, ack -= th->seq;
3514edb46e9SPaul Traina                                 else
3524edb46e9SPaul Traina                                         seq -= th->seq, ack -= th->ack;
3534edb46e9SPaul Traina                         }
354685295f4SBill Fenner 
355685295f4SBill Fenner                         thseq = th->seq;
356685295f4SBill Fenner                         thack = th->ack;
3573c602fabSXin LI                 }
358685295f4SBill Fenner         } else {
359685295f4SBill Fenner                 /*fool gcc*/
3603c602fabSXin LI                 thseq = thack = rev = 0;
3614edb46e9SPaul Traina         }
3624de76e31SBill Fenner         if (hlen > length) {
3633c602fabSXin LI                 ND_PRINT((ndo, " [bad hdr length %u - too long, > %u]",
3643c602fabSXin LI                              hlen, length));
3654de76e31SBill Fenner                 return;
3664de76e31SBill Fenner         }
367685295f4SBill Fenner 
3683c602fabSXin LI         if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
369cac3dcd5SXin LI                 /* Check the checksum, if possible. */
3703c602fabSXin LI                 uint16_t sum, tcp_sum;
371cac3dcd5SXin LI 
372cac3dcd5SXin LI                 if (IP_V(ip) == 4) {
3733c602fabSXin LI                         if (ND_TTEST2(tp->th_sport, length)) {
3743c602fabSXin LI                                 sum = tcp_cksum(ndo, ip, tp, length);
3755b0fe478SBruce M Simpson                                 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
376cac3dcd5SXin LI 
3773c602fabSXin LI                                 ND_PRINT((ndo, ", cksum 0x%04x", tcp_sum));
378cac3dcd5SXin LI                                 if (sum != 0)
3793c602fabSXin LI                                         ND_PRINT((ndo, " (incorrect -> 0x%04x)",
3803c602fabSXin LI                                             in_cksum_shouldbe(tcp_sum, sum)));
381cac3dcd5SXin LI                                 else
3823c602fabSXin LI                                         ND_PRINT((ndo, " (correct)"));
383685295f4SBill Fenner                         }
3843340d773SGleb Smirnoff                 } else if (IP_V(ip) == 6 && ip6->ip6_plen) {
3853c602fabSXin LI                         if (ND_TTEST2(tp->th_sport, length)) {
3863340d773SGleb Smirnoff                                 sum = tcp6_cksum(ndo, ip6, tp, length);
3871de50e9fSSam Leffler                                 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
388cac3dcd5SXin LI 
3893c602fabSXin LI                                 ND_PRINT((ndo, ", cksum 0x%04x", tcp_sum));
390cac3dcd5SXin LI                                 if (sum != 0)
3913c602fabSXin LI                                         ND_PRINT((ndo, " (incorrect -> 0x%04x)",
3923c602fabSXin LI                                             in_cksum_shouldbe(tcp_sum, sum)));
393cac3dcd5SXin LI                                 else
3943c602fabSXin LI                                         ND_PRINT((ndo, " (correct)"));
3951de50e9fSSam Leffler 
396685295f4SBill Fenner                         }
397685295f4SBill Fenner                 }
398cac3dcd5SXin LI         }
399685295f4SBill Fenner 
4004edb46e9SPaul Traina         length -= hlen;
4013c602fabSXin LI         if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
4023c602fabSXin LI                 ND_PRINT((ndo, ", seq %u", seq));
4034edb46e9SPaul Traina 
404a5779b6eSRui Paulo                 if (length > 0) {
4053c602fabSXin LI                         ND_PRINT((ndo, ":%u", seq + length));
406a5779b6eSRui Paulo                 }
407a5779b6eSRui Paulo         }
408a5779b6eSRui Paulo 
409a5779b6eSRui Paulo         if (flags & TH_ACK) {
4103c602fabSXin LI                 ND_PRINT((ndo, ", ack %u", ack));
411a5779b6eSRui Paulo         }
412a5779b6eSRui Paulo 
4133c602fabSXin LI         ND_PRINT((ndo, ", win %d", win));
4144edb46e9SPaul Traina 
4154edb46e9SPaul Traina         if (flags & TH_URG)
4163c602fabSXin LI                 ND_PRINT((ndo, ", urg %d", urp));
4174edb46e9SPaul Traina         /*
4184edb46e9SPaul Traina          * Handle any options.
4194edb46e9SPaul Traina          */
4205b0fe478SBruce M Simpson         if (hlen > sizeof(*tp)) {
4214edb46e9SPaul Traina                 register const u_char *cp;
4225b0fe478SBruce M Simpson                 register u_int i, opt, datalen;
4235b0fe478SBruce M Simpson                 register u_int len;
4244edb46e9SPaul Traina 
4255b0fe478SBruce M Simpson                 hlen -= sizeof(*tp);
4264edb46e9SPaul Traina                 cp = (const u_char *)tp + sizeof(*tp);
4273c602fabSXin LI                 ND_PRINT((ndo, ", options ["));
4284edb46e9SPaul Traina                 while (hlen > 0) {
429a5779b6eSRui Paulo                         if (ch != '\0')
4303c602fabSXin LI                                 ND_PRINT((ndo, "%c", ch));
4313c602fabSXin LI                         ND_TCHECK(*cp);
4324edb46e9SPaul Traina                         opt = *cp++;
4334edb46e9SPaul Traina                         if (ZEROLENOPT(opt))
4344edb46e9SPaul Traina                                 len = 1;
4354edb46e9SPaul Traina                         else {
4363c602fabSXin LI                                 ND_TCHECK(*cp);
4374de76e31SBill Fenner                                 len = *cp++;	/* total including type, len */
4384de76e31SBill Fenner                                 if (len < 2 || len > hlen)
4394de76e31SBill Fenner                                         goto bad;
4404de76e31SBill Fenner                                 --hlen;		/* account for length byte */
4414edb46e9SPaul Traina                         }
4424de76e31SBill Fenner                         --hlen;			/* account for type byte */
4434edb46e9SPaul Traina                         datalen = 0;
4444de76e31SBill Fenner 
4454de76e31SBill Fenner /* Bail if "l" bytes of data are not left or were not captured  */
4463c602fabSXin LI #define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK2(*cp, l); }
4474de76e31SBill Fenner 
448a5779b6eSRui Paulo 
4493c602fabSXin LI                         ND_PRINT((ndo, "%s", tok2str(tcp_option_values, "unknown-%u", opt)));
450a5779b6eSRui Paulo 
4514edb46e9SPaul Traina                         switch (opt) {
4524edb46e9SPaul Traina 
4534edb46e9SPaul Traina                         case TCPOPT_MAXSEG:
4544edb46e9SPaul Traina                                 datalen = 2;
4554de76e31SBill Fenner                                 LENCHECK(datalen);
4563c602fabSXin LI                                 ND_PRINT((ndo, " %u", EXTRACT_16BITS(cp)));
4574edb46e9SPaul Traina                                 break;
4584edb46e9SPaul Traina 
4594edb46e9SPaul Traina                         case TCPOPT_WSCALE:
4604edb46e9SPaul Traina                                 datalen = 1;
4614de76e31SBill Fenner                                 LENCHECK(datalen);
4623c602fabSXin LI                                 ND_PRINT((ndo, " %u", *cp));
4634edb46e9SPaul Traina                                 break;
4644edb46e9SPaul Traina 
4654edb46e9SPaul Traina                         case TCPOPT_SACK:
4664edb46e9SPaul Traina                                 datalen = len - 2;
467b0453382SBill Fenner                                 if (datalen % 8 != 0) {
4683340d773SGleb Smirnoff                                         ND_PRINT((ndo, " invalid sack"));
469b0453382SBill Fenner                                 } else {
4703c602fabSXin LI                                         uint32_t s, e;
471b0453382SBill Fenner 
4723c602fabSXin LI                                         ND_PRINT((ndo, " %d ", datalen / 8));
473b0453382SBill Fenner                                         for (i = 0; i < datalen; i += 8) {
4744de76e31SBill Fenner                                                 LENCHECK(i + 4);
475b0453382SBill Fenner                                                 s = EXTRACT_32BITS(cp + i);
476b0453382SBill Fenner                                                 LENCHECK(i + 8);
477b0453382SBill Fenner                                                 e = EXTRACT_32BITS(cp + i + 4);
4783c602fabSXin LI                                                 if (rev) {
479b0453382SBill Fenner                                                         s -= thseq;
480b0453382SBill Fenner                                                         e -= thseq;
481b0453382SBill Fenner                                                 } else {
482b0453382SBill Fenner                                                         s -= thack;
483b0453382SBill Fenner                                                         e -= thack;
4844edb46e9SPaul Traina                                                 }
4853c602fabSXin LI                                                 ND_PRINT((ndo, "{%u:%u}", s, e));
486b0453382SBill Fenner                                         }
487b0453382SBill Fenner                                 }
4884edb46e9SPaul Traina                                 break;
4894edb46e9SPaul Traina 
490a5779b6eSRui Paulo                         case TCPOPT_CC:
491a5779b6eSRui Paulo                         case TCPOPT_CCNEW:
492a5779b6eSRui Paulo                         case TCPOPT_CCECHO:
4934edb46e9SPaul Traina                         case TCPOPT_ECHO:
4944edb46e9SPaul Traina                         case TCPOPT_ECHOREPLY:
495a5779b6eSRui Paulo 
496a5779b6eSRui Paulo                                 /*
497a5779b6eSRui Paulo                                  * those options share their semantics.
498a5779b6eSRui Paulo                                  * fall through
499a5779b6eSRui Paulo                                  */
5004edb46e9SPaul Traina                                 datalen = 4;
5014de76e31SBill Fenner                                 LENCHECK(datalen);
5023c602fabSXin LI                                 ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
5034edb46e9SPaul Traina                                 break;
5044edb46e9SPaul Traina 
5054edb46e9SPaul Traina                         case TCPOPT_TIMESTAMP:
5064de76e31SBill Fenner                                 datalen = 8;
5074de76e31SBill Fenner                                 LENCHECK(datalen);
5083c602fabSXin LI                                 ND_PRINT((ndo, " val %u ecr %u",
509a5779b6eSRui Paulo                                              EXTRACT_32BITS(cp),
5103c602fabSXin LI                                              EXTRACT_32BITS(cp + 4)));
5114edb46e9SPaul Traina                                 break;
5124edb46e9SPaul Traina 
5131de50e9fSSam Leffler                         case TCPOPT_SIGNATURE:
5141de50e9fSSam Leffler                                 datalen = TCP_SIGLEN;
5151de50e9fSSam Leffler                                 LENCHECK(datalen);
5163340d773SGleb Smirnoff                                 ND_PRINT((ndo, " "));
5171de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
5183c602fabSXin LI                                 switch (tcp_verify_signature(ndo, ip, tp,
5191de50e9fSSam Leffler                                                              bp + TH_OFF(tp) * 4, length, cp)) {
5201de50e9fSSam Leffler 
5211de50e9fSSam Leffler                                 case SIGNATURE_VALID:
5223c602fabSXin LI                                         ND_PRINT((ndo, "valid"));
5231de50e9fSSam Leffler                                         break;
5241de50e9fSSam Leffler 
5251de50e9fSSam Leffler                                 case SIGNATURE_INVALID:
5263c602fabSXin LI                                         ND_PRINT((ndo, "invalid"));
5271de50e9fSSam Leffler                                         break;
5281de50e9fSSam Leffler 
5291de50e9fSSam Leffler                                 case CANT_CHECK_SIGNATURE:
5303c602fabSXin LI                                         ND_PRINT((ndo, "can't check - "));
5311de50e9fSSam Leffler                                         for (i = 0; i < TCP_SIGLEN; ++i)
5323c602fabSXin LI                                                 ND_PRINT((ndo, "%02x", cp[i]));
5331de50e9fSSam Leffler                                         break;
5341de50e9fSSam Leffler                                 }
5351de50e9fSSam Leffler #else
5361de50e9fSSam Leffler                                 for (i = 0; i < TCP_SIGLEN; ++i)
5373c602fabSXin LI                                         ND_PRINT((ndo, "%02x", cp[i]));
5381de50e9fSSam Leffler #endif
5391de50e9fSSam Leffler                                 break;
5401de50e9fSSam Leffler 
5413340d773SGleb Smirnoff                         case TCPOPT_SCPS:
5423340d773SGleb Smirnoff                                 datalen = 2;
5433340d773SGleb Smirnoff                                 LENCHECK(datalen);
5443340d773SGleb Smirnoff                                 ND_PRINT((ndo, " cap %02x id %u", cp[0], cp[1]));
545a5779b6eSRui Paulo                                 break;
546a5779b6eSRui Paulo 
5473340d773SGleb Smirnoff                         case TCPOPT_TCPAO:
5483340d773SGleb Smirnoff                                 datalen = len - 2;
5493340d773SGleb Smirnoff                                 /* RFC 5925 Section 2.2:
5503340d773SGleb Smirnoff                                  * "The Length value MUST be greater than or equal to 4."
5513340d773SGleb Smirnoff                                  * (This includes the Kind and Length fields already processed
5523340d773SGleb Smirnoff                                  * at this point.)
5533340d773SGleb Smirnoff                                  */
5543340d773SGleb Smirnoff                                 if (datalen < 2) {
5553340d773SGleb Smirnoff                                         ND_PRINT((ndo, " invalid"));
5563340d773SGleb Smirnoff                                 } else {
5573340d773SGleb Smirnoff                                         LENCHECK(1);
5583340d773SGleb Smirnoff                                         ND_PRINT((ndo, " keyid %u", cp[0]));
5593340d773SGleb Smirnoff                                         LENCHECK(2);
5603340d773SGleb Smirnoff                                         ND_PRINT((ndo, " rnextkeyid %u", cp[1]));
5613340d773SGleb Smirnoff                                         if (datalen > 2) {
5623340d773SGleb Smirnoff                                                 ND_PRINT((ndo, " mac 0x"));
5633340d773SGleb Smirnoff                                                 for (i = 2; i < datalen; i++) {
5643340d773SGleb Smirnoff                                                         LENCHECK(i + 1);
5653340d773SGleb Smirnoff                                                         ND_PRINT((ndo, "%02x", cp[i]));
5663340d773SGleb Smirnoff                                                 }
5673340d773SGleb Smirnoff                                         }
5683340d773SGleb Smirnoff                                 }
5693340d773SGleb Smirnoff                                 break;
570a5779b6eSRui Paulo 
571a5779b6eSRui Paulo                         case TCPOPT_EOL:
572a5779b6eSRui Paulo                         case TCPOPT_NOP:
573a5779b6eSRui Paulo                         case TCPOPT_SACKOK:
574a5779b6eSRui Paulo                                 /*
575a5779b6eSRui Paulo                                  * Nothing interesting.
576a5779b6eSRui Paulo                                  * fall through
577a5779b6eSRui Paulo                                  */
578a5779b6eSRui Paulo                                 break;
579a5779b6eSRui Paulo 
580ce3ed1caSRui Paulo                         case TCPOPT_UTO:
581ce3ed1caSRui Paulo                                 datalen = 2;
582ce3ed1caSRui Paulo                                 LENCHECK(datalen);
58327df3f5dSRui Paulo                                 utoval = EXTRACT_16BITS(cp);
5843c602fabSXin LI                                 ND_PRINT((ndo, " 0x%x", utoval));
585ce3ed1caSRui Paulo                                 if (utoval & 0x0001)
586ce3ed1caSRui Paulo                                         utoval = (utoval >> 1) * 60;
587ce3ed1caSRui Paulo                                 else
588ce3ed1caSRui Paulo                                         utoval >>= 1;
5893c602fabSXin LI                                 ND_PRINT((ndo, " %u", utoval));
5903c602fabSXin LI                                 break;
5913c602fabSXin LI 
5923c602fabSXin LI                         case TCPOPT_MPTCP:
5933c602fabSXin LI                                 datalen = len - 2;
5943c602fabSXin LI                                 LENCHECK(datalen);
5953c602fabSXin LI                                 if (!mptcp_print(ndo, cp-2, len, flags))
5963c602fabSXin LI                                         goto bad;
5973c602fabSXin LI                                 break;
5983c602fabSXin LI 
5993340d773SGleb Smirnoff                         case TCPOPT_FASTOPEN:
6003340d773SGleb Smirnoff                                 datalen = len - 2;
6013340d773SGleb Smirnoff                                 LENCHECK(datalen);
6023340d773SGleb Smirnoff                                 ND_PRINT((ndo, " "));
6033340d773SGleb Smirnoff                                 print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
6043340d773SGleb Smirnoff                                 break;
6053340d773SGleb Smirnoff 
6063c602fabSXin LI                         case TCPOPT_EXPERIMENT2:
6073c602fabSXin LI                                 datalen = len - 2;
6083c602fabSXin LI                                 LENCHECK(datalen);
6093c602fabSXin LI                                 if (datalen < 2)
6103c602fabSXin LI                                         goto bad;
6113c602fabSXin LI                                 /* RFC6994 */
6123c602fabSXin LI                                 magic = EXTRACT_16BITS(cp);
6133c602fabSXin LI                                 ND_PRINT((ndo, "-"));
6143c602fabSXin LI 
6153c602fabSXin LI                                 switch(magic) {
6163c602fabSXin LI 
6173340d773SGleb Smirnoff                                 case 0xf989: /* TCP Fast Open RFC 7413 */
6183340d773SGleb Smirnoff                                         print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
6193c602fabSXin LI                                         break;
6203c602fabSXin LI 
6213c602fabSXin LI                                 default:
6223c602fabSXin LI                                         /* Unknown magic number */
6233c602fabSXin LI                                         ND_PRINT((ndo, "%04x", magic));
6243c602fabSXin LI                                         break;
6253c602fabSXin LI                                 }
626ce3ed1caSRui Paulo                                 break;
627ce3ed1caSRui Paulo 
6284edb46e9SPaul Traina                         default:
6294edb46e9SPaul Traina                                 datalen = len - 2;
6303c602fabSXin LI                                 if (datalen)
6313c602fabSXin LI                                         ND_PRINT((ndo, " 0x"));
6324edb46e9SPaul Traina                                 for (i = 0; i < datalen; ++i) {
6333340d773SGleb Smirnoff                                         LENCHECK(i + 1);
6343c602fabSXin LI                                         ND_PRINT((ndo, "%02x", cp[i]));
6354edb46e9SPaul Traina                                 }
6364edb46e9SPaul Traina                                 break;
6374edb46e9SPaul Traina                         }
6384edb46e9SPaul Traina 
6394edb46e9SPaul Traina                         /* Account for data printed */
6404edb46e9SPaul Traina                         cp += datalen;
6414edb46e9SPaul Traina                         hlen -= datalen;
6424edb46e9SPaul Traina 
6434edb46e9SPaul Traina                         /* Check specification against observed length */
6444edb46e9SPaul Traina                         ++datalen;			/* option octet */
6454edb46e9SPaul Traina                         if (!ZEROLENOPT(opt))
6464edb46e9SPaul Traina                                 ++datalen;		/* size octet */
6474edb46e9SPaul Traina                         if (datalen != len)
6483c602fabSXin LI                                 ND_PRINT((ndo, "[len %d]", len));
6494edb46e9SPaul Traina                         ch = ',';
6504de76e31SBill Fenner                         if (opt == TCPOPT_EOL)
6514de76e31SBill Fenner                                 break;
6524edb46e9SPaul Traina                 }
6533c602fabSXin LI                 ND_PRINT((ndo, "]"));
6544edb46e9SPaul Traina         }
655b0453382SBill Fenner 
656a5779b6eSRui Paulo         /*
657a5779b6eSRui Paulo          * Print length field before crawling down the stack.
658a5779b6eSRui Paulo          */
6593c602fabSXin LI         ND_PRINT((ndo, ", length %u", length));
660a5779b6eSRui Paulo 
661b0453382SBill Fenner         if (length <= 0)
662b0453382SBill Fenner                 return;
663b0453382SBill Fenner 
664b0453382SBill Fenner         /*
665b0453382SBill Fenner          * Decode payload if necessary.
666b0453382SBill Fenner          */
667685295f4SBill Fenner         bp += TH_OFF(tp) * 4;
6683c602fabSXin LI         if ((flags & TH_RST) && ndo->ndo_vflag) {
6693c602fabSXin LI                 print_tcp_rst_data(ndo, bp, length);
670a5779b6eSRui Paulo                 return;
671a5779b6eSRui Paulo         }
672a5779b6eSRui Paulo 
6733c602fabSXin LI         if (ndo->ndo_packettype) {
6743c602fabSXin LI                 switch (ndo->ndo_packettype) {
675d03c0883SXin LI                 case PT_ZMTP1:
6763c602fabSXin LI                         zmtp1_print(ndo, bp, length);
677d03c0883SXin LI                         break;
6783340d773SGleb Smirnoff                 case PT_RESP:
6793340d773SGleb Smirnoff                         resp_print(ndo, bp, length);
6803340d773SGleb Smirnoff                         break;
681d03c0883SXin LI                 }
682d03c0883SXin LI                 return;
683d03c0883SXin LI         }
684d03c0883SXin LI 
6853340d773SGleb Smirnoff         if (IS_SRC_OR_DST_PORT(TELNET_PORT)) {
6863c602fabSXin LI                 telnet_print(ndo, bp, length);
6873340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(SMTP_PORT)) {
6888bdc5a62SPatrick Kelsey                 ND_PRINT((ndo, ": "));
6898bdc5a62SPatrick Kelsey                 smtp_print(ndo, bp, length);
6903340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(BGP_PORT))
6913c602fabSXin LI                 bgp_print(ndo, bp, length);
6923340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(PPTP_PORT))
6933c602fabSXin LI                 pptp_print(ndo, bp);
6943340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(REDIS_PORT))
6953340d773SGleb Smirnoff                 resp_print(ndo, bp, length);
6963340d773SGleb Smirnoff #ifdef ENABLE_SMB
6973340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(NETBIOS_SSN_PORT))
6983c602fabSXin LI                 nbt_tcp_print(ndo, bp, length);
6993340d773SGleb Smirnoff 	else if (IS_SRC_OR_DST_PORT(SMB_PORT))
7003c602fabSXin LI 		smb_tcp_print(ndo, bp, length);
701a90e161bSBill Fenner #endif
7023340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(BEEP_PORT))
7033c602fabSXin LI                 beep_print(ndo, bp, length);
7043340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(OPENFLOW_PORT_OLD) || IS_SRC_OR_DST_PORT(OPENFLOW_PORT_IANA))
7053c602fabSXin LI                 openflow_print(ndo, bp, length);
7063340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(FTP_PORT)) {
7078bdc5a62SPatrick Kelsey                 ND_PRINT((ndo, ": "));
7088bdc5a62SPatrick Kelsey                 ftp_print(ndo, bp, length);
7093340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(HTTP_PORT) || IS_SRC_OR_DST_PORT(HTTP_PORT_ALT)) {
7108bdc5a62SPatrick Kelsey                 ND_PRINT((ndo, ": "));
7118bdc5a62SPatrick Kelsey                 http_print(ndo, bp, length);
7123340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(RTSP_PORT) || IS_SRC_OR_DST_PORT(RTSP_PORT_ALT)) {
7138bdc5a62SPatrick Kelsey                 ND_PRINT((ndo, ": "));
7148bdc5a62SPatrick Kelsey                 rtsp_print(ndo, bp, length);
7158bdc5a62SPatrick Kelsey         } else if (length > 2 &&
7163340d773SGleb Smirnoff                  (IS_SRC_OR_DST_PORT(NAMESERVER_PORT))) {
71739e421e8SCy Schubert                 /* domain_print() assumes it does not have to prepend a space before its
71839e421e8SCy Schubert                  * own output to separate it from the output of the calling function. This
71939e421e8SCy Schubert                  * works well with udp_print(), but requires a small prop here.
72039e421e8SCy Schubert                  */
72139e421e8SCy Schubert                 ND_PRINT((ndo, " "));
72239e421e8SCy Schubert 
723a90e161bSBill Fenner                 /*
724a90e161bSBill Fenner                  * TCP DNS query has 2byte length at the head.
725a90e161bSBill Fenner                  * XXX packet could be unaligned, it can go strange
726a90e161bSBill Fenner                  */
7273c602fabSXin LI                 ns_print(ndo, bp + 2, length - 2, 0);
7283340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(MSDP_PORT)) {
7293c602fabSXin LI                 msdp_print(ndo, bp, length);
7303340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(RPKI_RTR_PORT)) {
7313c602fabSXin LI                 rpki_rtr_print(ndo, bp, length);
732a90e161bSBill Fenner         }
7333340d773SGleb Smirnoff         else if (length > 0 && (IS_SRC_OR_DST_PORT(LDP_PORT))) {
7343c602fabSXin LI                 ldp_print(ndo, bp, length);
7353c602fabSXin LI         }
7363340d773SGleb Smirnoff         else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
7373c602fabSXin LI                  length >= 4 && ND_TTEST2(*bp, 4)) {
7383c602fabSXin LI                 /*
7393c602fabSXin LI                  * If data present, header length valid, and NFS port used,
7403c602fabSXin LI                  * assume NFS.
7413c602fabSXin LI                  * Pass offset of data plus 4 bytes for RPC TCP msg length
7423c602fabSXin LI                  * to NFS print routines.
7433c602fabSXin LI                  */
7443c602fabSXin LI                 uint32_t fraglen;
7453340d773SGleb Smirnoff                 register const struct sunrpc_msg *rp;
7463c602fabSXin LI                 enum sunrpc_msg_type direction;
7473c602fabSXin LI 
7483c602fabSXin LI                 fraglen = EXTRACT_32BITS(bp) & 0x7FFFFFFF;
7493c602fabSXin LI                 if (fraglen > (length) - 4)
7503c602fabSXin LI                         fraglen = (length) - 4;
7513340d773SGleb Smirnoff                 rp = (const struct sunrpc_msg *)(bp + 4);
7523c602fabSXin LI                 if (ND_TTEST(rp->rm_direction)) {
7533c602fabSXin LI                         direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction);
7543c602fabSXin LI                         if (dport == NFS_PORT && direction == SUNRPC_CALL) {
7553c602fabSXin LI                                 ND_PRINT((ndo, ": NFS request xid %u ", EXTRACT_32BITS(&rp->rm_xid)));
7563340d773SGleb Smirnoff                                 nfsreq_print_noaddr(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
7573c602fabSXin LI                                 return;
7583c602fabSXin LI                         }
7593c602fabSXin LI                         if (sport == NFS_PORT && direction == SUNRPC_REPLY) {
7603c602fabSXin LI                                 ND_PRINT((ndo, ": NFS reply xid %u ", EXTRACT_32BITS(&rp->rm_xid)));
7613340d773SGleb Smirnoff                                 nfsreply_print_noaddr(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
7623c602fabSXin LI                                 return;
7633c602fabSXin LI                         }
7643c602fabSXin LI                 }
7651de50e9fSSam Leffler         }
766a5779b6eSRui Paulo 
7674edb46e9SPaul Traina         return;
7684de76e31SBill Fenner  bad:
7693c602fabSXin LI         ND_PRINT((ndo, "[bad opt]"));
7704de76e31SBill Fenner         if (ch != '\0')
7713c602fabSXin LI                 ND_PRINT((ndo, ">"));
7724de76e31SBill Fenner         return;
7734edb46e9SPaul Traina  trunc:
7743c602fabSXin LI         ND_PRINT((ndo, "[|tcp]"));
7754edb46e9SPaul Traina         if (ch != '\0')
7763c602fabSXin LI                 ND_PRINT((ndo, ">"));
7774edb46e9SPaul Traina }
7784edb46e9SPaul Traina 
779685295f4SBill Fenner /*
780685295f4SBill Fenner  * RFC1122 says the following on data in RST segments:
781685295f4SBill Fenner  *
782685295f4SBill Fenner  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
783685295f4SBill Fenner  *
784685295f4SBill Fenner  *            A TCP SHOULD allow a received RST segment to include data.
785685295f4SBill Fenner  *
786685295f4SBill Fenner  *            DISCUSSION
787685295f4SBill Fenner  *                 It has been suggested that a RST segment could contain
788685295f4SBill Fenner  *                 ASCII text that encoded and explained the cause of the
789685295f4SBill Fenner  *                 RST.  No standard has yet been established for such
790685295f4SBill Fenner  *                 data.
791685295f4SBill Fenner  *
792685295f4SBill Fenner  */
793685295f4SBill Fenner 
794685295f4SBill Fenner static void
7953c602fabSXin LI print_tcp_rst_data(netdissect_options *ndo,
7963c602fabSXin LI                    register const u_char *sp, u_int length)
797685295f4SBill Fenner {
798685295f4SBill Fenner         int c;
799685295f4SBill Fenner 
8003c602fabSXin LI         ND_PRINT((ndo, ND_TTEST2(*sp, length) ? " [RST" : " [!RST"));
801685295f4SBill Fenner         if (length > MAX_RST_DATA_LEN) {
802685295f4SBill Fenner                 length = MAX_RST_DATA_LEN;	/* can use -X for longer */
8033c602fabSXin LI                 ND_PRINT((ndo, "+"));			/* indicate we truncate */
804685295f4SBill Fenner         }
8053c602fabSXin LI         ND_PRINT((ndo, " "));
8063340d773SGleb Smirnoff         while (length-- && sp < ndo->ndo_snapend) {
807685295f4SBill Fenner                 c = *sp++;
8083c602fabSXin LI                 safeputchar(ndo, c);
809685295f4SBill Fenner         }
8103c602fabSXin LI         ND_PRINT((ndo, "]"));
811685295f4SBill Fenner }
8121de50e9fSSam Leffler 
8133340d773SGleb Smirnoff static void
8143340d773SGleb Smirnoff print_tcp_fastopen_option(netdissect_options *ndo, register const u_char *cp,
8153340d773SGleb Smirnoff                           u_int datalen, int exp)
8163340d773SGleb Smirnoff {
8173340d773SGleb Smirnoff         u_int i;
8183340d773SGleb Smirnoff 
8193340d773SGleb Smirnoff         if (exp)
8203340d773SGleb Smirnoff                 ND_PRINT((ndo, "tfo"));
8213340d773SGleb Smirnoff 
8223340d773SGleb Smirnoff         if (datalen == 0) {
8233340d773SGleb Smirnoff                 /* Fast Open Cookie Request */
8243340d773SGleb Smirnoff                 ND_PRINT((ndo, " cookiereq"));
8253340d773SGleb Smirnoff         } else {
8263340d773SGleb Smirnoff                 /* Fast Open Cookie */
8273340d773SGleb Smirnoff                 if (datalen % 2 != 0 || datalen < 4 || datalen > 16) {
8283340d773SGleb Smirnoff                         ND_PRINT((ndo, " invalid"));
8293340d773SGleb Smirnoff                 } else {
8303340d773SGleb Smirnoff                         ND_PRINT((ndo, " cookie "));
8313340d773SGleb Smirnoff                         for (i = 0; i < datalen; ++i)
8323340d773SGleb Smirnoff                                 ND_PRINT((ndo, "%02x", cp[i]));
8333340d773SGleb Smirnoff                 }
8343340d773SGleb Smirnoff         }
8353340d773SGleb Smirnoff }
8363340d773SGleb Smirnoff 
8371de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
8383c602fabSXin LI USES_APPLE_DEPRECATED_API
8391de50e9fSSam Leffler static int
8403c602fabSXin LI tcp_verify_signature(netdissect_options *ndo,
8413c602fabSXin LI                      const struct ip *ip, const struct tcphdr *tp,
8421de50e9fSSam Leffler                      const u_char *data, int length, const u_char *rcvsig)
8431de50e9fSSam Leffler {
8441de50e9fSSam Leffler         struct tcphdr tp1;
845f4d0c64aSSam Leffler         u_char sig[TCP_SIGLEN];
8461de50e9fSSam Leffler         char zero_proto = 0;
8471de50e9fSSam Leffler         MD5_CTX ctx;
8483c602fabSXin LI         uint16_t savecsum, tlen;
8493340d773SGleb Smirnoff         const struct ip6_hdr *ip6;
8503c602fabSXin LI         uint32_t len32;
8513c602fabSXin LI         uint8_t nxt;
8521de50e9fSSam Leffler 
8533c602fabSXin LI 	if (data + length > ndo->ndo_snapend) {
8543c602fabSXin LI 		ND_PRINT((ndo, "snaplen too short, "));
85527df3f5dSRui Paulo 		return (CANT_CHECK_SIGNATURE);
85627df3f5dSRui Paulo 	}
85727df3f5dSRui Paulo 
8581de50e9fSSam Leffler         tp1 = *tp;
8591de50e9fSSam Leffler 
8603c602fabSXin LI         if (ndo->ndo_sigsecret == NULL) {
8613c602fabSXin LI 		ND_PRINT((ndo, "shared secret not supplied with -M, "));
8621de50e9fSSam Leffler                 return (CANT_CHECK_SIGNATURE);
86327df3f5dSRui Paulo         }
8641de50e9fSSam Leffler 
8651de50e9fSSam Leffler         MD5_Init(&ctx);
8661de50e9fSSam Leffler         /*
8671de50e9fSSam Leffler          * Step 1: Update MD5 hash with IP pseudo-header.
8681de50e9fSSam Leffler          */
8691de50e9fSSam Leffler         if (IP_V(ip) == 4) {
8703340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip->ip_src, sizeof(ip->ip_src));
8713340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip->ip_dst, sizeof(ip->ip_dst));
8723340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&zero_proto, sizeof(zero_proto));
8733340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip->ip_p, sizeof(ip->ip_p));
8741de50e9fSSam Leffler                 tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4;
8751de50e9fSSam Leffler                 tlen = htons(tlen);
8763340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&tlen, sizeof(tlen));
8771de50e9fSSam Leffler         } else if (IP_V(ip) == 6) {
8783340d773SGleb Smirnoff                 ip6 = (const struct ip6_hdr *)ip;
8793340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
8803340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
88127df3f5dSRui Paulo                 len32 = htonl(EXTRACT_16BITS(&ip6->ip6_plen));
8823340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&len32, sizeof(len32));
8831de50e9fSSam Leffler                 nxt = 0;
8843340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
8853340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
8863340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
8871de50e9fSSam Leffler                 nxt = IPPROTO_TCP;
8883340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
88927df3f5dSRui Paulo         } else {
8903c602fabSXin LI 		ND_PRINT((ndo, "IP version not 4 or 6, "));
8911de50e9fSSam Leffler                 return (CANT_CHECK_SIGNATURE);
89227df3f5dSRui Paulo         }
8931de50e9fSSam Leffler 
8941de50e9fSSam Leffler         /*
8951de50e9fSSam Leffler          * Step 2: Update MD5 hash with TCP header, excluding options.
8961de50e9fSSam Leffler          * The TCP checksum must be set to zero.
8971de50e9fSSam Leffler          */
8981de50e9fSSam Leffler         savecsum = tp1.th_sum;
8991de50e9fSSam Leffler         tp1.th_sum = 0;
9003340d773SGleb Smirnoff         MD5_Update(&ctx, (const char *)&tp1, sizeof(struct tcphdr));
9011de50e9fSSam Leffler         tp1.th_sum = savecsum;
9021de50e9fSSam Leffler         /*
9031de50e9fSSam Leffler          * Step 3: Update MD5 hash with TCP segment data, if present.
9041de50e9fSSam Leffler          */
9051de50e9fSSam Leffler         if (length > 0)
9061de50e9fSSam Leffler                 MD5_Update(&ctx, data, length);
9071de50e9fSSam Leffler         /*
9081de50e9fSSam Leffler          * Step 4: Update MD5 hash with shared secret.
9091de50e9fSSam Leffler          */
9103c602fabSXin LI         MD5_Update(&ctx, ndo->ndo_sigsecret, strlen(ndo->ndo_sigsecret));
9111de50e9fSSam Leffler         MD5_Final(sig, &ctx);
9121de50e9fSSam Leffler 
913b5bfcb5dSMax Laier         if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
9141de50e9fSSam Leffler                 return (SIGNATURE_VALID);
9151de50e9fSSam Leffler         else
9161de50e9fSSam Leffler                 return (SIGNATURE_INVALID);
9171de50e9fSSam Leffler }
9183c602fabSXin LI USES_APPLE_RST
9191de50e9fSSam Leffler #endif /* HAVE_LIBCRYPTO */
920a5779b6eSRui Paulo 
921a5779b6eSRui Paulo /*
922a5779b6eSRui Paulo  * Local Variables:
923a5779b6eSRui Paulo  * c-style: whitesmith
924a5779b6eSRui Paulo  * c-basic-offset: 8
925a5779b6eSRui Paulo  * End:
926a5779b6eSRui Paulo  */
927