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