xref: /freebsd/contrib/tcpdump/print-tcp.c (revision ee67461e)
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
34ee67461eSJoseph Mingrone #include <config.h>
354edb46e9SPaul Traina #endif
364edb46e9SPaul Traina 
37ee67461eSJoseph Mingrone #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 
46ee67461eSJoseph Mingrone #include "diag-control.h"
47ee67461eSJoseph Mingrone 
48685295f4SBill Fenner #include "tcp.h"
49685295f4SBill Fenner 
50685295f4SBill Fenner #include "ip.h"
51685295f4SBill Fenner #include "ip6.h"
525b0fe478SBruce M Simpson #include "ipproto.h"
531de50e9fSSam Leffler #include "rpc_auth.h"
541de50e9fSSam Leffler #include "rpc_msg.h"
55685295f4SBill Fenner 
561de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
571de50e9fSSam Leffler #include <openssl/md5.h>
583340d773SGleb Smirnoff #include "signature.h"
591de50e9fSSam Leffler 
603c602fabSXin LI static int tcp_verify_signature(netdissect_options *ndo,
613c602fabSXin LI                                 const struct ip *ip, const struct tcphdr *tp,
62ee67461eSJoseph Mingrone                                 const u_char *data, u_int length, const u_char *rcvsig);
631de50e9fSSam Leffler #endif
641de50e9fSSam Leffler 
65ee67461eSJoseph Mingrone static void print_tcp_rst_data(netdissect_options *, const u_char *sp, u_int length);
66ee67461eSJoseph Mingrone static void print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp,
673340d773SGleb Smirnoff                                       u_int datalen, int exp);
68685295f4SBill Fenner 
69685295f4SBill Fenner #define MAX_RST_DATA_LEN	30
70685295f4SBill Fenner 
71685295f4SBill Fenner 
724edb46e9SPaul Traina struct tha {
73ee67461eSJoseph Mingrone         nd_ipv4 src;
74ee67461eSJoseph Mingrone         nd_ipv4 dst;
754edb46e9SPaul Traina         u_int port;
764edb46e9SPaul Traina };
774edb46e9SPaul Traina 
784edb46e9SPaul Traina struct tcp_seq_hash {
794edb46e9SPaul Traina         struct tcp_seq_hash *nxt;
804edb46e9SPaul Traina         struct tha addr;
81ee67461eSJoseph Mingrone         uint32_t seq;
82ee67461eSJoseph Mingrone         uint32_t ack;
834edb46e9SPaul Traina };
844edb46e9SPaul Traina 
853c602fabSXin LI struct tha6 {
86ee67461eSJoseph Mingrone         nd_ipv6 src;
87ee67461eSJoseph Mingrone         nd_ipv6 dst;
883c602fabSXin LI         u_int port;
893c602fabSXin LI };
903c602fabSXin LI 
913c602fabSXin LI struct tcp_seq_hash6 {
923c602fabSXin LI         struct tcp_seq_hash6 *nxt;
933c602fabSXin LI         struct tha6 addr;
94ee67461eSJoseph Mingrone         uint32_t seq;
95ee67461eSJoseph Mingrone         uint32_t ack;
963c602fabSXin LI };
973c602fabSXin LI 
984edb46e9SPaul Traina #define TSEQ_HASHSIZE 919
994edb46e9SPaul Traina 
100ee67461eSJoseph Mingrone /* These tcp options do not have the size octet */
1014edb46e9SPaul Traina #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
1024edb46e9SPaul Traina 
1033c602fabSXin LI static struct tcp_seq_hash tcp_seq_hash4[TSEQ_HASHSIZE];
1043c602fabSXin LI static struct tcp_seq_hash6 tcp_seq_hash6[TSEQ_HASHSIZE];
1054edb46e9SPaul Traina 
1063c602fabSXin LI static const struct tok tcp_flag_values[] = {
107a5779b6eSRui Paulo         { TH_FIN, "F" },
108a5779b6eSRui Paulo         { TH_SYN, "S" },
109a5779b6eSRui Paulo         { TH_RST, "R" },
110a5779b6eSRui Paulo         { TH_PUSH, "P" },
111a5779b6eSRui Paulo         { TH_ACK, "." },
112a5779b6eSRui Paulo         { TH_URG, "U" },
113a5779b6eSRui Paulo         { TH_ECNECHO, "E" },
114a5779b6eSRui Paulo         { TH_CWR, "W" },
115a5779b6eSRui Paulo         { 0, NULL }
116a5779b6eSRui Paulo };
1174edb46e9SPaul Traina 
1183c602fabSXin LI static const struct tok tcp_option_values[] = {
119a5779b6eSRui Paulo         { TCPOPT_EOL, "eol" },
120a5779b6eSRui Paulo         { TCPOPT_NOP, "nop" },
121a5779b6eSRui Paulo         { TCPOPT_MAXSEG, "mss" },
122a5779b6eSRui Paulo         { TCPOPT_WSCALE, "wscale" },
123a5779b6eSRui Paulo         { TCPOPT_SACKOK, "sackOK" },
124a5779b6eSRui Paulo         { TCPOPT_SACK, "sack" },
125a5779b6eSRui Paulo         { TCPOPT_ECHO, "echo" },
126a5779b6eSRui Paulo         { TCPOPT_ECHOREPLY, "echoreply" },
127a5779b6eSRui Paulo         { TCPOPT_TIMESTAMP, "TS" },
128a5779b6eSRui Paulo         { TCPOPT_CC, "cc" },
129a5779b6eSRui Paulo         { TCPOPT_CCNEW, "ccnew" },
130a5779b6eSRui Paulo         { TCPOPT_CCECHO, "" },
131a5779b6eSRui Paulo         { TCPOPT_SIGNATURE, "md5" },
1323340d773SGleb Smirnoff         { TCPOPT_SCPS, "scps" },
133ce3ed1caSRui Paulo         { TCPOPT_UTO, "uto" },
1343340d773SGleb Smirnoff         { TCPOPT_TCPAO, "tcp-ao" },
1353c602fabSXin LI         { TCPOPT_MPTCP, "mptcp" },
1363340d773SGleb Smirnoff         { TCPOPT_FASTOPEN, "tfo" },
1373c602fabSXin LI         { TCPOPT_EXPERIMENT2, "exp" },
138a5779b6eSRui Paulo         { 0, NULL }
139a5779b6eSRui Paulo };
140685295f4SBill Fenner 
141ee67461eSJoseph Mingrone static uint16_t
tcp_cksum(netdissect_options * ndo,const struct ip * ip,const struct tcphdr * tp,u_int len)1423c602fabSXin LI tcp_cksum(netdissect_options *ndo,
143ee67461eSJoseph Mingrone           const struct ip *ip,
144ee67461eSJoseph Mingrone           const struct tcphdr *tp,
145ee67461eSJoseph Mingrone           u_int len)
146685295f4SBill Fenner {
1473c602fabSXin LI         return nextproto4_cksum(ndo, ip, (const uint8_t *)tp, len, len,
1483c602fabSXin LI                                 IPPROTO_TCP);
149685295f4SBill Fenner }
150685295f4SBill Fenner 
151ee67461eSJoseph Mingrone static uint16_t
tcp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct tcphdr * tp,u_int len)1523340d773SGleb Smirnoff tcp6_cksum(netdissect_options *ndo,
153ee67461eSJoseph Mingrone            const struct ip6_hdr *ip6,
154ee67461eSJoseph Mingrone            const struct tcphdr *tp,
155ee67461eSJoseph Mingrone            u_int len)
1563340d773SGleb Smirnoff {
1573340d773SGleb Smirnoff         return nextproto6_cksum(ndo, ip6, (const uint8_t *)tp, len, len,
1583340d773SGleb Smirnoff                                 IPPROTO_TCP);
1593340d773SGleb Smirnoff }
1603340d773SGleb Smirnoff 
1614edb46e9SPaul Traina void
tcp_print(netdissect_options * ndo,const u_char * bp,u_int length,const u_char * bp2,int fragmented)1623c602fabSXin LI tcp_print(netdissect_options *ndo,
163ee67461eSJoseph Mingrone           const u_char *bp, u_int length,
164ee67461eSJoseph Mingrone           const u_char *bp2, int fragmented)
1654edb46e9SPaul Traina {
166ee67461eSJoseph Mingrone         const struct tcphdr *tp;
167ee67461eSJoseph Mingrone         const struct ip *ip;
168ee67461eSJoseph Mingrone         u_char flags;
169ee67461eSJoseph Mingrone         u_int hlen;
170ee67461eSJoseph Mingrone         char ch;
1713c602fabSXin LI         uint16_t sport, dport, win, urp;
1723c602fabSXin LI         uint32_t seq, ack, thseq, thack;
17327df3f5dSRui Paulo         u_int utoval;
1743c602fabSXin LI         uint16_t magic;
175ee67461eSJoseph Mingrone         int rev;
176ee67461eSJoseph Mingrone         const struct ip6_hdr *ip6;
177ee67461eSJoseph Mingrone         u_int header_len;	/* Header length in bytes */
1784edb46e9SPaul Traina 
179ee67461eSJoseph Mingrone         ndo->ndo_protocol = "tcp";
1803340d773SGleb Smirnoff         tp = (const struct tcphdr *)bp;
1813340d773SGleb Smirnoff         ip = (const struct ip *)bp2;
182685295f4SBill Fenner         if (IP_V(ip) == 6)
1833340d773SGleb Smirnoff                 ip6 = (const struct ip6_hdr *)bp2;
184b0453382SBill Fenner         else
185b0453382SBill Fenner                 ip6 = NULL;
1864edb46e9SPaul Traina         ch = '\0';
187ee67461eSJoseph Mingrone         if (!ND_TTEST_2(tp->th_dport)) {
188ee67461eSJoseph Mingrone                 if (ip6) {
189ee67461eSJoseph Mingrone                         ND_PRINT("%s > %s:",
190ee67461eSJoseph Mingrone                                  GET_IP6ADDR_STRING(ip6->ip6_src),
191ee67461eSJoseph Mingrone                                  GET_IP6ADDR_STRING(ip6->ip6_dst));
192ee67461eSJoseph Mingrone                 } else {
193ee67461eSJoseph Mingrone                         ND_PRINT("%s > %s:",
194ee67461eSJoseph Mingrone                                  GET_IPADDR_STRING(ip->ip_src),
195ee67461eSJoseph Mingrone                                  GET_IPADDR_STRING(ip->ip_dst));
196ee67461eSJoseph Mingrone                 }
197ee67461eSJoseph Mingrone                 nd_print_trunc(ndo);
1984edb46e9SPaul Traina                 return;
1994edb46e9SPaul Traina         }
2004edb46e9SPaul Traina 
201ee67461eSJoseph Mingrone         sport = GET_BE_U_2(tp->th_sport);
202ee67461eSJoseph Mingrone         dport = GET_BE_U_2(tp->th_dport);
203b0453382SBill Fenner 
204b0453382SBill Fenner         if (ip6) {
205ee67461eSJoseph Mingrone                 if (GET_U_1(ip6->ip6_nxt) == IPPROTO_TCP) {
206ee67461eSJoseph Mingrone                         ND_PRINT("%s.%s > %s.%s: ",
207ee67461eSJoseph Mingrone                                  GET_IP6ADDR_STRING(ip6->ip6_src),
2083340d773SGleb Smirnoff                                  tcpport_string(ndo, sport),
209ee67461eSJoseph Mingrone                                  GET_IP6ADDR_STRING(ip6->ip6_dst),
210ee67461eSJoseph Mingrone                                  tcpport_string(ndo, dport));
211b0453382SBill Fenner                 } else {
212ee67461eSJoseph Mingrone                         ND_PRINT("%s > %s: ",
213ee67461eSJoseph Mingrone                                  tcpport_string(ndo, sport), tcpport_string(ndo, dport));
214b0453382SBill Fenner                 }
2153340d773SGleb Smirnoff         } else {
216ee67461eSJoseph Mingrone                 if (GET_U_1(ip->ip_p) == IPPROTO_TCP) {
217ee67461eSJoseph Mingrone                         ND_PRINT("%s.%s > %s.%s: ",
218ee67461eSJoseph Mingrone                                  GET_IPADDR_STRING(ip->ip_src),
2193340d773SGleb Smirnoff                                  tcpport_string(ndo, sport),
220ee67461eSJoseph Mingrone                                  GET_IPADDR_STRING(ip->ip_dst),
221ee67461eSJoseph Mingrone                                  tcpport_string(ndo, dport));
222b0453382SBill Fenner                 } else {
223ee67461eSJoseph Mingrone                         ND_PRINT("%s > %s: ",
224ee67461eSJoseph Mingrone                                  tcpport_string(ndo, sport), tcpport_string(ndo, dport));
225b0453382SBill Fenner                 }
226b0453382SBill Fenner         }
227b0453382SBill Fenner 
228ee67461eSJoseph Mingrone         ND_TCHECK_SIZE(tp);
2293340d773SGleb Smirnoff 
2303340d773SGleb Smirnoff         hlen = TH_OFF(tp) * 4;
2313340d773SGleb Smirnoff 
2321de50e9fSSam Leffler         if (hlen < sizeof(*tp)) {
233ee67461eSJoseph Mingrone                 ND_PRINT(" tcp %u [bad hdr length %u - too short, < %zu]",
234ee67461eSJoseph Mingrone                          length - hlen, hlen, sizeof(*tp));
2351de50e9fSSam Leffler                 return;
2361de50e9fSSam Leffler         }
2371de50e9fSSam Leffler 
238ee67461eSJoseph Mingrone         seq = GET_BE_U_4(tp->th_seq);
239ee67461eSJoseph Mingrone         ack = GET_BE_U_4(tp->th_ack);
240ee67461eSJoseph Mingrone         win = GET_BE_U_2(tp->th_win);
241ee67461eSJoseph Mingrone         urp = GET_BE_U_2(tp->th_urp);
2424edb46e9SPaul Traina 
2433c602fabSXin LI         if (ndo->ndo_qflag) {
244ee67461eSJoseph Mingrone                 ND_PRINT("tcp %u", length - hlen);
2451de50e9fSSam Leffler                 if (hlen > length) {
246ee67461eSJoseph Mingrone                         ND_PRINT(" [bad hdr length %u - too long, > %u]",
247ee67461eSJoseph Mingrone                                  hlen, length);
2481de50e9fSSam Leffler                 }
2494edb46e9SPaul Traina                 return;
2504edb46e9SPaul Traina         }
251a5779b6eSRui Paulo 
252ee67461eSJoseph Mingrone         flags = GET_U_1(tp->th_flags);
253ee67461eSJoseph Mingrone         ND_PRINT("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags));
2544edb46e9SPaul Traina 
2553c602fabSXin LI         if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
2564edb46e9SPaul Traina                 /*
2574edb46e9SPaul Traina                  * Find (or record) the initial sequence numbers for
2584edb46e9SPaul Traina                  * this conversation.  (we pick an arbitrary
2594edb46e9SPaul Traina                  * collating order so there's only one entry for
2604edb46e9SPaul Traina                  * both directions).
2614edb46e9SPaul Traina                  */
262b0453382SBill Fenner                 rev = 0;
263b0453382SBill Fenner                 if (ip6) {
264ee67461eSJoseph Mingrone                         struct tcp_seq_hash6 *th;
2653c602fabSXin LI                         struct tcp_seq_hash6 *tcp_seq_hash;
266ee67461eSJoseph Mingrone                         const void *src, *dst;
2673c602fabSXin LI                         struct tha6 tha;
2683c602fabSXin LI 
2693c602fabSXin LI                         tcp_seq_hash = tcp_seq_hash6;
270ee67461eSJoseph Mingrone                         src = (const void *)ip6->ip6_src;
271ee67461eSJoseph Mingrone                         dst = (const void *)ip6->ip6_dst;
272a90e161bSBill Fenner                         if (sport > dport)
273b0453382SBill Fenner                                 rev = 1;
274a90e161bSBill Fenner                         else if (sport == dport) {
275ee67461eSJoseph Mingrone                                 if (UNALIGNED_MEMCMP(src, dst, sizeof(ip6->ip6_dst)) > 0)
276b0453382SBill Fenner                                         rev = 1;
277b0453382SBill Fenner                         }
278b0453382SBill Fenner                         if (rev) {
279ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.src, dst, sizeof(ip6->ip6_dst));
280ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.dst, src, sizeof(ip6->ip6_src));
28139e421e8SCy Schubert                                 tha.port = ((u_int)dport) << 16 | sport;
282b0453382SBill Fenner                         } else {
283ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.dst, dst, sizeof(ip6->ip6_dst));
284ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.src, src, sizeof(ip6->ip6_src));
28539e421e8SCy Schubert                                 tha.port = ((u_int)sport) << 16 | dport;
286b0453382SBill Fenner                         }
2874edb46e9SPaul Traina 
2883c602fabSXin LI                         for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
2893c602fabSXin LI                              th->nxt; th = th->nxt)
2903c602fabSXin LI                                 if (memcmp((char *)&tha, (char *)&th->addr,
2913c602fabSXin LI                                            sizeof(th->addr)) == 0)
2923c602fabSXin LI                                         break;
2933c602fabSXin LI 
2943c602fabSXin LI                         if (!th->nxt || (flags & TH_SYN)) {
2953c602fabSXin LI                                 /* didn't find it or new conversation */
296ee67461eSJoseph Mingrone                                 /* calloc() return used by the 'tcp_seq_hash6'
297ee67461eSJoseph Mingrone                                    hash table: do not free() */
2983c602fabSXin LI                                 if (th->nxt == NULL) {
2993c602fabSXin LI                                         th->nxt = (struct tcp_seq_hash6 *)
3003c602fabSXin LI                                                 calloc(1, sizeof(*th));
3013c602fabSXin LI                                         if (th->nxt == NULL)
3023340d773SGleb Smirnoff                                                 (*ndo->ndo_error)(ndo,
303ee67461eSJoseph Mingrone                                                         S_ERR_ND_MEM_ALLOC,
304ee67461eSJoseph Mingrone                                                         "%s: calloc", __func__);
3053c602fabSXin LI                                 }
3063c602fabSXin LI                                 th->addr = tha;
3073c602fabSXin LI                                 if (rev)
3083c602fabSXin LI                                         th->ack = seq, th->seq = ack - 1;
3093c602fabSXin LI                                 else
3103c602fabSXin LI                                         th->seq = seq, th->ack = ack - 1;
3113c602fabSXin LI                         } else {
3123c602fabSXin LI                                 if (rev)
3133c602fabSXin LI                                         seq -= th->ack, ack -= th->seq;
3143c602fabSXin LI                                 else
3153c602fabSXin LI                                         seq -= th->seq, ack -= th->ack;
3163c602fabSXin LI                         }
3173c602fabSXin LI 
3183c602fabSXin LI                         thseq = th->seq;
3193c602fabSXin LI                         thack = th->ack;
3203c602fabSXin LI                 } else {
321ee67461eSJoseph Mingrone                         struct tcp_seq_hash *th;
3223c602fabSXin LI                         struct tcp_seq_hash *tcp_seq_hash;
3233c602fabSXin LI                         struct tha tha;
3243c602fabSXin LI 
3253c602fabSXin LI                         tcp_seq_hash = tcp_seq_hash4;
3263c602fabSXin LI                         if (sport > dport)
3273c602fabSXin LI                                 rev = 1;
3283c602fabSXin LI                         else if (sport == dport) {
329ee67461eSJoseph Mingrone                                 if (UNALIGNED_MEMCMP(ip->ip_src, ip->ip_dst, sizeof(ip->ip_dst)) > 0)
3303c602fabSXin LI                                         rev = 1;
3313c602fabSXin LI                         }
3323c602fabSXin LI                         if (rev) {
333ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.src, ip->ip_dst,
334ee67461eSJoseph Mingrone                                                  sizeof(ip->ip_dst));
335ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.dst, ip->ip_src,
336ee67461eSJoseph Mingrone                                                  sizeof(ip->ip_src));
33739e421e8SCy Schubert                                 tha.port = ((u_int)dport) << 16 | sport;
3383c602fabSXin LI                         } else {
339ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.dst, ip->ip_dst,
340ee67461eSJoseph Mingrone                                                  sizeof(ip->ip_dst));
341ee67461eSJoseph Mingrone                                 UNALIGNED_MEMCPY(&tha.src, ip->ip_src,
342ee67461eSJoseph Mingrone                                                  sizeof(ip->ip_src));
34339e421e8SCy Schubert                                 tha.port = ((u_int)sport) << 16 | dport;
3443c602fabSXin LI                         }
3453c602fabSXin LI 
3464edb46e9SPaul Traina                         for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
3474edb46e9SPaul Traina                              th->nxt; th = th->nxt)
3485b0fe478SBruce M Simpson                                 if (memcmp((char *)&tha, (char *)&th->addr,
3495b0fe478SBruce M Simpson                                            sizeof(th->addr)) == 0)
3504edb46e9SPaul Traina                                         break;
3514edb46e9SPaul Traina 
352685295f4SBill Fenner                         if (!th->nxt || (flags & TH_SYN)) {
3534edb46e9SPaul Traina                                 /* didn't find it or new conversation */
354ee67461eSJoseph Mingrone                                 /* calloc() return used by the 'tcp_seq_hash4'
355ee67461eSJoseph Mingrone                                    hash table: do not free() */
3564edb46e9SPaul Traina                                 if (th->nxt == NULL) {
3574edb46e9SPaul Traina                                         th->nxt = (struct tcp_seq_hash *)
3584edb46e9SPaul Traina                                                 calloc(1, sizeof(*th));
3594edb46e9SPaul Traina                                         if (th->nxt == NULL)
3603340d773SGleb Smirnoff                                                 (*ndo->ndo_error)(ndo,
361ee67461eSJoseph Mingrone                                                         S_ERR_ND_MEM_ALLOC,
362ee67461eSJoseph Mingrone                                                         "%s: calloc", __func__);
3634edb46e9SPaul Traina                                 }
3644edb46e9SPaul Traina                                 th->addr = tha;
3654edb46e9SPaul Traina                                 if (rev)
3664edb46e9SPaul Traina                                         th->ack = seq, th->seq = ack - 1;
3674edb46e9SPaul Traina                                 else
3684edb46e9SPaul Traina                                         th->seq = seq, th->ack = ack - 1;
3694edb46e9SPaul Traina                         } else {
3704edb46e9SPaul Traina                                 if (rev)
3714edb46e9SPaul Traina                                         seq -= th->ack, ack -= th->seq;
3724edb46e9SPaul Traina                                 else
3734edb46e9SPaul Traina                                         seq -= th->seq, ack -= th->ack;
3744edb46e9SPaul Traina                         }
375685295f4SBill Fenner 
376685295f4SBill Fenner                         thseq = th->seq;
377685295f4SBill Fenner                         thack = th->ack;
3783c602fabSXin LI                 }
379685295f4SBill Fenner         } else {
380685295f4SBill Fenner                 /*fool gcc*/
3813c602fabSXin LI                 thseq = thack = rev = 0;
3824edb46e9SPaul Traina         }
3834de76e31SBill Fenner         if (hlen > length) {
384ee67461eSJoseph Mingrone                 ND_PRINT(" [bad hdr length %u - too long, > %u]",
385ee67461eSJoseph Mingrone                          hlen, length);
3864de76e31SBill Fenner                 return;
3874de76e31SBill Fenner         }
388685295f4SBill Fenner 
3893c602fabSXin LI         if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
390cac3dcd5SXin LI                 /* Check the checksum, if possible. */
3913c602fabSXin LI                 uint16_t sum, tcp_sum;
392cac3dcd5SXin LI 
393cac3dcd5SXin LI                 if (IP_V(ip) == 4) {
394ee67461eSJoseph Mingrone                         if (ND_TTEST_LEN(tp->th_sport, length)) {
3953c602fabSXin LI                                 sum = tcp_cksum(ndo, ip, tp, length);
396ee67461eSJoseph Mingrone                                 tcp_sum = GET_BE_U_2(tp->th_sum);
397cac3dcd5SXin LI 
398ee67461eSJoseph Mingrone                                 ND_PRINT(", cksum 0x%04x", tcp_sum);
399cac3dcd5SXin LI                                 if (sum != 0)
400ee67461eSJoseph Mingrone                                         ND_PRINT(" (incorrect -> 0x%04x)",
401ee67461eSJoseph Mingrone                                             in_cksum_shouldbe(tcp_sum, sum));
402cac3dcd5SXin LI                                 else
403ee67461eSJoseph Mingrone                                         ND_PRINT(" (correct)");
404685295f4SBill Fenner                         }
405ee67461eSJoseph Mingrone                 } else if (IP_V(ip) == 6) {
406ee67461eSJoseph Mingrone                         if (ND_TTEST_LEN(tp->th_sport, length)) {
4073340d773SGleb Smirnoff                                 sum = tcp6_cksum(ndo, ip6, tp, length);
408ee67461eSJoseph Mingrone                                 tcp_sum = GET_BE_U_2(tp->th_sum);
409cac3dcd5SXin LI 
410ee67461eSJoseph Mingrone                                 ND_PRINT(", cksum 0x%04x", tcp_sum);
411cac3dcd5SXin LI                                 if (sum != 0)
412ee67461eSJoseph Mingrone                                         ND_PRINT(" (incorrect -> 0x%04x)",
413ee67461eSJoseph Mingrone                                             in_cksum_shouldbe(tcp_sum, sum));
414cac3dcd5SXin LI                                 else
415ee67461eSJoseph Mingrone                                         ND_PRINT(" (correct)");
4161de50e9fSSam Leffler 
417685295f4SBill Fenner                         }
418685295f4SBill Fenner                 }
419cac3dcd5SXin LI         }
420685295f4SBill Fenner 
4214edb46e9SPaul Traina         length -= hlen;
4223c602fabSXin LI         if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
423ee67461eSJoseph Mingrone                 ND_PRINT(", seq %u", seq);
4244edb46e9SPaul Traina 
425a5779b6eSRui Paulo                 if (length > 0) {
426ee67461eSJoseph Mingrone                         ND_PRINT(":%u", seq + length);
427a5779b6eSRui Paulo                 }
428a5779b6eSRui Paulo         }
429a5779b6eSRui Paulo 
430a5779b6eSRui Paulo         if (flags & TH_ACK) {
431ee67461eSJoseph Mingrone                 ND_PRINT(", ack %u", ack);
432a5779b6eSRui Paulo         }
433a5779b6eSRui Paulo 
434ee67461eSJoseph Mingrone         ND_PRINT(", win %u", win);
4354edb46e9SPaul Traina 
4364edb46e9SPaul Traina         if (flags & TH_URG)
437ee67461eSJoseph Mingrone                 ND_PRINT(", urg %u", urp);
4384edb46e9SPaul Traina         /*
4394edb46e9SPaul Traina          * Handle any options.
4404edb46e9SPaul Traina          */
4415b0fe478SBruce M Simpson         if (hlen > sizeof(*tp)) {
442ee67461eSJoseph Mingrone                 const u_char *cp;
443ee67461eSJoseph Mingrone                 u_int i, opt, datalen;
444ee67461eSJoseph Mingrone                 u_int len;
4454edb46e9SPaul Traina 
4465b0fe478SBruce M Simpson                 hlen -= sizeof(*tp);
4474edb46e9SPaul Traina                 cp = (const u_char *)tp + sizeof(*tp);
448ee67461eSJoseph Mingrone                 ND_PRINT(", options [");
4494edb46e9SPaul Traina                 while (hlen > 0) {
450a5779b6eSRui Paulo                         if (ch != '\0')
451ee67461eSJoseph Mingrone                                 ND_PRINT("%c", ch);
452ee67461eSJoseph Mingrone                         opt = GET_U_1(cp);
453ee67461eSJoseph Mingrone                         cp++;
4544edb46e9SPaul Traina                         if (ZEROLENOPT(opt))
4554edb46e9SPaul Traina                                 len = 1;
4564edb46e9SPaul Traina                         else {
457ee67461eSJoseph Mingrone                                 len = GET_U_1(cp);
458ee67461eSJoseph Mingrone                                 cp++;	/* total including type, len */
4594de76e31SBill Fenner                                 if (len < 2 || len > hlen)
4604de76e31SBill Fenner                                         goto bad;
4614de76e31SBill Fenner                                 --hlen;		/* account for length byte */
4624edb46e9SPaul Traina                         }
4634de76e31SBill Fenner                         --hlen;			/* account for type byte */
4644edb46e9SPaul Traina                         datalen = 0;
4654de76e31SBill Fenner 
4664de76e31SBill Fenner /* Bail if "l" bytes of data are not left or were not captured  */
467ee67461eSJoseph Mingrone #define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); }
4684de76e31SBill Fenner 
469a5779b6eSRui Paulo 
470ee67461eSJoseph Mingrone                         ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt));
471a5779b6eSRui Paulo 
4724edb46e9SPaul Traina                         switch (opt) {
4734edb46e9SPaul Traina 
4744edb46e9SPaul Traina                         case TCPOPT_MAXSEG:
4754edb46e9SPaul Traina                                 datalen = 2;
4764de76e31SBill Fenner                                 LENCHECK(datalen);
477ee67461eSJoseph Mingrone                                 ND_PRINT(" %u", GET_BE_U_2(cp));
4784edb46e9SPaul Traina                                 break;
4794edb46e9SPaul Traina 
4804edb46e9SPaul Traina                         case TCPOPT_WSCALE:
4814edb46e9SPaul Traina                                 datalen = 1;
4824de76e31SBill Fenner                                 LENCHECK(datalen);
483ee67461eSJoseph Mingrone                                 ND_PRINT(" %u", GET_U_1(cp));
4844edb46e9SPaul Traina                                 break;
4854edb46e9SPaul Traina 
4864edb46e9SPaul Traina                         case TCPOPT_SACK:
4874edb46e9SPaul Traina                                 datalen = len - 2;
488b0453382SBill Fenner                                 if (datalen % 8 != 0) {
489ee67461eSJoseph Mingrone                                         ND_PRINT(" invalid sack");
490b0453382SBill Fenner                                 } else {
4913c602fabSXin LI                                         uint32_t s, e;
492b0453382SBill Fenner 
493ee67461eSJoseph Mingrone                                         ND_PRINT(" %u ", datalen / 8);
494b0453382SBill Fenner                                         for (i = 0; i < datalen; i += 8) {
4954de76e31SBill Fenner                                                 LENCHECK(i + 4);
496ee67461eSJoseph Mingrone                                                 s = GET_BE_U_4(cp + i);
497b0453382SBill Fenner                                                 LENCHECK(i + 8);
498ee67461eSJoseph Mingrone                                                 e = GET_BE_U_4(cp + i + 4);
4993c602fabSXin LI                                                 if (rev) {
500b0453382SBill Fenner                                                         s -= thseq;
501b0453382SBill Fenner                                                         e -= thseq;
502b0453382SBill Fenner                                                 } else {
503b0453382SBill Fenner                                                         s -= thack;
504b0453382SBill Fenner                                                         e -= thack;
5054edb46e9SPaul Traina                                                 }
506ee67461eSJoseph Mingrone                                                 ND_PRINT("{%u:%u}", s, e);
507b0453382SBill Fenner                                         }
508b0453382SBill Fenner                                 }
5094edb46e9SPaul Traina                                 break;
5104edb46e9SPaul Traina 
511a5779b6eSRui Paulo                         case TCPOPT_CC:
512a5779b6eSRui Paulo                         case TCPOPT_CCNEW:
513a5779b6eSRui Paulo                         case TCPOPT_CCECHO:
5144edb46e9SPaul Traina                         case TCPOPT_ECHO:
5154edb46e9SPaul Traina                         case TCPOPT_ECHOREPLY:
516a5779b6eSRui Paulo 
517a5779b6eSRui Paulo                                 /*
518a5779b6eSRui Paulo                                  * those options share their semantics.
519a5779b6eSRui Paulo                                  * fall through
520a5779b6eSRui Paulo                                  */
5214edb46e9SPaul Traina                                 datalen = 4;
5224de76e31SBill Fenner                                 LENCHECK(datalen);
523ee67461eSJoseph Mingrone                                 ND_PRINT(" %u", GET_BE_U_4(cp));
5244edb46e9SPaul Traina                                 break;
5254edb46e9SPaul Traina 
5264edb46e9SPaul Traina                         case TCPOPT_TIMESTAMP:
5274de76e31SBill Fenner                                 datalen = 8;
5284de76e31SBill Fenner                                 LENCHECK(datalen);
529ee67461eSJoseph Mingrone                                 ND_PRINT(" val %u ecr %u",
530ee67461eSJoseph Mingrone                                              GET_BE_U_4(cp),
531ee67461eSJoseph Mingrone                                              GET_BE_U_4(cp + 4));
5324edb46e9SPaul Traina                                 break;
5334edb46e9SPaul Traina 
5341de50e9fSSam Leffler                         case TCPOPT_SIGNATURE:
5351de50e9fSSam Leffler                                 datalen = TCP_SIGLEN;
5361de50e9fSSam Leffler                                 LENCHECK(datalen);
537ee67461eSJoseph Mingrone                                 ND_PRINT(" ");
5381de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
5393c602fabSXin LI                                 switch (tcp_verify_signature(ndo, ip, tp,
5401de50e9fSSam Leffler                                                              bp + TH_OFF(tp) * 4, length, cp)) {
5411de50e9fSSam Leffler 
5421de50e9fSSam Leffler                                 case SIGNATURE_VALID:
543ee67461eSJoseph Mingrone                                         ND_PRINT("valid");
5441de50e9fSSam Leffler                                         break;
5451de50e9fSSam Leffler 
5461de50e9fSSam Leffler                                 case SIGNATURE_INVALID:
547ee67461eSJoseph Mingrone                                         nd_print_invalid(ndo);
5481de50e9fSSam Leffler                                         break;
5491de50e9fSSam Leffler 
5501de50e9fSSam Leffler                                 case CANT_CHECK_SIGNATURE:
551ee67461eSJoseph Mingrone                                         ND_PRINT("can't check - ");
5521de50e9fSSam Leffler                                         for (i = 0; i < TCP_SIGLEN; ++i)
553ee67461eSJoseph Mingrone                                                 ND_PRINT("%02x",
554ee67461eSJoseph Mingrone                                                          GET_U_1(cp + i));
5551de50e9fSSam Leffler                                         break;
5561de50e9fSSam Leffler                                 }
5571de50e9fSSam Leffler #else
5581de50e9fSSam Leffler                                 for (i = 0; i < TCP_SIGLEN; ++i)
559ee67461eSJoseph Mingrone                                         ND_PRINT("%02x", GET_U_1(cp + i));
5601de50e9fSSam Leffler #endif
5611de50e9fSSam Leffler                                 break;
5621de50e9fSSam Leffler 
5633340d773SGleb Smirnoff                         case TCPOPT_SCPS:
5643340d773SGleb Smirnoff                                 datalen = 2;
5653340d773SGleb Smirnoff                                 LENCHECK(datalen);
566ee67461eSJoseph Mingrone                                 ND_PRINT(" cap %02x id %u", GET_U_1(cp),
567ee67461eSJoseph Mingrone                                          GET_U_1(cp + 1));
568a5779b6eSRui Paulo                                 break;
569a5779b6eSRui Paulo 
5703340d773SGleb Smirnoff                         case TCPOPT_TCPAO:
5713340d773SGleb Smirnoff                                 datalen = len - 2;
5723340d773SGleb Smirnoff                                 /* RFC 5925 Section 2.2:
5733340d773SGleb Smirnoff                                  * "The Length value MUST be greater than or equal to 4."
5743340d773SGleb Smirnoff                                  * (This includes the Kind and Length fields already processed
5753340d773SGleb Smirnoff                                  * at this point.)
5763340d773SGleb Smirnoff                                  */
5773340d773SGleb Smirnoff                                 if (datalen < 2) {
578ee67461eSJoseph Mingrone                                         nd_print_invalid(ndo);
5793340d773SGleb Smirnoff                                 } else {
5803340d773SGleb Smirnoff                                         LENCHECK(1);
581ee67461eSJoseph Mingrone                                         ND_PRINT(" keyid %u", GET_U_1(cp));
5823340d773SGleb Smirnoff                                         LENCHECK(2);
583ee67461eSJoseph Mingrone                                         ND_PRINT(" rnextkeyid %u",
584ee67461eSJoseph Mingrone                                                  GET_U_1(cp + 1));
5853340d773SGleb Smirnoff                                         if (datalen > 2) {
586ee67461eSJoseph Mingrone                                                 ND_PRINT(" mac 0x");
5873340d773SGleb Smirnoff                                                 for (i = 2; i < datalen; i++) {
5883340d773SGleb Smirnoff                                                         LENCHECK(i + 1);
589ee67461eSJoseph Mingrone                                                         ND_PRINT("%02x",
590ee67461eSJoseph Mingrone                                                                  GET_U_1(cp + i));
5913340d773SGleb Smirnoff                                                 }
5923340d773SGleb Smirnoff                                         }
5933340d773SGleb Smirnoff                                 }
5943340d773SGleb Smirnoff                                 break;
595a5779b6eSRui Paulo 
596a5779b6eSRui Paulo                         case TCPOPT_EOL:
597a5779b6eSRui Paulo                         case TCPOPT_NOP:
598a5779b6eSRui Paulo                         case TCPOPT_SACKOK:
599a5779b6eSRui Paulo                                 /*
600a5779b6eSRui Paulo                                  * Nothing interesting.
601a5779b6eSRui Paulo                                  * fall through
602a5779b6eSRui Paulo                                  */
603a5779b6eSRui Paulo                                 break;
604a5779b6eSRui Paulo 
605ce3ed1caSRui Paulo                         case TCPOPT_UTO:
606ce3ed1caSRui Paulo                                 datalen = 2;
607ce3ed1caSRui Paulo                                 LENCHECK(datalen);
608ee67461eSJoseph Mingrone                                 utoval = GET_BE_U_2(cp);
609ee67461eSJoseph Mingrone                                 ND_PRINT(" 0x%x", utoval);
610ce3ed1caSRui Paulo                                 if (utoval & 0x0001)
611ce3ed1caSRui Paulo                                         utoval = (utoval >> 1) * 60;
612ce3ed1caSRui Paulo                                 else
613ce3ed1caSRui Paulo                                         utoval >>= 1;
614ee67461eSJoseph Mingrone                                 ND_PRINT(" %u", utoval);
6153c602fabSXin LI                                 break;
6163c602fabSXin LI 
6173c602fabSXin LI                         case TCPOPT_MPTCP:
618ee67461eSJoseph Mingrone                             {
619ee67461eSJoseph Mingrone                                 const u_char *snapend_save;
620ee67461eSJoseph Mingrone                                 int ret;
621ee67461eSJoseph Mingrone 
6223c602fabSXin LI                                 datalen = len - 2;
6233c602fabSXin LI                                 LENCHECK(datalen);
624ee67461eSJoseph Mingrone                                 /* Update the snapend to the end of the option
625ee67461eSJoseph Mingrone                                  * before calling mptcp_print(). Some options
626ee67461eSJoseph Mingrone                                  * (MPTCP or others) may be present after a
627ee67461eSJoseph Mingrone                                  * MPTCP option. This prevents that, in
628ee67461eSJoseph Mingrone                                  * mptcp_print(), the remaining length < the
629ee67461eSJoseph Mingrone                                  * remaining caplen.
630ee67461eSJoseph Mingrone                                  */
631ee67461eSJoseph Mingrone                                 snapend_save = ndo->ndo_snapend;
632ee67461eSJoseph Mingrone                                 ndo->ndo_snapend = ND_MIN(cp - 2 + len,
633ee67461eSJoseph Mingrone                                                           ndo->ndo_snapend);
634ee67461eSJoseph Mingrone                                 ret = mptcp_print(ndo, cp - 2, len, flags);
635ee67461eSJoseph Mingrone                                 ndo->ndo_snapend = snapend_save;
636ee67461eSJoseph Mingrone                                 if (!ret)
6373c602fabSXin LI                                         goto bad;
6383c602fabSXin LI                                 break;
639ee67461eSJoseph Mingrone                             }
6403c602fabSXin LI 
6413340d773SGleb Smirnoff                         case TCPOPT_FASTOPEN:
6423340d773SGleb Smirnoff                                 datalen = len - 2;
6433340d773SGleb Smirnoff                                 LENCHECK(datalen);
644ee67461eSJoseph Mingrone                                 ND_PRINT(" ");
6453340d773SGleb Smirnoff                                 print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
6463340d773SGleb Smirnoff                                 break;
6473340d773SGleb Smirnoff 
6483c602fabSXin LI                         case TCPOPT_EXPERIMENT2:
6493c602fabSXin LI                                 datalen = len - 2;
6503c602fabSXin LI                                 LENCHECK(datalen);
6513c602fabSXin LI                                 if (datalen < 2)
6523c602fabSXin LI                                         goto bad;
6533c602fabSXin LI                                 /* RFC6994 */
654ee67461eSJoseph Mingrone                                 magic = GET_BE_U_2(cp);
655ee67461eSJoseph Mingrone                                 ND_PRINT("-");
6563c602fabSXin LI 
6573c602fabSXin LI                                 switch(magic) {
6583c602fabSXin LI 
6593340d773SGleb Smirnoff                                 case 0xf989: /* TCP Fast Open RFC 7413 */
6603340d773SGleb Smirnoff                                         print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
6613c602fabSXin LI                                         break;
6623c602fabSXin LI 
6633c602fabSXin LI                                 default:
6643c602fabSXin LI                                         /* Unknown magic number */
665ee67461eSJoseph Mingrone                                         ND_PRINT("%04x", magic);
6663c602fabSXin LI                                         break;
6673c602fabSXin LI                                 }
668ce3ed1caSRui Paulo                                 break;
669ce3ed1caSRui Paulo 
6704edb46e9SPaul Traina                         default:
6714edb46e9SPaul Traina                                 datalen = len - 2;
6723c602fabSXin LI                                 if (datalen)
673ee67461eSJoseph Mingrone                                         ND_PRINT(" 0x");
6744edb46e9SPaul Traina                                 for (i = 0; i < datalen; ++i) {
6753340d773SGleb Smirnoff                                         LENCHECK(i + 1);
676ee67461eSJoseph Mingrone                                         ND_PRINT("%02x", GET_U_1(cp + i));
6774edb46e9SPaul Traina                                 }
6784edb46e9SPaul Traina                                 break;
6794edb46e9SPaul Traina                         }
6804edb46e9SPaul Traina 
6814edb46e9SPaul Traina                         /* Account for data printed */
6824edb46e9SPaul Traina                         cp += datalen;
6834edb46e9SPaul Traina                         hlen -= datalen;
6844edb46e9SPaul Traina 
6854edb46e9SPaul Traina                         /* Check specification against observed length */
6864edb46e9SPaul Traina                         ++datalen;		/* option octet */
6874edb46e9SPaul Traina                         if (!ZEROLENOPT(opt))
6884edb46e9SPaul Traina                                 ++datalen;	/* size octet */
6894edb46e9SPaul Traina                         if (datalen != len)
690ee67461eSJoseph Mingrone                                 ND_PRINT("[len %u]", len);
6914edb46e9SPaul Traina                         ch = ',';
6924de76e31SBill Fenner                         if (opt == TCPOPT_EOL)
6934de76e31SBill Fenner                                 break;
6944edb46e9SPaul Traina                 }
695ee67461eSJoseph Mingrone                 ND_PRINT("]");
6964edb46e9SPaul Traina         }
697b0453382SBill Fenner 
698a5779b6eSRui Paulo         /*
699a5779b6eSRui Paulo          * Print length field before crawling down the stack.
700a5779b6eSRui Paulo          */
701ee67461eSJoseph Mingrone         ND_PRINT(", length %u", length);
702a5779b6eSRui Paulo 
703ee67461eSJoseph Mingrone         if (length == 0)
704b0453382SBill Fenner                 return;
705b0453382SBill Fenner 
706b0453382SBill Fenner         /*
707b0453382SBill Fenner          * Decode payload if necessary.
708b0453382SBill Fenner          */
709ee67461eSJoseph Mingrone         header_len = TH_OFF(tp) * 4;
710ee67461eSJoseph Mingrone         /*
711ee67461eSJoseph Mingrone          * Do a bounds check before decoding the payload.
712ee67461eSJoseph Mingrone          * At least the header data is required.
713ee67461eSJoseph Mingrone          */
714ee67461eSJoseph Mingrone         if (!ND_TTEST_LEN(bp, header_len)) {
715ee67461eSJoseph Mingrone                 ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
716ee67461eSJoseph Mingrone                          ND_BYTES_AVAILABLE_AFTER(bp), header_len);
717ee67461eSJoseph Mingrone                 nd_trunc_longjmp(ndo);
718ee67461eSJoseph Mingrone         }
719ee67461eSJoseph Mingrone         bp += header_len;
7203c602fabSXin LI         if ((flags & TH_RST) && ndo->ndo_vflag) {
7213c602fabSXin LI                 print_tcp_rst_data(ndo, bp, length);
722a5779b6eSRui Paulo                 return;
723a5779b6eSRui Paulo         }
724a5779b6eSRui Paulo 
7253c602fabSXin LI         if (ndo->ndo_packettype) {
7263c602fabSXin LI                 switch (ndo->ndo_packettype) {
727d03c0883SXin LI                 case PT_ZMTP1:
7283c602fabSXin LI                         zmtp1_print(ndo, bp, length);
729d03c0883SXin LI                         break;
7303340d773SGleb Smirnoff                 case PT_RESP:
7313340d773SGleb Smirnoff                         resp_print(ndo, bp, length);
7323340d773SGleb Smirnoff                         break;
733ee67461eSJoseph Mingrone                 case PT_DOMAIN:
734ee67461eSJoseph Mingrone                         /* over_tcp: TRUE, is_mdns: FALSE */
735ee67461eSJoseph Mingrone                         domain_print(ndo, bp, length, TRUE, FALSE);
736ee67461eSJoseph Mingrone                         break;
737d03c0883SXin LI                 }
738d03c0883SXin LI                 return;
739d03c0883SXin LI         }
740d03c0883SXin LI 
7413340d773SGleb Smirnoff         if (IS_SRC_OR_DST_PORT(TELNET_PORT)) {
7423c602fabSXin LI                 telnet_print(ndo, bp, length);
7433340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(SMTP_PORT)) {
744ee67461eSJoseph Mingrone                 ND_PRINT(": ");
7458bdc5a62SPatrick Kelsey                 smtp_print(ndo, bp, length);
746ee67461eSJoseph Mingrone         } else if (IS_SRC_OR_DST_PORT(WHOIS_PORT)) {
747ee67461eSJoseph Mingrone                 ND_PRINT(": ");
748ee67461eSJoseph Mingrone                 whois_print(ndo, bp, length);
7493340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(BGP_PORT))
7503c602fabSXin LI                 bgp_print(ndo, bp, length);
7513340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(PPTP_PORT))
7523c602fabSXin LI                 pptp_print(ndo, bp);
7533340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(REDIS_PORT))
7543340d773SGleb Smirnoff                 resp_print(ndo, bp, length);
755ee67461eSJoseph Mingrone         else if (IS_SRC_OR_DST_PORT(SSH_PORT))
756ee67461eSJoseph Mingrone                 ssh_print(ndo, bp, length);
7573340d773SGleb Smirnoff #ifdef ENABLE_SMB
7583340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(NETBIOS_SSN_PORT))
7593c602fabSXin LI                 nbt_tcp_print(ndo, bp, length);
7603340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(SMB_PORT))
7613c602fabSXin LI                 smb_tcp_print(ndo, bp, length);
762a90e161bSBill Fenner #endif
7633340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(BEEP_PORT))
7643c602fabSXin LI                 beep_print(ndo, bp, length);
7653340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(OPENFLOW_PORT_OLD) || IS_SRC_OR_DST_PORT(OPENFLOW_PORT_IANA))
7663c602fabSXin LI                 openflow_print(ndo, bp, length);
7673340d773SGleb Smirnoff         else if (IS_SRC_OR_DST_PORT(FTP_PORT)) {
768ee67461eSJoseph Mingrone                 ND_PRINT(": ");
7698bdc5a62SPatrick Kelsey                 ftp_print(ndo, bp, length);
7703340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(HTTP_PORT) || IS_SRC_OR_DST_PORT(HTTP_PORT_ALT)) {
771ee67461eSJoseph Mingrone                 ND_PRINT(": ");
7728bdc5a62SPatrick Kelsey                 http_print(ndo, bp, length);
7733340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(RTSP_PORT) || IS_SRC_OR_DST_PORT(RTSP_PORT_ALT)) {
774ee67461eSJoseph Mingrone                 ND_PRINT(": ");
7758bdc5a62SPatrick Kelsey                 rtsp_print(ndo, bp, length);
776ee67461eSJoseph Mingrone         } else if (IS_SRC_OR_DST_PORT(NAMESERVER_PORT)) {
777ee67461eSJoseph Mingrone                 /* over_tcp: TRUE, is_mdns: FALSE */
778ee67461eSJoseph Mingrone                 domain_print(ndo, bp, length, TRUE, FALSE);
7793340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(MSDP_PORT)) {
7803c602fabSXin LI                 msdp_print(ndo, bp, length);
7813340d773SGleb Smirnoff         } else if (IS_SRC_OR_DST_PORT(RPKI_RTR_PORT)) {
7823c602fabSXin LI                 rpki_rtr_print(ndo, bp, length);
783ee67461eSJoseph Mingrone         } else if (IS_SRC_OR_DST_PORT(LDP_PORT)) {
7843c602fabSXin LI                 ldp_print(ndo, bp, length);
785ee67461eSJoseph Mingrone         } else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
786ee67461eSJoseph Mingrone                  length >= 4 && ND_TTEST_4(bp)) {
7873c602fabSXin LI                 /*
7883c602fabSXin LI                  * If data present, header length valid, and NFS port used,
7893c602fabSXin LI                  * assume NFS.
7903c602fabSXin LI                  * Pass offset of data plus 4 bytes for RPC TCP msg length
7913c602fabSXin LI                  * to NFS print routines.
7923c602fabSXin LI                  */
7933c602fabSXin LI                 uint32_t fraglen;
794ee67461eSJoseph Mingrone                 const struct sunrpc_msg *rp;
7953c602fabSXin LI                 enum sunrpc_msg_type direction;
7963c602fabSXin LI 
797ee67461eSJoseph Mingrone                 fraglen = GET_BE_U_4(bp) & 0x7FFFFFFF;
7983c602fabSXin LI                 if (fraglen > (length) - 4)
7993c602fabSXin LI                         fraglen = (length) - 4;
8003340d773SGleb Smirnoff                 rp = (const struct sunrpc_msg *)(bp + 4);
801ee67461eSJoseph Mingrone                 if (ND_TTEST_4(rp->rm_direction)) {
802ee67461eSJoseph Mingrone                         direction = (enum sunrpc_msg_type) GET_BE_U_4(rp->rm_direction);
8033c602fabSXin LI                         if (dport == NFS_PORT && direction == SUNRPC_CALL) {
804ee67461eSJoseph Mingrone                                 ND_PRINT(": NFS request xid %u ",
805ee67461eSJoseph Mingrone                                          GET_BE_U_4(rp->rm_xid));
806ee67461eSJoseph Mingrone                                 nfsreq_noaddr_print(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
8073c602fabSXin LI                                 return;
8083c602fabSXin LI                         }
8093c602fabSXin LI                         if (sport == NFS_PORT && direction == SUNRPC_REPLY) {
810ee67461eSJoseph Mingrone                                 ND_PRINT(": NFS reply xid %u ",
811ee67461eSJoseph Mingrone                                          GET_BE_U_4(rp->rm_xid));
812ee67461eSJoseph Mingrone                                 nfsreply_noaddr_print(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
8133c602fabSXin LI                                 return;
8143c602fabSXin LI                         }
8153c602fabSXin LI                 }
8161de50e9fSSam Leffler         }
817a5779b6eSRui Paulo 
8184edb46e9SPaul Traina         return;
8194de76e31SBill Fenner bad:
820ee67461eSJoseph Mingrone         ND_PRINT("[bad opt]");
8214de76e31SBill Fenner         if (ch != '\0')
822ee67461eSJoseph Mingrone                 ND_PRINT("]");
8234de76e31SBill Fenner         return;
8244edb46e9SPaul Traina trunc:
825ee67461eSJoseph Mingrone         nd_print_trunc(ndo);
8264edb46e9SPaul Traina         if (ch != '\0')
827ee67461eSJoseph Mingrone                 ND_PRINT(">");
8284edb46e9SPaul Traina }
8294edb46e9SPaul Traina 
830685295f4SBill Fenner /*
831685295f4SBill Fenner  * RFC1122 says the following on data in RST segments:
832685295f4SBill Fenner  *
833685295f4SBill Fenner  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
834685295f4SBill Fenner  *
835685295f4SBill Fenner  *            A TCP SHOULD allow a received RST segment to include data.
836685295f4SBill Fenner  *
837685295f4SBill Fenner  *            DISCUSSION
838685295f4SBill Fenner  *                 It has been suggested that a RST segment could contain
839685295f4SBill Fenner  *                 ASCII text that encoded and explained the cause of the
840685295f4SBill Fenner  *                 RST.  No standard has yet been established for such
841685295f4SBill Fenner  *                 data.
842685295f4SBill Fenner  *
843685295f4SBill Fenner  */
844685295f4SBill Fenner 
845685295f4SBill Fenner static void
print_tcp_rst_data(netdissect_options * ndo,const u_char * sp,u_int length)8463c602fabSXin LI print_tcp_rst_data(netdissect_options *ndo,
847ee67461eSJoseph Mingrone                    const u_char *sp, u_int length)
848685295f4SBill Fenner {
849ee67461eSJoseph Mingrone         u_char c;
850685295f4SBill Fenner 
851ee67461eSJoseph Mingrone         ND_PRINT(ND_TTEST_LEN(sp, length) ? " [RST" : " [!RST");
852685295f4SBill Fenner         if (length > MAX_RST_DATA_LEN) {
853685295f4SBill Fenner                 length = MAX_RST_DATA_LEN;	/* can use -X for longer */
854ee67461eSJoseph Mingrone                 ND_PRINT("+");			/* indicate we truncate */
855685295f4SBill Fenner         }
856ee67461eSJoseph Mingrone         ND_PRINT(" ");
857ee67461eSJoseph Mingrone         while (length && sp < ndo->ndo_snapend) {
858ee67461eSJoseph Mingrone                 c = GET_U_1(sp);
859ee67461eSJoseph Mingrone                 sp++;
860ee67461eSJoseph Mingrone                 fn_print_char(ndo, c);
861ee67461eSJoseph Mingrone                 length--;
862685295f4SBill Fenner         }
863ee67461eSJoseph Mingrone         ND_PRINT("]");
864685295f4SBill Fenner }
8651de50e9fSSam Leffler 
8663340d773SGleb Smirnoff static void
print_tcp_fastopen_option(netdissect_options * ndo,const u_char * cp,u_int datalen,int exp)867ee67461eSJoseph Mingrone print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp,
8683340d773SGleb Smirnoff                           u_int datalen, int exp)
8693340d773SGleb Smirnoff {
8703340d773SGleb Smirnoff         u_int i;
8713340d773SGleb Smirnoff 
8723340d773SGleb Smirnoff         if (exp)
873ee67461eSJoseph Mingrone                 ND_PRINT("tfo");
8743340d773SGleb Smirnoff 
8753340d773SGleb Smirnoff         if (datalen == 0) {
8763340d773SGleb Smirnoff                 /* Fast Open Cookie Request */
877ee67461eSJoseph Mingrone                 ND_PRINT(" cookiereq");
8783340d773SGleb Smirnoff         } else {
8793340d773SGleb Smirnoff                 /* Fast Open Cookie */
8803340d773SGleb Smirnoff                 if (datalen % 2 != 0 || datalen < 4 || datalen > 16) {
881ee67461eSJoseph Mingrone                         nd_print_invalid(ndo);
8823340d773SGleb Smirnoff                 } else {
883ee67461eSJoseph Mingrone                         ND_PRINT(" cookie ");
8843340d773SGleb Smirnoff                         for (i = 0; i < datalen; ++i)
885ee67461eSJoseph Mingrone                                 ND_PRINT("%02x", GET_U_1(cp + i));
8863340d773SGleb Smirnoff                 }
8873340d773SGleb Smirnoff         }
8883340d773SGleb Smirnoff }
8893340d773SGleb Smirnoff 
8901de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
891ee67461eSJoseph Mingrone DIAG_OFF_DEPRECATION
8921de50e9fSSam Leffler static int
tcp_verify_signature(netdissect_options * ndo,const struct ip * ip,const struct tcphdr * tp,const u_char * data,u_int length,const u_char * rcvsig)8933c602fabSXin LI tcp_verify_signature(netdissect_options *ndo,
8943c602fabSXin LI                      const struct ip *ip, const struct tcphdr *tp,
895ee67461eSJoseph Mingrone                      const u_char *data, u_int length, const u_char *rcvsig)
8961de50e9fSSam Leffler {
8971de50e9fSSam Leffler         struct tcphdr tp1;
898f4d0c64aSSam Leffler         u_char sig[TCP_SIGLEN];
8991de50e9fSSam Leffler         char zero_proto = 0;
9001de50e9fSSam Leffler         MD5_CTX ctx;
9013c602fabSXin LI         uint16_t savecsum, tlen;
9023340d773SGleb Smirnoff         const struct ip6_hdr *ip6;
9033c602fabSXin LI         uint32_t len32;
9043c602fabSXin LI         uint8_t nxt;
9051de50e9fSSam Leffler 
9063c602fabSXin LI         if (data + length > ndo->ndo_snapend) {
907ee67461eSJoseph Mingrone                 ND_PRINT("snaplen too short, ");
90827df3f5dSRui Paulo                 return (CANT_CHECK_SIGNATURE);
90927df3f5dSRui Paulo         }
91027df3f5dSRui Paulo 
9111de50e9fSSam Leffler         tp1 = *tp;
9121de50e9fSSam Leffler 
9133c602fabSXin LI         if (ndo->ndo_sigsecret == NULL) {
914ee67461eSJoseph Mingrone                 ND_PRINT("shared secret not supplied with -M, ");
9151de50e9fSSam Leffler                 return (CANT_CHECK_SIGNATURE);
91627df3f5dSRui Paulo         }
9171de50e9fSSam Leffler 
9181de50e9fSSam Leffler         MD5_Init(&ctx);
9191de50e9fSSam Leffler         /*
9201de50e9fSSam Leffler          * Step 1: Update MD5 hash with IP pseudo-header.
9211de50e9fSSam Leffler          */
9221de50e9fSSam Leffler         if (IP_V(ip) == 4) {
9233340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip->ip_src, sizeof(ip->ip_src));
9243340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip->ip_dst, sizeof(ip->ip_dst));
9253340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&zero_proto, sizeof(zero_proto));
9263340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip->ip_p, sizeof(ip->ip_p));
927ee67461eSJoseph Mingrone                 tlen = GET_BE_U_2(ip->ip_len) - IP_HL(ip) * 4;
9281de50e9fSSam Leffler                 tlen = htons(tlen);
9293340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&tlen, sizeof(tlen));
9301de50e9fSSam Leffler         } else if (IP_V(ip) == 6) {
9313340d773SGleb Smirnoff                 ip6 = (const struct ip6_hdr *)ip;
9323340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
9333340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
934ee67461eSJoseph Mingrone                 len32 = htonl(GET_BE_U_2(ip6->ip6_plen));
9353340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&len32, sizeof(len32));
9361de50e9fSSam Leffler                 nxt = 0;
9373340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
9383340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
9393340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
9401de50e9fSSam Leffler                 nxt = IPPROTO_TCP;
9413340d773SGleb Smirnoff                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
94227df3f5dSRui Paulo         } else {
943ee67461eSJoseph Mingrone                 ND_PRINT("IP version not 4 or 6, ");
9441de50e9fSSam Leffler                 return (CANT_CHECK_SIGNATURE);
94527df3f5dSRui Paulo         }
9461de50e9fSSam Leffler 
9471de50e9fSSam Leffler         /*
9481de50e9fSSam Leffler          * Step 2: Update MD5 hash with TCP header, excluding options.
9491de50e9fSSam Leffler          * The TCP checksum must be set to zero.
9501de50e9fSSam Leffler          */
951ee67461eSJoseph Mingrone         memcpy(&savecsum, tp1.th_sum, sizeof(savecsum));
952ee67461eSJoseph Mingrone         memset(tp1.th_sum, 0, sizeof(tp1.th_sum));
9533340d773SGleb Smirnoff         MD5_Update(&ctx, (const char *)&tp1, sizeof(struct tcphdr));
954ee67461eSJoseph Mingrone         memcpy(tp1.th_sum, &savecsum, sizeof(tp1.th_sum));
9551de50e9fSSam Leffler         /*
9561de50e9fSSam Leffler          * Step 3: Update MD5 hash with TCP segment data, if present.
9571de50e9fSSam Leffler          */
9581de50e9fSSam Leffler         if (length > 0)
9591de50e9fSSam Leffler                 MD5_Update(&ctx, data, length);
9601de50e9fSSam Leffler         /*
9611de50e9fSSam Leffler          * Step 4: Update MD5 hash with shared secret.
9621de50e9fSSam Leffler          */
9633c602fabSXin LI         MD5_Update(&ctx, ndo->ndo_sigsecret, strlen(ndo->ndo_sigsecret));
9641de50e9fSSam Leffler         MD5_Final(sig, &ctx);
9651de50e9fSSam Leffler 
966b5bfcb5dSMax Laier         if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
9671de50e9fSSam Leffler                 return (SIGNATURE_VALID);
9681de50e9fSSam Leffler         else
9691de50e9fSSam Leffler                 return (SIGNATURE_INVALID);
9701de50e9fSSam Leffler }
971ee67461eSJoseph Mingrone DIAG_ON_DEPRECATION
9721de50e9fSSam Leffler #endif /* HAVE_LIBCRYPTO */
973