xref: /aosp_15_r20/external/tcpdump/print-tcp.c (revision 05b00f6010a2396e3db2409989fc67270046269f)
1*05b00f60SXin Li /*	$NetBSD: print-tcp.c,v 1.9 2007/07/26 18:15:12 plunky Exp $	*/
2*05b00f60SXin Li 
3*05b00f60SXin Li /*
4*05b00f60SXin Li  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
5*05b00f60SXin Li  *	The Regents of the University of California.  All rights reserved.
6*05b00f60SXin Li  *
7*05b00f60SXin Li  * Copyright (c) 1999-2004 The tcpdump.org project
8*05b00f60SXin Li  *
9*05b00f60SXin Li  * Redistribution and use in source and binary forms, with or without
10*05b00f60SXin Li  * modification, are permitted provided that: (1) source code distributions
11*05b00f60SXin Li  * retain the above copyright notice and this paragraph in its entirety, (2)
12*05b00f60SXin Li  * distributions including binary code include the above copyright notice and
13*05b00f60SXin Li  * this paragraph in its entirety in the documentation or other materials
14*05b00f60SXin Li  * provided with the distribution, and (3) all advertising materials mentioning
15*05b00f60SXin Li  * features or use of this software display the following acknowledgement:
16*05b00f60SXin Li  * ``This product includes software developed by the University of California,
17*05b00f60SXin Li  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
18*05b00f60SXin Li  * the University nor the names of its contributors may be used to endorse
19*05b00f60SXin Li  * or promote products derived from this software without specific prior
20*05b00f60SXin Li  * written permission.
21*05b00f60SXin Li  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22*05b00f60SXin Li  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23*05b00f60SXin Li  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24*05b00f60SXin Li  */
25*05b00f60SXin Li 
26*05b00f60SXin Li /* \summary: TCP printer */
27*05b00f60SXin Li 
28*05b00f60SXin Li #ifndef lint
29*05b00f60SXin Li #else
30*05b00f60SXin Li __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
31*05b00f60SXin Li #endif
32*05b00f60SXin Li 
33*05b00f60SXin Li #ifdef HAVE_CONFIG_H
34*05b00f60SXin Li #include <config.h>
35*05b00f60SXin Li #endif
36*05b00f60SXin Li 
37*05b00f60SXin Li #include "netdissect-stdinc.h"
38*05b00f60SXin Li 
39*05b00f60SXin Li #include <stdlib.h>
40*05b00f60SXin Li #include <string.h>
41*05b00f60SXin Li 
42*05b00f60SXin Li #include "netdissect.h"
43*05b00f60SXin Li #include "addrtoname.h"
44*05b00f60SXin Li #include "extract.h"
45*05b00f60SXin Li 
46*05b00f60SXin Li #include "diag-control.h"
47*05b00f60SXin Li 
48*05b00f60SXin Li #include "tcp.h"
49*05b00f60SXin Li 
50*05b00f60SXin Li #include "ip.h"
51*05b00f60SXin Li #include "ip6.h"
52*05b00f60SXin Li #include "ipproto.h"
53*05b00f60SXin Li #include "rpc_auth.h"
54*05b00f60SXin Li #include "rpc_msg.h"
55*05b00f60SXin Li 
56*05b00f60SXin Li #ifdef HAVE_LIBCRYPTO
57*05b00f60SXin Li #include <openssl/md5.h>
58*05b00f60SXin Li #include "signature.h"
59*05b00f60SXin Li 
60*05b00f60SXin Li static int tcp_verify_signature(netdissect_options *ndo,
61*05b00f60SXin Li                                 const struct ip *ip, const struct tcphdr *tp,
62*05b00f60SXin Li                                 const u_char *data, u_int length, const u_char *rcvsig);
63*05b00f60SXin Li #endif
64*05b00f60SXin Li 
65*05b00f60SXin Li static void print_tcp_rst_data(netdissect_options *, const u_char *sp, u_int length);
66*05b00f60SXin Li static void print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp,
67*05b00f60SXin Li                                       u_int datalen, int exp);
68*05b00f60SXin Li 
69*05b00f60SXin Li #define MAX_RST_DATA_LEN	30
70*05b00f60SXin Li 
71*05b00f60SXin Li 
72*05b00f60SXin Li struct tha {
73*05b00f60SXin Li         nd_ipv4 src;
74*05b00f60SXin Li         nd_ipv4 dst;
75*05b00f60SXin Li         u_int port;
76*05b00f60SXin Li };
77*05b00f60SXin Li 
78*05b00f60SXin Li struct tcp_seq_hash {
79*05b00f60SXin Li         struct tcp_seq_hash *nxt;
80*05b00f60SXin Li         struct tha addr;
81*05b00f60SXin Li         uint32_t seq;
82*05b00f60SXin Li         uint32_t ack;
83*05b00f60SXin Li };
84*05b00f60SXin Li 
85*05b00f60SXin Li struct tha6 {
86*05b00f60SXin Li         nd_ipv6 src;
87*05b00f60SXin Li         nd_ipv6 dst;
88*05b00f60SXin Li         u_int port;
89*05b00f60SXin Li };
90*05b00f60SXin Li 
91*05b00f60SXin Li struct tcp_seq_hash6 {
92*05b00f60SXin Li         struct tcp_seq_hash6 *nxt;
93*05b00f60SXin Li         struct tha6 addr;
94*05b00f60SXin Li         uint32_t seq;
95*05b00f60SXin Li         uint32_t ack;
96*05b00f60SXin Li };
97*05b00f60SXin Li 
98*05b00f60SXin Li #define TSEQ_HASHSIZE 919
99*05b00f60SXin Li 
100*05b00f60SXin Li /* These tcp options do not have the size octet */
101*05b00f60SXin Li #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
102*05b00f60SXin Li 
103*05b00f60SXin Li static struct tcp_seq_hash tcp_seq_hash4[TSEQ_HASHSIZE];
104*05b00f60SXin Li static struct tcp_seq_hash6 tcp_seq_hash6[TSEQ_HASHSIZE];
105*05b00f60SXin Li 
106*05b00f60SXin Li static const struct tok tcp_flag_values[] = {
107*05b00f60SXin Li         { TH_FIN, "F" },
108*05b00f60SXin Li         { TH_SYN, "S" },
109*05b00f60SXin Li         { TH_RST, "R" },
110*05b00f60SXin Li         { TH_PUSH, "P" },
111*05b00f60SXin Li         { TH_ACK, "." },
112*05b00f60SXin Li         { TH_URG, "U" },
113*05b00f60SXin Li         { TH_ECNECHO, "E" },
114*05b00f60SXin Li         { TH_CWR, "W" },
115*05b00f60SXin Li         { 0, NULL }
116*05b00f60SXin Li };
117*05b00f60SXin Li 
118*05b00f60SXin Li static const struct tok tcp_option_values[] = {
119*05b00f60SXin Li         { TCPOPT_EOL, "eol" },
120*05b00f60SXin Li         { TCPOPT_NOP, "nop" },
121*05b00f60SXin Li         { TCPOPT_MAXSEG, "mss" },
122*05b00f60SXin Li         { TCPOPT_WSCALE, "wscale" },
123*05b00f60SXin Li         { TCPOPT_SACKOK, "sackOK" },
124*05b00f60SXin Li         { TCPOPT_SACK, "sack" },
125*05b00f60SXin Li         { TCPOPT_ECHO, "echo" },
126*05b00f60SXin Li         { TCPOPT_ECHOREPLY, "echoreply" },
127*05b00f60SXin Li         { TCPOPT_TIMESTAMP, "TS" },
128*05b00f60SXin Li         { TCPOPT_CC, "cc" },
129*05b00f60SXin Li         { TCPOPT_CCNEW, "ccnew" },
130*05b00f60SXin Li         { TCPOPT_CCECHO, "" },
131*05b00f60SXin Li         { TCPOPT_SIGNATURE, "md5" },
132*05b00f60SXin Li         { TCPOPT_SCPS, "scps" },
133*05b00f60SXin Li         { TCPOPT_UTO, "uto" },
134*05b00f60SXin Li         { TCPOPT_TCPAO, "tcp-ao" },
135*05b00f60SXin Li         { TCPOPT_MPTCP, "mptcp" },
136*05b00f60SXin Li         { TCPOPT_FASTOPEN, "tfo" },
137*05b00f60SXin Li         { TCPOPT_EXPERIMENT2, "exp" },
138*05b00f60SXin Li         { 0, NULL }
139*05b00f60SXin Li };
140*05b00f60SXin Li 
141*05b00f60SXin Li static uint16_t
tcp_cksum(netdissect_options * ndo,const struct ip * ip,const struct tcphdr * tp,u_int len)142*05b00f60SXin Li tcp_cksum(netdissect_options *ndo,
143*05b00f60SXin Li           const struct ip *ip,
144*05b00f60SXin Li           const struct tcphdr *tp,
145*05b00f60SXin Li           u_int len)
146*05b00f60SXin Li {
147*05b00f60SXin Li         return nextproto4_cksum(ndo, ip, (const uint8_t *)tp, len, len,
148*05b00f60SXin Li                                 IPPROTO_TCP);
149*05b00f60SXin Li }
150*05b00f60SXin Li 
151*05b00f60SXin Li static uint16_t
tcp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct tcphdr * tp,u_int len)152*05b00f60SXin Li tcp6_cksum(netdissect_options *ndo,
153*05b00f60SXin Li            const struct ip6_hdr *ip6,
154*05b00f60SXin Li            const struct tcphdr *tp,
155*05b00f60SXin Li            u_int len)
156*05b00f60SXin Li {
157*05b00f60SXin Li         return nextproto6_cksum(ndo, ip6, (const uint8_t *)tp, len, len,
158*05b00f60SXin Li                                 IPPROTO_TCP);
159*05b00f60SXin Li }
160*05b00f60SXin Li 
161*05b00f60SXin Li void
tcp_print(netdissect_options * ndo,const u_char * bp,u_int length,const u_char * bp2,int fragmented)162*05b00f60SXin Li tcp_print(netdissect_options *ndo,
163*05b00f60SXin Li           const u_char *bp, u_int length,
164*05b00f60SXin Li           const u_char *bp2, int fragmented)
165*05b00f60SXin Li {
166*05b00f60SXin Li         const struct tcphdr *tp;
167*05b00f60SXin Li         const struct ip *ip;
168*05b00f60SXin Li         u_char flags;
169*05b00f60SXin Li         u_int hlen;
170*05b00f60SXin Li         char ch;
171*05b00f60SXin Li         uint16_t sport, dport, win, urp;
172*05b00f60SXin Li         uint32_t seq, ack, thseq, thack;
173*05b00f60SXin Li         u_int utoval;
174*05b00f60SXin Li         uint16_t magic;
175*05b00f60SXin Li         int rev;
176*05b00f60SXin Li         const struct ip6_hdr *ip6;
177*05b00f60SXin Li         u_int header_len;	/* Header length in bytes */
178*05b00f60SXin Li 
179*05b00f60SXin Li         ndo->ndo_protocol = "tcp";
180*05b00f60SXin Li         tp = (const struct tcphdr *)bp;
181*05b00f60SXin Li         ip = (const struct ip *)bp2;
182*05b00f60SXin Li         if (IP_V(ip) == 6)
183*05b00f60SXin Li                 ip6 = (const struct ip6_hdr *)bp2;
184*05b00f60SXin Li         else
185*05b00f60SXin Li                 ip6 = NULL;
186*05b00f60SXin Li         ch = '\0';
187*05b00f60SXin Li         if (!ND_TTEST_2(tp->th_dport)) {
188*05b00f60SXin Li                 if (ip6) {
189*05b00f60SXin Li                         ND_PRINT("%s > %s:",
190*05b00f60SXin Li                                  GET_IP6ADDR_STRING(ip6->ip6_src),
191*05b00f60SXin Li                                  GET_IP6ADDR_STRING(ip6->ip6_dst));
192*05b00f60SXin Li                 } else {
193*05b00f60SXin Li                         ND_PRINT("%s > %s:",
194*05b00f60SXin Li                                  GET_IPADDR_STRING(ip->ip_src),
195*05b00f60SXin Li                                  GET_IPADDR_STRING(ip->ip_dst));
196*05b00f60SXin Li                 }
197*05b00f60SXin Li                 nd_print_trunc(ndo);
198*05b00f60SXin Li                 return;
199*05b00f60SXin Li         }
200*05b00f60SXin Li 
201*05b00f60SXin Li         sport = GET_BE_U_2(tp->th_sport);
202*05b00f60SXin Li         dport = GET_BE_U_2(tp->th_dport);
203*05b00f60SXin Li 
204*05b00f60SXin Li         if (ip6) {
205*05b00f60SXin Li                 if (GET_U_1(ip6->ip6_nxt) == IPPROTO_TCP) {
206*05b00f60SXin Li                         ND_PRINT("%s.%s > %s.%s: ",
207*05b00f60SXin Li                                  GET_IP6ADDR_STRING(ip6->ip6_src),
208*05b00f60SXin Li                                  tcpport_string(ndo, sport),
209*05b00f60SXin Li                                  GET_IP6ADDR_STRING(ip6->ip6_dst),
210*05b00f60SXin Li                                  tcpport_string(ndo, dport));
211*05b00f60SXin Li                 } else {
212*05b00f60SXin Li                         ND_PRINT("%s > %s: ",
213*05b00f60SXin Li                                  tcpport_string(ndo, sport), tcpport_string(ndo, dport));
214*05b00f60SXin Li                 }
215*05b00f60SXin Li         } else {
216*05b00f60SXin Li                 if (GET_U_1(ip->ip_p) == IPPROTO_TCP) {
217*05b00f60SXin Li                         ND_PRINT("%s.%s > %s.%s: ",
218*05b00f60SXin Li                                  GET_IPADDR_STRING(ip->ip_src),
219*05b00f60SXin Li                                  tcpport_string(ndo, sport),
220*05b00f60SXin Li                                  GET_IPADDR_STRING(ip->ip_dst),
221*05b00f60SXin Li                                  tcpport_string(ndo, dport));
222*05b00f60SXin Li                 } else {
223*05b00f60SXin Li                         ND_PRINT("%s > %s: ",
224*05b00f60SXin Li                                  tcpport_string(ndo, sport), tcpport_string(ndo, dport));
225*05b00f60SXin Li                 }
226*05b00f60SXin Li         }
227*05b00f60SXin Li 
228*05b00f60SXin Li         ND_TCHECK_SIZE(tp);
229*05b00f60SXin Li 
230*05b00f60SXin Li         hlen = TH_OFF(tp) * 4;
231*05b00f60SXin Li 
232*05b00f60SXin Li         if (hlen < sizeof(*tp)) {
233*05b00f60SXin Li                 ND_PRINT(" tcp %u [bad hdr length %u - too short, < %zu]",
234*05b00f60SXin Li                          length - hlen, hlen, sizeof(*tp));
235*05b00f60SXin Li                 return;
236*05b00f60SXin Li         }
237*05b00f60SXin Li 
238*05b00f60SXin Li         seq = GET_BE_U_4(tp->th_seq);
239*05b00f60SXin Li         ack = GET_BE_U_4(tp->th_ack);
240*05b00f60SXin Li         win = GET_BE_U_2(tp->th_win);
241*05b00f60SXin Li         urp = GET_BE_U_2(tp->th_urp);
242*05b00f60SXin Li 
243*05b00f60SXin Li         if (ndo->ndo_qflag) {
244*05b00f60SXin Li                 ND_PRINT("tcp %u", length - hlen);
245*05b00f60SXin Li                 if (hlen > length) {
246*05b00f60SXin Li                         ND_PRINT(" [bad hdr length %u - too long, > %u]",
247*05b00f60SXin Li                                  hlen, length);
248*05b00f60SXin Li                 }
249*05b00f60SXin Li                 return;
250*05b00f60SXin Li         }
251*05b00f60SXin Li 
252*05b00f60SXin Li         flags = GET_U_1(tp->th_flags);
253*05b00f60SXin Li         ND_PRINT("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags));
254*05b00f60SXin Li 
255*05b00f60SXin Li         if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
256*05b00f60SXin Li                 /*
257*05b00f60SXin Li                  * Find (or record) the initial sequence numbers for
258*05b00f60SXin Li                  * this conversation.  (we pick an arbitrary
259*05b00f60SXin Li                  * collating order so there's only one entry for
260*05b00f60SXin Li                  * both directions).
261*05b00f60SXin Li                  */
262*05b00f60SXin Li                 rev = 0;
263*05b00f60SXin Li                 if (ip6) {
264*05b00f60SXin Li                         struct tcp_seq_hash6 *th;
265*05b00f60SXin Li                         struct tcp_seq_hash6 *tcp_seq_hash;
266*05b00f60SXin Li                         const void *src, *dst;
267*05b00f60SXin Li                         struct tha6 tha;
268*05b00f60SXin Li 
269*05b00f60SXin Li                         tcp_seq_hash = tcp_seq_hash6;
270*05b00f60SXin Li                         src = (const void *)ip6->ip6_src;
271*05b00f60SXin Li                         dst = (const void *)ip6->ip6_dst;
272*05b00f60SXin Li                         if (sport > dport)
273*05b00f60SXin Li                                 rev = 1;
274*05b00f60SXin Li                         else if (sport == dport) {
275*05b00f60SXin Li                                 if (UNALIGNED_MEMCMP(src, dst, sizeof(ip6->ip6_dst)) > 0)
276*05b00f60SXin Li                                         rev = 1;
277*05b00f60SXin Li                         }
278*05b00f60SXin Li                         if (rev) {
279*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.src, dst, sizeof(ip6->ip6_dst));
280*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.dst, src, sizeof(ip6->ip6_src));
281*05b00f60SXin Li                                 tha.port = ((u_int)dport) << 16 | sport;
282*05b00f60SXin Li                         } else {
283*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.dst, dst, sizeof(ip6->ip6_dst));
284*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.src, src, sizeof(ip6->ip6_src));
285*05b00f60SXin Li                                 tha.port = ((u_int)sport) << 16 | dport;
286*05b00f60SXin Li                         }
287*05b00f60SXin Li 
288*05b00f60SXin Li                         for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
289*05b00f60SXin Li                              th->nxt; th = th->nxt)
290*05b00f60SXin Li                                 if (memcmp((char *)&tha, (char *)&th->addr,
291*05b00f60SXin Li                                            sizeof(th->addr)) == 0)
292*05b00f60SXin Li                                         break;
293*05b00f60SXin Li 
294*05b00f60SXin Li                         if (!th->nxt || (flags & TH_SYN)) {
295*05b00f60SXin Li                                 /* didn't find it or new conversation */
296*05b00f60SXin Li                                 /* calloc() return used by the 'tcp_seq_hash6'
297*05b00f60SXin Li                                    hash table: do not free() */
298*05b00f60SXin Li                                 if (th->nxt == NULL) {
299*05b00f60SXin Li                                         th->nxt = (struct tcp_seq_hash6 *)
300*05b00f60SXin Li                                                 calloc(1, sizeof(*th));
301*05b00f60SXin Li                                         if (th->nxt == NULL)
302*05b00f60SXin Li                                                 (*ndo->ndo_error)(ndo,
303*05b00f60SXin Li                                                         S_ERR_ND_MEM_ALLOC,
304*05b00f60SXin Li                                                         "%s: calloc", __func__);
305*05b00f60SXin Li                                 }
306*05b00f60SXin Li                                 th->addr = tha;
307*05b00f60SXin Li                                 if (rev)
308*05b00f60SXin Li                                         th->ack = seq, th->seq = ack - 1;
309*05b00f60SXin Li                                 else
310*05b00f60SXin Li                                         th->seq = seq, th->ack = ack - 1;
311*05b00f60SXin Li                         } else {
312*05b00f60SXin Li                                 if (rev)
313*05b00f60SXin Li                                         seq -= th->ack, ack -= th->seq;
314*05b00f60SXin Li                                 else
315*05b00f60SXin Li                                         seq -= th->seq, ack -= th->ack;
316*05b00f60SXin Li                         }
317*05b00f60SXin Li 
318*05b00f60SXin Li                         thseq = th->seq;
319*05b00f60SXin Li                         thack = th->ack;
320*05b00f60SXin Li                 } else {
321*05b00f60SXin Li                         struct tcp_seq_hash *th;
322*05b00f60SXin Li                         struct tcp_seq_hash *tcp_seq_hash;
323*05b00f60SXin Li                         struct tha tha;
324*05b00f60SXin Li 
325*05b00f60SXin Li                         tcp_seq_hash = tcp_seq_hash4;
326*05b00f60SXin Li                         if (sport > dport)
327*05b00f60SXin Li                                 rev = 1;
328*05b00f60SXin Li                         else if (sport == dport) {
329*05b00f60SXin Li                                 if (UNALIGNED_MEMCMP(ip->ip_src, ip->ip_dst, sizeof(ip->ip_dst)) > 0)
330*05b00f60SXin Li                                         rev = 1;
331*05b00f60SXin Li                         }
332*05b00f60SXin Li                         if (rev) {
333*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.src, ip->ip_dst,
334*05b00f60SXin Li                                                  sizeof(ip->ip_dst));
335*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.dst, ip->ip_src,
336*05b00f60SXin Li                                                  sizeof(ip->ip_src));
337*05b00f60SXin Li                                 tha.port = ((u_int)dport) << 16 | sport;
338*05b00f60SXin Li                         } else {
339*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.dst, ip->ip_dst,
340*05b00f60SXin Li                                                  sizeof(ip->ip_dst));
341*05b00f60SXin Li                                 UNALIGNED_MEMCPY(&tha.src, ip->ip_src,
342*05b00f60SXin Li                                                  sizeof(ip->ip_src));
343*05b00f60SXin Li                                 tha.port = ((u_int)sport) << 16 | dport;
344*05b00f60SXin Li                         }
345*05b00f60SXin Li 
346*05b00f60SXin Li                         for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
347*05b00f60SXin Li                              th->nxt; th = th->nxt)
348*05b00f60SXin Li                                 if (memcmp((char *)&tha, (char *)&th->addr,
349*05b00f60SXin Li                                            sizeof(th->addr)) == 0)
350*05b00f60SXin Li                                         break;
351*05b00f60SXin Li 
352*05b00f60SXin Li                         if (!th->nxt || (flags & TH_SYN)) {
353*05b00f60SXin Li                                 /* didn't find it or new conversation */
354*05b00f60SXin Li                                 /* calloc() return used by the 'tcp_seq_hash4'
355*05b00f60SXin Li                                    hash table: do not free() */
356*05b00f60SXin Li                                 if (th->nxt == NULL) {
357*05b00f60SXin Li                                         th->nxt = (struct tcp_seq_hash *)
358*05b00f60SXin Li                                                 calloc(1, sizeof(*th));
359*05b00f60SXin Li                                         if (th->nxt == NULL)
360*05b00f60SXin Li                                                 (*ndo->ndo_error)(ndo,
361*05b00f60SXin Li                                                         S_ERR_ND_MEM_ALLOC,
362*05b00f60SXin Li                                                         "%s: calloc", __func__);
363*05b00f60SXin Li                                 }
364*05b00f60SXin Li                                 th->addr = tha;
365*05b00f60SXin Li                                 if (rev)
366*05b00f60SXin Li                                         th->ack = seq, th->seq = ack - 1;
367*05b00f60SXin Li                                 else
368*05b00f60SXin Li                                         th->seq = seq, th->ack = ack - 1;
369*05b00f60SXin Li                         } else {
370*05b00f60SXin Li                                 if (rev)
371*05b00f60SXin Li                                         seq -= th->ack, ack -= th->seq;
372*05b00f60SXin Li                                 else
373*05b00f60SXin Li                                         seq -= th->seq, ack -= th->ack;
374*05b00f60SXin Li                         }
375*05b00f60SXin Li 
376*05b00f60SXin Li                         thseq = th->seq;
377*05b00f60SXin Li                         thack = th->ack;
378*05b00f60SXin Li                 }
379*05b00f60SXin Li         } else {
380*05b00f60SXin Li                 /*fool gcc*/
381*05b00f60SXin Li                 thseq = thack = rev = 0;
382*05b00f60SXin Li         }
383*05b00f60SXin Li         if (hlen > length) {
384*05b00f60SXin Li                 ND_PRINT(" [bad hdr length %u - too long, > %u]",
385*05b00f60SXin Li                          hlen, length);
386*05b00f60SXin Li                 return;
387*05b00f60SXin Li         }
388*05b00f60SXin Li 
389*05b00f60SXin Li         if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
390*05b00f60SXin Li                 /* Check the checksum, if possible. */
391*05b00f60SXin Li                 uint16_t sum, tcp_sum;
392*05b00f60SXin Li 
393*05b00f60SXin Li                 if (IP_V(ip) == 4) {
394*05b00f60SXin Li                         if (ND_TTEST_LEN(tp->th_sport, length)) {
395*05b00f60SXin Li                                 sum = tcp_cksum(ndo, ip, tp, length);
396*05b00f60SXin Li                                 tcp_sum = GET_BE_U_2(tp->th_sum);
397*05b00f60SXin Li 
398*05b00f60SXin Li                                 ND_PRINT(", cksum 0x%04x", tcp_sum);
399*05b00f60SXin Li                                 if (sum != 0)
400*05b00f60SXin Li                                         ND_PRINT(" (incorrect -> 0x%04x)",
401*05b00f60SXin Li                                             in_cksum_shouldbe(tcp_sum, sum));
402*05b00f60SXin Li                                 else
403*05b00f60SXin Li                                         ND_PRINT(" (correct)");
404*05b00f60SXin Li                         }
405*05b00f60SXin Li                 } else if (IP_V(ip) == 6) {
406*05b00f60SXin Li                         if (ND_TTEST_LEN(tp->th_sport, length)) {
407*05b00f60SXin Li                                 sum = tcp6_cksum(ndo, ip6, tp, length);
408*05b00f60SXin Li                                 tcp_sum = GET_BE_U_2(tp->th_sum);
409*05b00f60SXin Li 
410*05b00f60SXin Li                                 ND_PRINT(", cksum 0x%04x", tcp_sum);
411*05b00f60SXin Li                                 if (sum != 0)
412*05b00f60SXin Li                                         ND_PRINT(" (incorrect -> 0x%04x)",
413*05b00f60SXin Li                                             in_cksum_shouldbe(tcp_sum, sum));
414*05b00f60SXin Li                                 else
415*05b00f60SXin Li                                         ND_PRINT(" (correct)");
416*05b00f60SXin Li 
417*05b00f60SXin Li                         }
418*05b00f60SXin Li                 }
419*05b00f60SXin Li         }
420*05b00f60SXin Li 
421*05b00f60SXin Li         length -= hlen;
422*05b00f60SXin Li         if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
423*05b00f60SXin Li                 ND_PRINT(", seq %u", seq);
424*05b00f60SXin Li 
425*05b00f60SXin Li                 if (length > 0) {
426*05b00f60SXin Li                         ND_PRINT(":%u", seq + length);
427*05b00f60SXin Li                 }
428*05b00f60SXin Li         }
429*05b00f60SXin Li 
430*05b00f60SXin Li         if (flags & TH_ACK) {
431*05b00f60SXin Li                 ND_PRINT(", ack %u", ack);
432*05b00f60SXin Li         }
433*05b00f60SXin Li 
434*05b00f60SXin Li         ND_PRINT(", win %u", win);
435*05b00f60SXin Li 
436*05b00f60SXin Li         if (flags & TH_URG)
437*05b00f60SXin Li                 ND_PRINT(", urg %u", urp);
438*05b00f60SXin Li         /*
439*05b00f60SXin Li          * Handle any options.
440*05b00f60SXin Li          */
441*05b00f60SXin Li         if (hlen > sizeof(*tp)) {
442*05b00f60SXin Li                 const u_char *cp;
443*05b00f60SXin Li                 u_int i, opt, datalen;
444*05b00f60SXin Li                 u_int len;
445*05b00f60SXin Li 
446*05b00f60SXin Li                 hlen -= sizeof(*tp);
447*05b00f60SXin Li                 cp = (const u_char *)tp + sizeof(*tp);
448*05b00f60SXin Li                 ND_PRINT(", options [");
449*05b00f60SXin Li                 while (hlen > 0) {
450*05b00f60SXin Li                         if (ch != '\0')
451*05b00f60SXin Li                                 ND_PRINT("%c", ch);
452*05b00f60SXin Li                         opt = GET_U_1(cp);
453*05b00f60SXin Li                         cp++;
454*05b00f60SXin Li                         if (ZEROLENOPT(opt))
455*05b00f60SXin Li                                 len = 1;
456*05b00f60SXin Li                         else {
457*05b00f60SXin Li                                 len = GET_U_1(cp);
458*05b00f60SXin Li                                 cp++;	/* total including type, len */
459*05b00f60SXin Li                                 if (len < 2 || len > hlen)
460*05b00f60SXin Li                                         goto bad;
461*05b00f60SXin Li                                 --hlen;		/* account for length byte */
462*05b00f60SXin Li                         }
463*05b00f60SXin Li                         --hlen;			/* account for type byte */
464*05b00f60SXin Li                         datalen = 0;
465*05b00f60SXin Li 
466*05b00f60SXin Li /* Bail if "l" bytes of data are not left or were not captured  */
467*05b00f60SXin Li #define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); }
468*05b00f60SXin Li 
469*05b00f60SXin Li 
470*05b00f60SXin Li                         ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt));
471*05b00f60SXin Li 
472*05b00f60SXin Li                         switch (opt) {
473*05b00f60SXin Li 
474*05b00f60SXin Li                         case TCPOPT_MAXSEG:
475*05b00f60SXin Li                                 datalen = 2;
476*05b00f60SXin Li                                 LENCHECK(datalen);
477*05b00f60SXin Li                                 ND_PRINT(" %u", GET_BE_U_2(cp));
478*05b00f60SXin Li                                 break;
479*05b00f60SXin Li 
480*05b00f60SXin Li                         case TCPOPT_WSCALE:
481*05b00f60SXin Li                                 datalen = 1;
482*05b00f60SXin Li                                 LENCHECK(datalen);
483*05b00f60SXin Li                                 ND_PRINT(" %u", GET_U_1(cp));
484*05b00f60SXin Li                                 break;
485*05b00f60SXin Li 
486*05b00f60SXin Li                         case TCPOPT_SACK:
487*05b00f60SXin Li                                 datalen = len - 2;
488*05b00f60SXin Li                                 if (datalen % 8 != 0) {
489*05b00f60SXin Li                                         ND_PRINT(" invalid sack");
490*05b00f60SXin Li                                 } else {
491*05b00f60SXin Li                                         uint32_t s, e;
492*05b00f60SXin Li 
493*05b00f60SXin Li                                         ND_PRINT(" %u ", datalen / 8);
494*05b00f60SXin Li                                         for (i = 0; i < datalen; i += 8) {
495*05b00f60SXin Li                                                 LENCHECK(i + 4);
496*05b00f60SXin Li                                                 s = GET_BE_U_4(cp + i);
497*05b00f60SXin Li                                                 LENCHECK(i + 8);
498*05b00f60SXin Li                                                 e = GET_BE_U_4(cp + i + 4);
499*05b00f60SXin Li                                                 if (rev) {
500*05b00f60SXin Li                                                         s -= thseq;
501*05b00f60SXin Li                                                         e -= thseq;
502*05b00f60SXin Li                                                 } else {
503*05b00f60SXin Li                                                         s -= thack;
504*05b00f60SXin Li                                                         e -= thack;
505*05b00f60SXin Li                                                 }
506*05b00f60SXin Li                                                 ND_PRINT("{%u:%u}", s, e);
507*05b00f60SXin Li                                         }
508*05b00f60SXin Li                                 }
509*05b00f60SXin Li                                 break;
510*05b00f60SXin Li 
511*05b00f60SXin Li                         case TCPOPT_CC:
512*05b00f60SXin Li                         case TCPOPT_CCNEW:
513*05b00f60SXin Li                         case TCPOPT_CCECHO:
514*05b00f60SXin Li                         case TCPOPT_ECHO:
515*05b00f60SXin Li                         case TCPOPT_ECHOREPLY:
516*05b00f60SXin Li 
517*05b00f60SXin Li                                 /*
518*05b00f60SXin Li                                  * those options share their semantics.
519*05b00f60SXin Li                                  * fall through
520*05b00f60SXin Li                                  */
521*05b00f60SXin Li                                 datalen = 4;
522*05b00f60SXin Li                                 LENCHECK(datalen);
523*05b00f60SXin Li                                 ND_PRINT(" %u", GET_BE_U_4(cp));
524*05b00f60SXin Li                                 break;
525*05b00f60SXin Li 
526*05b00f60SXin Li                         case TCPOPT_TIMESTAMP:
527*05b00f60SXin Li                                 datalen = 8;
528*05b00f60SXin Li                                 LENCHECK(datalen);
529*05b00f60SXin Li                                 ND_PRINT(" val %u ecr %u",
530*05b00f60SXin Li                                              GET_BE_U_4(cp),
531*05b00f60SXin Li                                              GET_BE_U_4(cp + 4));
532*05b00f60SXin Li                                 break;
533*05b00f60SXin Li 
534*05b00f60SXin Li                         case TCPOPT_SIGNATURE:
535*05b00f60SXin Li                                 datalen = TCP_SIGLEN;
536*05b00f60SXin Li                                 LENCHECK(datalen);
537*05b00f60SXin Li                                 ND_PRINT(" ");
538*05b00f60SXin Li #ifdef HAVE_LIBCRYPTO
539*05b00f60SXin Li                                 switch (tcp_verify_signature(ndo, ip, tp,
540*05b00f60SXin Li                                                              bp + TH_OFF(tp) * 4, length, cp)) {
541*05b00f60SXin Li 
542*05b00f60SXin Li                                 case SIGNATURE_VALID:
543*05b00f60SXin Li                                         ND_PRINT("valid");
544*05b00f60SXin Li                                         break;
545*05b00f60SXin Li 
546*05b00f60SXin Li                                 case SIGNATURE_INVALID:
547*05b00f60SXin Li                                         nd_print_invalid(ndo);
548*05b00f60SXin Li                                         break;
549*05b00f60SXin Li 
550*05b00f60SXin Li                                 case CANT_CHECK_SIGNATURE:
551*05b00f60SXin Li                                         ND_PRINT("can't check - ");
552*05b00f60SXin Li                                         for (i = 0; i < TCP_SIGLEN; ++i)
553*05b00f60SXin Li                                                 ND_PRINT("%02x",
554*05b00f60SXin Li                                                          GET_U_1(cp + i));
555*05b00f60SXin Li                                         break;
556*05b00f60SXin Li                                 }
557*05b00f60SXin Li #else
558*05b00f60SXin Li                                 for (i = 0; i < TCP_SIGLEN; ++i)
559*05b00f60SXin Li                                         ND_PRINT("%02x", GET_U_1(cp + i));
560*05b00f60SXin Li #endif
561*05b00f60SXin Li                                 break;
562*05b00f60SXin Li 
563*05b00f60SXin Li                         case TCPOPT_SCPS:
564*05b00f60SXin Li                                 datalen = 2;
565*05b00f60SXin Li                                 LENCHECK(datalen);
566*05b00f60SXin Li                                 ND_PRINT(" cap %02x id %u", GET_U_1(cp),
567*05b00f60SXin Li                                          GET_U_1(cp + 1));
568*05b00f60SXin Li                                 break;
569*05b00f60SXin Li 
570*05b00f60SXin Li                         case TCPOPT_TCPAO:
571*05b00f60SXin Li                                 datalen = len - 2;
572*05b00f60SXin Li                                 /* RFC 5925 Section 2.2:
573*05b00f60SXin Li                                  * "The Length value MUST be greater than or equal to 4."
574*05b00f60SXin Li                                  * (This includes the Kind and Length fields already processed
575*05b00f60SXin Li                                  * at this point.)
576*05b00f60SXin Li                                  */
577*05b00f60SXin Li                                 if (datalen < 2) {
578*05b00f60SXin Li                                         nd_print_invalid(ndo);
579*05b00f60SXin Li                                 } else {
580*05b00f60SXin Li                                         LENCHECK(1);
581*05b00f60SXin Li                                         ND_PRINT(" keyid %u", GET_U_1(cp));
582*05b00f60SXin Li                                         LENCHECK(2);
583*05b00f60SXin Li                                         ND_PRINT(" rnextkeyid %u",
584*05b00f60SXin Li                                                  GET_U_1(cp + 1));
585*05b00f60SXin Li                                         if (datalen > 2) {
586*05b00f60SXin Li                                                 ND_PRINT(" mac 0x");
587*05b00f60SXin Li                                                 for (i = 2; i < datalen; i++) {
588*05b00f60SXin Li                                                         LENCHECK(i + 1);
589*05b00f60SXin Li                                                         ND_PRINT("%02x",
590*05b00f60SXin Li                                                                  GET_U_1(cp + i));
591*05b00f60SXin Li                                                 }
592*05b00f60SXin Li                                         }
593*05b00f60SXin Li                                 }
594*05b00f60SXin Li                                 break;
595*05b00f60SXin Li 
596*05b00f60SXin Li                         case TCPOPT_EOL:
597*05b00f60SXin Li                         case TCPOPT_NOP:
598*05b00f60SXin Li                         case TCPOPT_SACKOK:
599*05b00f60SXin Li                                 /*
600*05b00f60SXin Li                                  * Nothing interesting.
601*05b00f60SXin Li                                  * fall through
602*05b00f60SXin Li                                  */
603*05b00f60SXin Li                                 break;
604*05b00f60SXin Li 
605*05b00f60SXin Li                         case TCPOPT_UTO:
606*05b00f60SXin Li                                 datalen = 2;
607*05b00f60SXin Li                                 LENCHECK(datalen);
608*05b00f60SXin Li                                 utoval = GET_BE_U_2(cp);
609*05b00f60SXin Li                                 ND_PRINT(" 0x%x", utoval);
610*05b00f60SXin Li                                 if (utoval & 0x0001)
611*05b00f60SXin Li                                         utoval = (utoval >> 1) * 60;
612*05b00f60SXin Li                                 else
613*05b00f60SXin Li                                         utoval >>= 1;
614*05b00f60SXin Li                                 ND_PRINT(" %u", utoval);
615*05b00f60SXin Li                                 break;
616*05b00f60SXin Li 
617*05b00f60SXin Li                         case TCPOPT_MPTCP:
618*05b00f60SXin Li                             {
619*05b00f60SXin Li                                 const u_char *snapend_save;
620*05b00f60SXin Li                                 int ret;
621*05b00f60SXin Li 
622*05b00f60SXin Li                                 datalen = len - 2;
623*05b00f60SXin Li                                 LENCHECK(datalen);
624*05b00f60SXin Li                                 /* Update the snapend to the end of the option
625*05b00f60SXin Li                                  * before calling mptcp_print(). Some options
626*05b00f60SXin Li                                  * (MPTCP or others) may be present after a
627*05b00f60SXin Li                                  * MPTCP option. This prevents that, in
628*05b00f60SXin Li                                  * mptcp_print(), the remaining length < the
629*05b00f60SXin Li                                  * remaining caplen.
630*05b00f60SXin Li                                  */
631*05b00f60SXin Li                                 snapend_save = ndo->ndo_snapend;
632*05b00f60SXin Li                                 ndo->ndo_snapend = ND_MIN(cp - 2 + len,
633*05b00f60SXin Li                                                           ndo->ndo_snapend);
634*05b00f60SXin Li                                 ret = mptcp_print(ndo, cp - 2, len, flags);
635*05b00f60SXin Li                                 ndo->ndo_snapend = snapend_save;
636*05b00f60SXin Li                                 if (!ret)
637*05b00f60SXin Li                                         goto bad;
638*05b00f60SXin Li                                 break;
639*05b00f60SXin Li                             }
640*05b00f60SXin Li 
641*05b00f60SXin Li                         case TCPOPT_FASTOPEN:
642*05b00f60SXin Li                                 datalen = len - 2;
643*05b00f60SXin Li                                 LENCHECK(datalen);
644*05b00f60SXin Li                                 ND_PRINT(" ");
645*05b00f60SXin Li                                 print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
646*05b00f60SXin Li                                 break;
647*05b00f60SXin Li 
648*05b00f60SXin Li                         case TCPOPT_EXPERIMENT2:
649*05b00f60SXin Li                                 datalen = len - 2;
650*05b00f60SXin Li                                 LENCHECK(datalen);
651*05b00f60SXin Li                                 if (datalen < 2)
652*05b00f60SXin Li                                         goto bad;
653*05b00f60SXin Li                                 /* RFC6994 */
654*05b00f60SXin Li                                 magic = GET_BE_U_2(cp);
655*05b00f60SXin Li                                 ND_PRINT("-");
656*05b00f60SXin Li 
657*05b00f60SXin Li                                 switch(magic) {
658*05b00f60SXin Li 
659*05b00f60SXin Li                                 case 0xf989: /* TCP Fast Open RFC 7413 */
660*05b00f60SXin Li                                         print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
661*05b00f60SXin Li                                         break;
662*05b00f60SXin Li 
663*05b00f60SXin Li                                 default:
664*05b00f60SXin Li                                         /* Unknown magic number */
665*05b00f60SXin Li                                         ND_PRINT("%04x", magic);
666*05b00f60SXin Li                                         break;
667*05b00f60SXin Li                                 }
668*05b00f60SXin Li                                 break;
669*05b00f60SXin Li 
670*05b00f60SXin Li                         default:
671*05b00f60SXin Li                                 datalen = len - 2;
672*05b00f60SXin Li                                 if (datalen)
673*05b00f60SXin Li                                         ND_PRINT(" 0x");
674*05b00f60SXin Li                                 for (i = 0; i < datalen; ++i) {
675*05b00f60SXin Li                                         LENCHECK(i + 1);
676*05b00f60SXin Li                                         ND_PRINT("%02x", GET_U_1(cp + i));
677*05b00f60SXin Li                                 }
678*05b00f60SXin Li                                 break;
679*05b00f60SXin Li                         }
680*05b00f60SXin Li 
681*05b00f60SXin Li                         /* Account for data printed */
682*05b00f60SXin Li                         cp += datalen;
683*05b00f60SXin Li                         hlen -= datalen;
684*05b00f60SXin Li 
685*05b00f60SXin Li                         /* Check specification against observed length */
686*05b00f60SXin Li                         ++datalen;		/* option octet */
687*05b00f60SXin Li                         if (!ZEROLENOPT(opt))
688*05b00f60SXin Li                                 ++datalen;	/* size octet */
689*05b00f60SXin Li                         if (datalen != len)
690*05b00f60SXin Li                                 ND_PRINT("[len %u]", len);
691*05b00f60SXin Li                         ch = ',';
692*05b00f60SXin Li                         if (opt == TCPOPT_EOL)
693*05b00f60SXin Li                                 break;
694*05b00f60SXin Li                 }
695*05b00f60SXin Li                 ND_PRINT("]");
696*05b00f60SXin Li         }
697*05b00f60SXin Li 
698*05b00f60SXin Li         /*
699*05b00f60SXin Li          * Print length field before crawling down the stack.
700*05b00f60SXin Li          */
701*05b00f60SXin Li         ND_PRINT(", length %u", length);
702*05b00f60SXin Li 
703*05b00f60SXin Li         if (length == 0)
704*05b00f60SXin Li                 return;
705*05b00f60SXin Li 
706*05b00f60SXin Li         /*
707*05b00f60SXin Li          * Decode payload if necessary.
708*05b00f60SXin Li          */
709*05b00f60SXin Li         header_len = TH_OFF(tp) * 4;
710*05b00f60SXin Li         /*
711*05b00f60SXin Li          * Do a bounds check before decoding the payload.
712*05b00f60SXin Li          * At least the header data is required.
713*05b00f60SXin Li          */
714*05b00f60SXin Li         if (!ND_TTEST_LEN(bp, header_len)) {
715*05b00f60SXin Li                 ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
716*05b00f60SXin Li                          ND_BYTES_AVAILABLE_AFTER(bp), header_len);
717*05b00f60SXin Li                 nd_trunc_longjmp(ndo);
718*05b00f60SXin Li         }
719*05b00f60SXin Li         bp += header_len;
720*05b00f60SXin Li         if ((flags & TH_RST) && ndo->ndo_vflag) {
721*05b00f60SXin Li                 print_tcp_rst_data(ndo, bp, length);
722*05b00f60SXin Li                 return;
723*05b00f60SXin Li         }
724*05b00f60SXin Li 
725*05b00f60SXin Li         if (ndo->ndo_packettype) {
726*05b00f60SXin Li                 switch (ndo->ndo_packettype) {
727*05b00f60SXin Li                 case PT_ZMTP1:
728*05b00f60SXin Li                         zmtp1_print(ndo, bp, length);
729*05b00f60SXin Li                         break;
730*05b00f60SXin Li                 case PT_RESP:
731*05b00f60SXin Li                         resp_print(ndo, bp, length);
732*05b00f60SXin Li                         break;
733*05b00f60SXin Li                 case PT_DOMAIN:
734*05b00f60SXin Li                         /* over_tcp: TRUE, is_mdns: FALSE */
735*05b00f60SXin Li                         domain_print(ndo, bp, length, TRUE, FALSE);
736*05b00f60SXin Li                         break;
737*05b00f60SXin Li                 }
738*05b00f60SXin Li                 return;
739*05b00f60SXin Li         }
740*05b00f60SXin Li 
741*05b00f60SXin Li         if (IS_SRC_OR_DST_PORT(TELNET_PORT)) {
742*05b00f60SXin Li                 telnet_print(ndo, bp, length);
743*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(SMTP_PORT)) {
744*05b00f60SXin Li                 ND_PRINT(": ");
745*05b00f60SXin Li                 smtp_print(ndo, bp, length);
746*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(WHOIS_PORT)) {
747*05b00f60SXin Li                 ND_PRINT(": ");
748*05b00f60SXin Li                 whois_print(ndo, bp, length);
749*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(BGP_PORT))
750*05b00f60SXin Li                 bgp_print(ndo, bp, length);
751*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(PPTP_PORT))
752*05b00f60SXin Li                 pptp_print(ndo, bp);
753*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(REDIS_PORT))
754*05b00f60SXin Li                 resp_print(ndo, bp, length);
755*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(SSH_PORT))
756*05b00f60SXin Li                 ssh_print(ndo, bp, length);
757*05b00f60SXin Li #ifdef ENABLE_SMB
758*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(NETBIOS_SSN_PORT))
759*05b00f60SXin Li                 nbt_tcp_print(ndo, bp, length);
760*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(SMB_PORT))
761*05b00f60SXin Li                 smb_tcp_print(ndo, bp, length);
762*05b00f60SXin Li #endif
763*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(BEEP_PORT))
764*05b00f60SXin Li                 beep_print(ndo, bp, length);
765*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(OPENFLOW_PORT_OLD) || IS_SRC_OR_DST_PORT(OPENFLOW_PORT_IANA))
766*05b00f60SXin Li                 openflow_print(ndo, bp, length);
767*05b00f60SXin Li         else if (IS_SRC_OR_DST_PORT(FTP_PORT)) {
768*05b00f60SXin Li                 ND_PRINT(": ");
769*05b00f60SXin Li                 ftp_print(ndo, bp, length);
770*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(HTTP_PORT) || IS_SRC_OR_DST_PORT(HTTP_PORT_ALT)) {
771*05b00f60SXin Li                 ND_PRINT(": ");
772*05b00f60SXin Li                 http_print(ndo, bp, length);
773*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(RTSP_PORT) || IS_SRC_OR_DST_PORT(RTSP_PORT_ALT)) {
774*05b00f60SXin Li                 ND_PRINT(": ");
775*05b00f60SXin Li                 rtsp_print(ndo, bp, length);
776*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(NAMESERVER_PORT)) {
777*05b00f60SXin Li                 /* over_tcp: TRUE, is_mdns: FALSE */
778*05b00f60SXin Li                 domain_print(ndo, bp, length, TRUE, FALSE);
779*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(MSDP_PORT)) {
780*05b00f60SXin Li                 msdp_print(ndo, bp, length);
781*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(RPKI_RTR_PORT)) {
782*05b00f60SXin Li                 rpki_rtr_print(ndo, bp, length);
783*05b00f60SXin Li         } else if (IS_SRC_OR_DST_PORT(LDP_PORT)) {
784*05b00f60SXin Li                 ldp_print(ndo, bp, length);
785*05b00f60SXin Li         } else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
786*05b00f60SXin Li                  length >= 4 && ND_TTEST_4(bp)) {
787*05b00f60SXin Li                 /*
788*05b00f60SXin Li                  * If data present, header length valid, and NFS port used,
789*05b00f60SXin Li                  * assume NFS.
790*05b00f60SXin Li                  * Pass offset of data plus 4 bytes for RPC TCP msg length
791*05b00f60SXin Li                  * to NFS print routines.
792*05b00f60SXin Li                  */
793*05b00f60SXin Li                 uint32_t fraglen;
794*05b00f60SXin Li                 const struct sunrpc_msg *rp;
795*05b00f60SXin Li                 enum sunrpc_msg_type direction;
796*05b00f60SXin Li 
797*05b00f60SXin Li                 fraglen = GET_BE_U_4(bp) & 0x7FFFFFFF;
798*05b00f60SXin Li                 if (fraglen > (length) - 4)
799*05b00f60SXin Li                         fraglen = (length) - 4;
800*05b00f60SXin Li                 rp = (const struct sunrpc_msg *)(bp + 4);
801*05b00f60SXin Li                 if (ND_TTEST_4(rp->rm_direction)) {
802*05b00f60SXin Li                         direction = (enum sunrpc_msg_type) GET_BE_U_4(rp->rm_direction);
803*05b00f60SXin Li                         if (dport == NFS_PORT && direction == SUNRPC_CALL) {
804*05b00f60SXin Li                                 ND_PRINT(": NFS request xid %u ",
805*05b00f60SXin Li                                          GET_BE_U_4(rp->rm_xid));
806*05b00f60SXin Li                                 nfsreq_noaddr_print(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
807*05b00f60SXin Li                                 return;
808*05b00f60SXin Li                         }
809*05b00f60SXin Li                         if (sport == NFS_PORT && direction == SUNRPC_REPLY) {
810*05b00f60SXin Li                                 ND_PRINT(": NFS reply xid %u ",
811*05b00f60SXin Li                                          GET_BE_U_4(rp->rm_xid));
812*05b00f60SXin Li                                 nfsreply_noaddr_print(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
813*05b00f60SXin Li                                 return;
814*05b00f60SXin Li                         }
815*05b00f60SXin Li                 }
816*05b00f60SXin Li         }
817*05b00f60SXin Li 
818*05b00f60SXin Li         return;
819*05b00f60SXin Li bad:
820*05b00f60SXin Li         ND_PRINT("[bad opt]");
821*05b00f60SXin Li         if (ch != '\0')
822*05b00f60SXin Li                 ND_PRINT("]");
823*05b00f60SXin Li         return;
824*05b00f60SXin Li trunc:
825*05b00f60SXin Li         nd_print_trunc(ndo);
826*05b00f60SXin Li         if (ch != '\0')
827*05b00f60SXin Li                 ND_PRINT(">");
828*05b00f60SXin Li }
829*05b00f60SXin Li 
830*05b00f60SXin Li /*
831*05b00f60SXin Li  * RFC1122 says the following on data in RST segments:
832*05b00f60SXin Li  *
833*05b00f60SXin Li  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
834*05b00f60SXin Li  *
835*05b00f60SXin Li  *            A TCP SHOULD allow a received RST segment to include data.
836*05b00f60SXin Li  *
837*05b00f60SXin Li  *            DISCUSSION
838*05b00f60SXin Li  *                 It has been suggested that a RST segment could contain
839*05b00f60SXin Li  *                 ASCII text that encoded and explained the cause of the
840*05b00f60SXin Li  *                 RST.  No standard has yet been established for such
841*05b00f60SXin Li  *                 data.
842*05b00f60SXin Li  *
843*05b00f60SXin Li  */
844*05b00f60SXin Li 
845*05b00f60SXin Li static void
print_tcp_rst_data(netdissect_options * ndo,const u_char * sp,u_int length)846*05b00f60SXin Li print_tcp_rst_data(netdissect_options *ndo,
847*05b00f60SXin Li                    const u_char *sp, u_int length)
848*05b00f60SXin Li {
849*05b00f60SXin Li         u_char c;
850*05b00f60SXin Li 
851*05b00f60SXin Li         ND_PRINT(ND_TTEST_LEN(sp, length) ? " [RST" : " [!RST");
852*05b00f60SXin Li         if (length > MAX_RST_DATA_LEN) {
853*05b00f60SXin Li                 length = MAX_RST_DATA_LEN;	/* can use -X for longer */
854*05b00f60SXin Li                 ND_PRINT("+");			/* indicate we truncate */
855*05b00f60SXin Li         }
856*05b00f60SXin Li         ND_PRINT(" ");
857*05b00f60SXin Li         while (length && sp < ndo->ndo_snapend) {
858*05b00f60SXin Li                 c = GET_U_1(sp);
859*05b00f60SXin Li                 sp++;
860*05b00f60SXin Li                 fn_print_char(ndo, c);
861*05b00f60SXin Li                 length--;
862*05b00f60SXin Li         }
863*05b00f60SXin Li         ND_PRINT("]");
864*05b00f60SXin Li }
865*05b00f60SXin Li 
866*05b00f60SXin Li static void
print_tcp_fastopen_option(netdissect_options * ndo,const u_char * cp,u_int datalen,int exp)867*05b00f60SXin Li print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp,
868*05b00f60SXin Li                           u_int datalen, int exp)
869*05b00f60SXin Li {
870*05b00f60SXin Li         u_int i;
871*05b00f60SXin Li 
872*05b00f60SXin Li         if (exp)
873*05b00f60SXin Li                 ND_PRINT("tfo");
874*05b00f60SXin Li 
875*05b00f60SXin Li         if (datalen == 0) {
876*05b00f60SXin Li                 /* Fast Open Cookie Request */
877*05b00f60SXin Li                 ND_PRINT(" cookiereq");
878*05b00f60SXin Li         } else {
879*05b00f60SXin Li                 /* Fast Open Cookie */
880*05b00f60SXin Li                 if (datalen % 2 != 0 || datalen < 4 || datalen > 16) {
881*05b00f60SXin Li                         nd_print_invalid(ndo);
882*05b00f60SXin Li                 } else {
883*05b00f60SXin Li                         ND_PRINT(" cookie ");
884*05b00f60SXin Li                         for (i = 0; i < datalen; ++i)
885*05b00f60SXin Li                                 ND_PRINT("%02x", GET_U_1(cp + i));
886*05b00f60SXin Li                 }
887*05b00f60SXin Li         }
888*05b00f60SXin Li }
889*05b00f60SXin Li 
890*05b00f60SXin Li #ifdef HAVE_LIBCRYPTO
891*05b00f60SXin Li DIAG_OFF_DEPRECATION
892*05b00f60SXin Li 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)893*05b00f60SXin Li tcp_verify_signature(netdissect_options *ndo,
894*05b00f60SXin Li                      const struct ip *ip, const struct tcphdr *tp,
895*05b00f60SXin Li                      const u_char *data, u_int length, const u_char *rcvsig)
896*05b00f60SXin Li {
897*05b00f60SXin Li         struct tcphdr tp1;
898*05b00f60SXin Li         u_char sig[TCP_SIGLEN];
899*05b00f60SXin Li         char zero_proto = 0;
900*05b00f60SXin Li         MD5_CTX ctx;
901*05b00f60SXin Li         uint16_t savecsum, tlen;
902*05b00f60SXin Li         const struct ip6_hdr *ip6;
903*05b00f60SXin Li         uint32_t len32;
904*05b00f60SXin Li         uint8_t nxt;
905*05b00f60SXin Li 
906*05b00f60SXin Li         if (data + length > ndo->ndo_snapend) {
907*05b00f60SXin Li                 ND_PRINT("snaplen too short, ");
908*05b00f60SXin Li                 return (CANT_CHECK_SIGNATURE);
909*05b00f60SXin Li         }
910*05b00f60SXin Li 
911*05b00f60SXin Li         tp1 = *tp;
912*05b00f60SXin Li 
913*05b00f60SXin Li         if (ndo->ndo_sigsecret == NULL) {
914*05b00f60SXin Li                 ND_PRINT("shared secret not supplied with -M, ");
915*05b00f60SXin Li                 return (CANT_CHECK_SIGNATURE);
916*05b00f60SXin Li         }
917*05b00f60SXin Li 
918*05b00f60SXin Li         MD5_Init(&ctx);
919*05b00f60SXin Li         /*
920*05b00f60SXin Li          * Step 1: Update MD5 hash with IP pseudo-header.
921*05b00f60SXin Li          */
922*05b00f60SXin Li         if (IP_V(ip) == 4) {
923*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&ip->ip_src, sizeof(ip->ip_src));
924*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&ip->ip_dst, sizeof(ip->ip_dst));
925*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&zero_proto, sizeof(zero_proto));
926*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&ip->ip_p, sizeof(ip->ip_p));
927*05b00f60SXin Li                 tlen = GET_BE_U_2(ip->ip_len) - IP_HL(ip) * 4;
928*05b00f60SXin Li                 tlen = htons(tlen);
929*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&tlen, sizeof(tlen));
930*05b00f60SXin Li         } else if (IP_V(ip) == 6) {
931*05b00f60SXin Li                 ip6 = (const struct ip6_hdr *)ip;
932*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
933*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
934*05b00f60SXin Li                 len32 = htonl(GET_BE_U_2(ip6->ip6_plen));
935*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&len32, sizeof(len32));
936*05b00f60SXin Li                 nxt = 0;
937*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
938*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
939*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
940*05b00f60SXin Li                 nxt = IPPROTO_TCP;
941*05b00f60SXin Li                 MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
942*05b00f60SXin Li         } else {
943*05b00f60SXin Li                 ND_PRINT("IP version not 4 or 6, ");
944*05b00f60SXin Li                 return (CANT_CHECK_SIGNATURE);
945*05b00f60SXin Li         }
946*05b00f60SXin Li 
947*05b00f60SXin Li         /*
948*05b00f60SXin Li          * Step 2: Update MD5 hash with TCP header, excluding options.
949*05b00f60SXin Li          * The TCP checksum must be set to zero.
950*05b00f60SXin Li          */
951*05b00f60SXin Li         memcpy(&savecsum, tp1.th_sum, sizeof(savecsum));
952*05b00f60SXin Li         memset(tp1.th_sum, 0, sizeof(tp1.th_sum));
953*05b00f60SXin Li         MD5_Update(&ctx, (const char *)&tp1, sizeof(struct tcphdr));
954*05b00f60SXin Li         memcpy(tp1.th_sum, &savecsum, sizeof(tp1.th_sum));
955*05b00f60SXin Li         /*
956*05b00f60SXin Li          * Step 3: Update MD5 hash with TCP segment data, if present.
957*05b00f60SXin Li          */
958*05b00f60SXin Li         if (length > 0)
959*05b00f60SXin Li                 MD5_Update(&ctx, data, length);
960*05b00f60SXin Li         /*
961*05b00f60SXin Li          * Step 4: Update MD5 hash with shared secret.
962*05b00f60SXin Li          */
963*05b00f60SXin Li         MD5_Update(&ctx, ndo->ndo_sigsecret, strlen(ndo->ndo_sigsecret));
964*05b00f60SXin Li         MD5_Final(sig, &ctx);
965*05b00f60SXin Li 
966*05b00f60SXin Li         if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
967*05b00f60SXin Li                 return (SIGNATURE_VALID);
968*05b00f60SXin Li         else
969*05b00f60SXin Li                 return (SIGNATURE_INVALID);
970*05b00f60SXin Li }
971*05b00f60SXin Li DIAG_ON_DEPRECATION
972*05b00f60SXin Li #endif /* HAVE_LIBCRYPTO */
973