1a5779b6eSRui Paulo /* $NetBSD: print-tcp.c,v 1.9 2007/07/26 18:15:12 plunky Exp $ */
2a5779b6eSRui Paulo
34edb46e9SPaul Traina /*
44644f044SBill Fenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
54edb46e9SPaul Traina * The Regents of the University of California. All rights reserved.
64edb46e9SPaul Traina *
71de50e9fSSam Leffler * Copyright (c) 1999-2004 The tcpdump.org project
81de50e9fSSam Leffler *
94edb46e9SPaul Traina * Redistribution and use in source and binary forms, with or without
104edb46e9SPaul Traina * modification, are permitted provided that: (1) source code distributions
114edb46e9SPaul Traina * retain the above copyright notice and this paragraph in its entirety, (2)
124edb46e9SPaul Traina * distributions including binary code include the above copyright notice and
134edb46e9SPaul Traina * this paragraph in its entirety in the documentation or other materials
144edb46e9SPaul Traina * provided with the distribution, and (3) all advertising materials mentioning
154edb46e9SPaul Traina * features or use of this software display the following acknowledgement:
164edb46e9SPaul Traina * ``This product includes software developed by the University of California,
174edb46e9SPaul Traina * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
184edb46e9SPaul Traina * the University nor the names of its contributors may be used to endorse
194edb46e9SPaul Traina * or promote products derived from this software without specific prior
204edb46e9SPaul Traina * written permission.
214edb46e9SPaul Traina * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
224edb46e9SPaul Traina * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
234edb46e9SPaul Traina * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
244edb46e9SPaul Traina */
254edb46e9SPaul Traina
263340d773SGleb Smirnoff /* \summary: TCP printer */
273340d773SGleb Smirnoff
284edb46e9SPaul Traina #ifndef lint
29a5779b6eSRui Paulo #else
30a5779b6eSRui Paulo __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
31b0453382SBill Fenner #endif
32b0453382SBill Fenner
33ee67461eSJoseph Mingrone #include <config.h>
344edb46e9SPaul Traina
35ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
364edb46e9SPaul Traina
374edb46e9SPaul Traina #include <stdlib.h>
384edb46e9SPaul Traina #include <string.h>
394edb46e9SPaul Traina
403340d773SGleb Smirnoff #include "netdissect.h"
414edb46e9SPaul Traina #include "addrtoname.h"
424edb46e9SPaul Traina #include "extract.h"
434edb46e9SPaul Traina
44ee67461eSJoseph Mingrone #include "diag-control.h"
45ee67461eSJoseph Mingrone
46685295f4SBill Fenner #include "tcp.h"
47685295f4SBill Fenner
48685295f4SBill Fenner #include "ip.h"
49685295f4SBill Fenner #include "ip6.h"
505b0fe478SBruce M Simpson #include "ipproto.h"
511de50e9fSSam Leffler #include "rpc_auth.h"
521de50e9fSSam Leffler #include "rpc_msg.h"
53685295f4SBill Fenner
541de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
551de50e9fSSam Leffler #include <openssl/md5.h>
563340d773SGleb Smirnoff #include "signature.h"
571de50e9fSSam Leffler
583c602fabSXin LI static int tcp_verify_signature(netdissect_options *ndo,
593c602fabSXin LI const struct ip *ip, const struct tcphdr *tp,
60ee67461eSJoseph Mingrone const u_char *data, u_int length, const u_char *rcvsig);
611de50e9fSSam Leffler #endif
621de50e9fSSam Leffler
63ee67461eSJoseph Mingrone static void print_tcp_rst_data(netdissect_options *, const u_char *sp, u_int length);
64ee67461eSJoseph Mingrone static void print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp,
653340d773SGleb Smirnoff u_int datalen, int exp);
66685295f4SBill Fenner
67685295f4SBill Fenner #define MAX_RST_DATA_LEN 30
68685295f4SBill Fenner
69685295f4SBill Fenner
704edb46e9SPaul Traina struct tha {
71ee67461eSJoseph Mingrone nd_ipv4 src;
72ee67461eSJoseph Mingrone nd_ipv4 dst;
734edb46e9SPaul Traina u_int port;
744edb46e9SPaul Traina };
754edb46e9SPaul Traina
764edb46e9SPaul Traina struct tcp_seq_hash {
774edb46e9SPaul Traina struct tcp_seq_hash *nxt;
784edb46e9SPaul Traina struct tha addr;
79ee67461eSJoseph Mingrone uint32_t seq;
80ee67461eSJoseph Mingrone uint32_t ack;
814edb46e9SPaul Traina };
824edb46e9SPaul Traina
833c602fabSXin LI struct tha6 {
84ee67461eSJoseph Mingrone nd_ipv6 src;
85ee67461eSJoseph Mingrone nd_ipv6 dst;
863c602fabSXin LI u_int port;
873c602fabSXin LI };
883c602fabSXin LI
893c602fabSXin LI struct tcp_seq_hash6 {
903c602fabSXin LI struct tcp_seq_hash6 *nxt;
913c602fabSXin LI struct tha6 addr;
92ee67461eSJoseph Mingrone uint32_t seq;
93ee67461eSJoseph Mingrone uint32_t ack;
943c602fabSXin LI };
953c602fabSXin LI
964edb46e9SPaul Traina #define TSEQ_HASHSIZE 919
974edb46e9SPaul Traina
98ee67461eSJoseph Mingrone /* These tcp options do not have the size octet */
994edb46e9SPaul Traina #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
1004edb46e9SPaul Traina
1013c602fabSXin LI static struct tcp_seq_hash tcp_seq_hash4[TSEQ_HASHSIZE];
1023c602fabSXin LI static struct tcp_seq_hash6 tcp_seq_hash6[TSEQ_HASHSIZE];
1034edb46e9SPaul Traina
1043c602fabSXin LI static const struct tok tcp_flag_values[] = {
105a5779b6eSRui Paulo { TH_FIN, "F" },
106a5779b6eSRui Paulo { TH_SYN, "S" },
107a5779b6eSRui Paulo { TH_RST, "R" },
108a5779b6eSRui Paulo { TH_PUSH, "P" },
109a5779b6eSRui Paulo { TH_ACK, "." },
110a5779b6eSRui Paulo { TH_URG, "U" },
111a5779b6eSRui Paulo { TH_ECNECHO, "E" },
112a5779b6eSRui Paulo { TH_CWR, "W" },
113a5779b6eSRui Paulo { 0, NULL }
114a5779b6eSRui Paulo };
1154edb46e9SPaul Traina
1163c602fabSXin LI static const struct tok tcp_option_values[] = {
117a5779b6eSRui Paulo { TCPOPT_EOL, "eol" },
118a5779b6eSRui Paulo { TCPOPT_NOP, "nop" },
119a5779b6eSRui Paulo { TCPOPT_MAXSEG, "mss" },
120a5779b6eSRui Paulo { TCPOPT_WSCALE, "wscale" },
121a5779b6eSRui Paulo { TCPOPT_SACKOK, "sackOK" },
122a5779b6eSRui Paulo { TCPOPT_SACK, "sack" },
123a5779b6eSRui Paulo { TCPOPT_ECHO, "echo" },
124a5779b6eSRui Paulo { TCPOPT_ECHOREPLY, "echoreply" },
125a5779b6eSRui Paulo { TCPOPT_TIMESTAMP, "TS" },
126a5779b6eSRui Paulo { TCPOPT_CC, "cc" },
127a5779b6eSRui Paulo { TCPOPT_CCNEW, "ccnew" },
128*0a7e5f1fSJoseph Mingrone { TCPOPT_CCECHO, "ccecho" },
129a5779b6eSRui Paulo { TCPOPT_SIGNATURE, "md5" },
1303340d773SGleb Smirnoff { TCPOPT_SCPS, "scps" },
131ce3ed1caSRui Paulo { TCPOPT_UTO, "uto" },
1323340d773SGleb Smirnoff { TCPOPT_TCPAO, "tcp-ao" },
1333c602fabSXin LI { TCPOPT_MPTCP, "mptcp" },
1343340d773SGleb Smirnoff { TCPOPT_FASTOPEN, "tfo" },
1353c602fabSXin LI { TCPOPT_EXPERIMENT2, "exp" },
136a5779b6eSRui Paulo { 0, NULL }
137a5779b6eSRui Paulo };
138685295f4SBill Fenner
139ee67461eSJoseph Mingrone static uint16_t
tcp_cksum(netdissect_options * ndo,const struct ip * ip,const struct tcphdr * tp,u_int len)1403c602fabSXin LI tcp_cksum(netdissect_options *ndo,
141ee67461eSJoseph Mingrone const struct ip *ip,
142ee67461eSJoseph Mingrone const struct tcphdr *tp,
143ee67461eSJoseph Mingrone u_int len)
144685295f4SBill Fenner {
1453c602fabSXin LI return nextproto4_cksum(ndo, ip, (const uint8_t *)tp, len, len,
1463c602fabSXin LI IPPROTO_TCP);
147685295f4SBill Fenner }
148685295f4SBill Fenner
149ee67461eSJoseph Mingrone static uint16_t
tcp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct tcphdr * tp,u_int len)1503340d773SGleb Smirnoff tcp6_cksum(netdissect_options *ndo,
151ee67461eSJoseph Mingrone const struct ip6_hdr *ip6,
152ee67461eSJoseph Mingrone const struct tcphdr *tp,
153ee67461eSJoseph Mingrone u_int len)
1543340d773SGleb Smirnoff {
1553340d773SGleb Smirnoff return nextproto6_cksum(ndo, ip6, (const uint8_t *)tp, len, len,
1563340d773SGleb Smirnoff IPPROTO_TCP);
1573340d773SGleb Smirnoff }
1583340d773SGleb Smirnoff
1594edb46e9SPaul Traina void
tcp_print(netdissect_options * ndo,const u_char * bp,u_int length,const u_char * bp2,int fragmented)1603c602fabSXin LI tcp_print(netdissect_options *ndo,
161ee67461eSJoseph Mingrone const u_char *bp, u_int length,
162ee67461eSJoseph Mingrone const u_char *bp2, int fragmented)
1634edb46e9SPaul Traina {
164ee67461eSJoseph Mingrone const struct tcphdr *tp;
165ee67461eSJoseph Mingrone const struct ip *ip;
166ee67461eSJoseph Mingrone u_char flags;
167ee67461eSJoseph Mingrone u_int hlen;
168ee67461eSJoseph Mingrone char ch;
1693c602fabSXin LI uint16_t sport, dport, win, urp;
1703c602fabSXin LI uint32_t seq, ack, thseq, thack;
17127df3f5dSRui Paulo u_int utoval;
1723c602fabSXin LI uint16_t magic;
173ee67461eSJoseph Mingrone int rev;
174ee67461eSJoseph Mingrone const struct ip6_hdr *ip6;
175ee67461eSJoseph Mingrone u_int header_len; /* Header length in bytes */
1764edb46e9SPaul Traina
177ee67461eSJoseph Mingrone ndo->ndo_protocol = "tcp";
1783340d773SGleb Smirnoff tp = (const struct tcphdr *)bp;
1793340d773SGleb Smirnoff ip = (const struct ip *)bp2;
180685295f4SBill Fenner if (IP_V(ip) == 6)
1813340d773SGleb Smirnoff ip6 = (const struct ip6_hdr *)bp2;
182b0453382SBill Fenner else
183b0453382SBill Fenner ip6 = NULL;
1844edb46e9SPaul Traina ch = '\0';
185ee67461eSJoseph Mingrone if (!ND_TTEST_2(tp->th_dport)) {
186ee67461eSJoseph Mingrone if (ip6) {
187ee67461eSJoseph Mingrone ND_PRINT("%s > %s:",
188ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(ip6->ip6_src),
189ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(ip6->ip6_dst));
190ee67461eSJoseph Mingrone } else {
191ee67461eSJoseph Mingrone ND_PRINT("%s > %s:",
192ee67461eSJoseph Mingrone GET_IPADDR_STRING(ip->ip_src),
193ee67461eSJoseph Mingrone GET_IPADDR_STRING(ip->ip_dst));
194ee67461eSJoseph Mingrone }
195ee67461eSJoseph Mingrone nd_print_trunc(ndo);
1964edb46e9SPaul Traina return;
1974edb46e9SPaul Traina }
1984edb46e9SPaul Traina
199ee67461eSJoseph Mingrone sport = GET_BE_U_2(tp->th_sport);
200ee67461eSJoseph Mingrone dport = GET_BE_U_2(tp->th_dport);
201b0453382SBill Fenner
202b0453382SBill Fenner if (ip6) {
203ee67461eSJoseph Mingrone if (GET_U_1(ip6->ip6_nxt) == IPPROTO_TCP) {
204ee67461eSJoseph Mingrone ND_PRINT("%s.%s > %s.%s: ",
205ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(ip6->ip6_src),
2063340d773SGleb Smirnoff tcpport_string(ndo, sport),
207ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(ip6->ip6_dst),
208ee67461eSJoseph Mingrone tcpport_string(ndo, dport));
209b0453382SBill Fenner } else {
210ee67461eSJoseph Mingrone ND_PRINT("%s > %s: ",
211ee67461eSJoseph Mingrone tcpport_string(ndo, sport), tcpport_string(ndo, dport));
212b0453382SBill Fenner }
2133340d773SGleb Smirnoff } else {
214ee67461eSJoseph Mingrone if (GET_U_1(ip->ip_p) == IPPROTO_TCP) {
215ee67461eSJoseph Mingrone ND_PRINT("%s.%s > %s.%s: ",
216ee67461eSJoseph Mingrone GET_IPADDR_STRING(ip->ip_src),
2173340d773SGleb Smirnoff tcpport_string(ndo, sport),
218ee67461eSJoseph Mingrone GET_IPADDR_STRING(ip->ip_dst),
219ee67461eSJoseph Mingrone tcpport_string(ndo, dport));
220b0453382SBill Fenner } else {
221ee67461eSJoseph Mingrone ND_PRINT("%s > %s: ",
222ee67461eSJoseph Mingrone tcpport_string(ndo, sport), tcpport_string(ndo, dport));
223b0453382SBill Fenner }
224b0453382SBill Fenner }
225b0453382SBill Fenner
226ee67461eSJoseph Mingrone ND_TCHECK_SIZE(tp);
2273340d773SGleb Smirnoff
2283340d773SGleb Smirnoff hlen = TH_OFF(tp) * 4;
2293340d773SGleb Smirnoff
2301de50e9fSSam Leffler if (hlen < sizeof(*tp)) {
231ee67461eSJoseph Mingrone ND_PRINT(" tcp %u [bad hdr length %u - too short, < %zu]",
232ee67461eSJoseph Mingrone length - hlen, hlen, sizeof(*tp));
2331de50e9fSSam Leffler return;
2341de50e9fSSam Leffler }
2351de50e9fSSam Leffler
236ee67461eSJoseph Mingrone seq = GET_BE_U_4(tp->th_seq);
237ee67461eSJoseph Mingrone ack = GET_BE_U_4(tp->th_ack);
238ee67461eSJoseph Mingrone win = GET_BE_U_2(tp->th_win);
239ee67461eSJoseph Mingrone urp = GET_BE_U_2(tp->th_urp);
2404edb46e9SPaul Traina
2413c602fabSXin LI if (ndo->ndo_qflag) {
242ee67461eSJoseph Mingrone ND_PRINT("tcp %u", length - hlen);
2431de50e9fSSam Leffler if (hlen > length) {
244ee67461eSJoseph Mingrone ND_PRINT(" [bad hdr length %u - too long, > %u]",
245ee67461eSJoseph Mingrone hlen, length);
2461de50e9fSSam Leffler }
2474edb46e9SPaul Traina return;
2484edb46e9SPaul Traina }
249a5779b6eSRui Paulo
250ee67461eSJoseph Mingrone flags = GET_U_1(tp->th_flags);
251ee67461eSJoseph Mingrone ND_PRINT("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags));
2524edb46e9SPaul Traina
2533c602fabSXin LI if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
2544edb46e9SPaul Traina /*
2554edb46e9SPaul Traina * Find (or record) the initial sequence numbers for
2564edb46e9SPaul Traina * this conversation. (we pick an arbitrary
2574edb46e9SPaul Traina * collating order so there's only one entry for
2584edb46e9SPaul Traina * both directions).
2594edb46e9SPaul Traina */
260b0453382SBill Fenner rev = 0;
261b0453382SBill Fenner if (ip6) {
262ee67461eSJoseph Mingrone struct tcp_seq_hash6 *th;
2633c602fabSXin LI struct tcp_seq_hash6 *tcp_seq_hash;
264ee67461eSJoseph Mingrone const void *src, *dst;
2653c602fabSXin LI struct tha6 tha;
2663c602fabSXin LI
2673c602fabSXin LI tcp_seq_hash = tcp_seq_hash6;
268ee67461eSJoseph Mingrone src = (const void *)ip6->ip6_src;
269ee67461eSJoseph Mingrone dst = (const void *)ip6->ip6_dst;
270a90e161bSBill Fenner if (sport > dport)
271b0453382SBill Fenner rev = 1;
272a90e161bSBill Fenner else if (sport == dport) {
273ee67461eSJoseph Mingrone if (UNALIGNED_MEMCMP(src, dst, sizeof(ip6->ip6_dst)) > 0)
274b0453382SBill Fenner rev = 1;
275b0453382SBill Fenner }
276b0453382SBill Fenner if (rev) {
277ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.src, dst, sizeof(ip6->ip6_dst));
278ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.dst, src, sizeof(ip6->ip6_src));
27939e421e8SCy Schubert tha.port = ((u_int)dport) << 16 | sport;
280b0453382SBill Fenner } else {
281ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.dst, dst, sizeof(ip6->ip6_dst));
282ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.src, src, sizeof(ip6->ip6_src));
28339e421e8SCy Schubert tha.port = ((u_int)sport) << 16 | dport;
284b0453382SBill Fenner }
2854edb46e9SPaul Traina
2863c602fabSXin LI for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
2873c602fabSXin LI th->nxt; th = th->nxt)
2883c602fabSXin LI if (memcmp((char *)&tha, (char *)&th->addr,
2893c602fabSXin LI sizeof(th->addr)) == 0)
2903c602fabSXin LI break;
2913c602fabSXin LI
2923c602fabSXin LI if (!th->nxt || (flags & TH_SYN)) {
2933c602fabSXin LI /* didn't find it or new conversation */
294ee67461eSJoseph Mingrone /* calloc() return used by the 'tcp_seq_hash6'
295ee67461eSJoseph Mingrone hash table: do not free() */
2963c602fabSXin LI if (th->nxt == NULL) {
2973c602fabSXin LI th->nxt = (struct tcp_seq_hash6 *)
2983c602fabSXin LI calloc(1, sizeof(*th));
2993c602fabSXin LI if (th->nxt == NULL)
3003340d773SGleb Smirnoff (*ndo->ndo_error)(ndo,
301ee67461eSJoseph Mingrone S_ERR_ND_MEM_ALLOC,
302ee67461eSJoseph Mingrone "%s: calloc", __func__);
3033c602fabSXin LI }
3043c602fabSXin LI th->addr = tha;
3053c602fabSXin LI if (rev)
3063c602fabSXin LI th->ack = seq, th->seq = ack - 1;
3073c602fabSXin LI else
3083c602fabSXin LI th->seq = seq, th->ack = ack - 1;
3093c602fabSXin LI } else {
3103c602fabSXin LI if (rev)
3113c602fabSXin LI seq -= th->ack, ack -= th->seq;
3123c602fabSXin LI else
3133c602fabSXin LI seq -= th->seq, ack -= th->ack;
3143c602fabSXin LI }
3153c602fabSXin LI
3163c602fabSXin LI thseq = th->seq;
3173c602fabSXin LI thack = th->ack;
3183c602fabSXin LI } else {
319ee67461eSJoseph Mingrone struct tcp_seq_hash *th;
3203c602fabSXin LI struct tcp_seq_hash *tcp_seq_hash;
3213c602fabSXin LI struct tha tha;
3223c602fabSXin LI
3233c602fabSXin LI tcp_seq_hash = tcp_seq_hash4;
3243c602fabSXin LI if (sport > dport)
3253c602fabSXin LI rev = 1;
3263c602fabSXin LI else if (sport == dport) {
327ee67461eSJoseph Mingrone if (UNALIGNED_MEMCMP(ip->ip_src, ip->ip_dst, sizeof(ip->ip_dst)) > 0)
3283c602fabSXin LI rev = 1;
3293c602fabSXin LI }
3303c602fabSXin LI if (rev) {
331ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.src, ip->ip_dst,
332ee67461eSJoseph Mingrone sizeof(ip->ip_dst));
333ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.dst, ip->ip_src,
334ee67461eSJoseph Mingrone sizeof(ip->ip_src));
33539e421e8SCy Schubert tha.port = ((u_int)dport) << 16 | sport;
3363c602fabSXin LI } else {
337ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.dst, ip->ip_dst,
338ee67461eSJoseph Mingrone sizeof(ip->ip_dst));
339ee67461eSJoseph Mingrone UNALIGNED_MEMCPY(&tha.src, ip->ip_src,
340ee67461eSJoseph Mingrone sizeof(ip->ip_src));
34139e421e8SCy Schubert tha.port = ((u_int)sport) << 16 | dport;
3423c602fabSXin LI }
3433c602fabSXin LI
3444edb46e9SPaul Traina for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
3454edb46e9SPaul Traina th->nxt; th = th->nxt)
3465b0fe478SBruce M Simpson if (memcmp((char *)&tha, (char *)&th->addr,
3475b0fe478SBruce M Simpson sizeof(th->addr)) == 0)
3484edb46e9SPaul Traina break;
3494edb46e9SPaul Traina
350685295f4SBill Fenner if (!th->nxt || (flags & TH_SYN)) {
3514edb46e9SPaul Traina /* didn't find it or new conversation */
352ee67461eSJoseph Mingrone /* calloc() return used by the 'tcp_seq_hash4'
353ee67461eSJoseph Mingrone hash table: do not free() */
3544edb46e9SPaul Traina if (th->nxt == NULL) {
3554edb46e9SPaul Traina th->nxt = (struct tcp_seq_hash *)
3564edb46e9SPaul Traina calloc(1, sizeof(*th));
3574edb46e9SPaul Traina if (th->nxt == NULL)
3583340d773SGleb Smirnoff (*ndo->ndo_error)(ndo,
359ee67461eSJoseph Mingrone S_ERR_ND_MEM_ALLOC,
360ee67461eSJoseph Mingrone "%s: calloc", __func__);
3614edb46e9SPaul Traina }
3624edb46e9SPaul Traina th->addr = tha;
3634edb46e9SPaul Traina if (rev)
3644edb46e9SPaul Traina th->ack = seq, th->seq = ack - 1;
3654edb46e9SPaul Traina else
3664edb46e9SPaul Traina th->seq = seq, th->ack = ack - 1;
3674edb46e9SPaul Traina } else {
3684edb46e9SPaul Traina if (rev)
3694edb46e9SPaul Traina seq -= th->ack, ack -= th->seq;
3704edb46e9SPaul Traina else
3714edb46e9SPaul Traina seq -= th->seq, ack -= th->ack;
3724edb46e9SPaul Traina }
373685295f4SBill Fenner
374685295f4SBill Fenner thseq = th->seq;
375685295f4SBill Fenner thack = th->ack;
3763c602fabSXin LI }
377685295f4SBill Fenner } else {
378685295f4SBill Fenner /*fool gcc*/
3793c602fabSXin LI thseq = thack = rev = 0;
3804edb46e9SPaul Traina }
3814de76e31SBill Fenner if (hlen > length) {
382ee67461eSJoseph Mingrone ND_PRINT(" [bad hdr length %u - too long, > %u]",
383ee67461eSJoseph Mingrone hlen, length);
3844de76e31SBill Fenner return;
3854de76e31SBill Fenner }
386685295f4SBill Fenner
3873c602fabSXin LI if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
388cac3dcd5SXin LI /* Check the checksum, if possible. */
3893c602fabSXin LI uint16_t sum, tcp_sum;
390cac3dcd5SXin LI
391cac3dcd5SXin LI if (IP_V(ip) == 4) {
392ee67461eSJoseph Mingrone if (ND_TTEST_LEN(tp->th_sport, length)) {
3933c602fabSXin LI sum = tcp_cksum(ndo, ip, tp, length);
394ee67461eSJoseph Mingrone tcp_sum = GET_BE_U_2(tp->th_sum);
395cac3dcd5SXin LI
396ee67461eSJoseph Mingrone ND_PRINT(", cksum 0x%04x", tcp_sum);
397cac3dcd5SXin LI if (sum != 0)
398ee67461eSJoseph Mingrone ND_PRINT(" (incorrect -> 0x%04x)",
399ee67461eSJoseph Mingrone in_cksum_shouldbe(tcp_sum, sum));
400cac3dcd5SXin LI else
401ee67461eSJoseph Mingrone ND_PRINT(" (correct)");
402685295f4SBill Fenner }
403ee67461eSJoseph Mingrone } else if (IP_V(ip) == 6) {
404ee67461eSJoseph Mingrone if (ND_TTEST_LEN(tp->th_sport, length)) {
4053340d773SGleb Smirnoff sum = tcp6_cksum(ndo, ip6, tp, length);
406ee67461eSJoseph Mingrone tcp_sum = GET_BE_U_2(tp->th_sum);
407cac3dcd5SXin LI
408ee67461eSJoseph Mingrone ND_PRINT(", cksum 0x%04x", tcp_sum);
409cac3dcd5SXin LI if (sum != 0)
410ee67461eSJoseph Mingrone ND_PRINT(" (incorrect -> 0x%04x)",
411ee67461eSJoseph Mingrone in_cksum_shouldbe(tcp_sum, sum));
412cac3dcd5SXin LI else
413ee67461eSJoseph Mingrone ND_PRINT(" (correct)");
4141de50e9fSSam Leffler
415685295f4SBill Fenner }
416685295f4SBill Fenner }
417cac3dcd5SXin LI }
418685295f4SBill Fenner
4194edb46e9SPaul Traina length -= hlen;
4203c602fabSXin LI if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
421ee67461eSJoseph Mingrone ND_PRINT(", seq %u", seq);
4224edb46e9SPaul Traina
423a5779b6eSRui Paulo if (length > 0) {
424ee67461eSJoseph Mingrone ND_PRINT(":%u", seq + length);
425a5779b6eSRui Paulo }
426a5779b6eSRui Paulo }
427a5779b6eSRui Paulo
428a5779b6eSRui Paulo if (flags & TH_ACK) {
429ee67461eSJoseph Mingrone ND_PRINT(", ack %u", ack);
430a5779b6eSRui Paulo }
431a5779b6eSRui Paulo
432ee67461eSJoseph Mingrone ND_PRINT(", win %u", win);
4334edb46e9SPaul Traina
4344edb46e9SPaul Traina if (flags & TH_URG)
435ee67461eSJoseph Mingrone ND_PRINT(", urg %u", urp);
4364edb46e9SPaul Traina /*
4374edb46e9SPaul Traina * Handle any options.
4384edb46e9SPaul Traina */
4395b0fe478SBruce M Simpson if (hlen > sizeof(*tp)) {
440ee67461eSJoseph Mingrone const u_char *cp;
441ee67461eSJoseph Mingrone u_int i, opt, datalen;
442ee67461eSJoseph Mingrone u_int len;
4434edb46e9SPaul Traina
4445b0fe478SBruce M Simpson hlen -= sizeof(*tp);
4454edb46e9SPaul Traina cp = (const u_char *)tp + sizeof(*tp);
446ee67461eSJoseph Mingrone ND_PRINT(", options [");
4474edb46e9SPaul Traina while (hlen > 0) {
448a5779b6eSRui Paulo if (ch != '\0')
449ee67461eSJoseph Mingrone ND_PRINT("%c", ch);
450ee67461eSJoseph Mingrone opt = GET_U_1(cp);
451ee67461eSJoseph Mingrone cp++;
4524edb46e9SPaul Traina if (ZEROLENOPT(opt))
4534edb46e9SPaul Traina len = 1;
4544edb46e9SPaul Traina else {
455ee67461eSJoseph Mingrone len = GET_U_1(cp);
456ee67461eSJoseph Mingrone cp++; /* total including type, len */
4574de76e31SBill Fenner if (len < 2 || len > hlen)
4584de76e31SBill Fenner goto bad;
4594de76e31SBill Fenner --hlen; /* account for length byte */
4604edb46e9SPaul Traina }
4614de76e31SBill Fenner --hlen; /* account for type byte */
4624edb46e9SPaul Traina datalen = 0;
4634de76e31SBill Fenner
4644de76e31SBill Fenner /* Bail if "l" bytes of data are not left or were not captured */
465ee67461eSJoseph Mingrone #define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); }
4664de76e31SBill Fenner
467a5779b6eSRui Paulo
468ee67461eSJoseph Mingrone ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt));
469a5779b6eSRui Paulo
4704edb46e9SPaul Traina switch (opt) {
4714edb46e9SPaul Traina
4724edb46e9SPaul Traina case TCPOPT_MAXSEG:
4734edb46e9SPaul Traina datalen = 2;
4744de76e31SBill Fenner LENCHECK(datalen);
475ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_2(cp));
4764edb46e9SPaul Traina break;
4774edb46e9SPaul Traina
4784edb46e9SPaul Traina case TCPOPT_WSCALE:
4794edb46e9SPaul Traina datalen = 1;
4804de76e31SBill Fenner LENCHECK(datalen);
481ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_U_1(cp));
4824edb46e9SPaul Traina break;
4834edb46e9SPaul Traina
4844edb46e9SPaul Traina case TCPOPT_SACK:
4854edb46e9SPaul Traina datalen = len - 2;
486b0453382SBill Fenner if (datalen % 8 != 0) {
487ee67461eSJoseph Mingrone ND_PRINT(" invalid sack");
488b0453382SBill Fenner } else {
4893c602fabSXin LI uint32_t s, e;
490b0453382SBill Fenner
491ee67461eSJoseph Mingrone ND_PRINT(" %u ", datalen / 8);
492b0453382SBill Fenner for (i = 0; i < datalen; i += 8) {
4934de76e31SBill Fenner LENCHECK(i + 4);
494ee67461eSJoseph Mingrone s = GET_BE_U_4(cp + i);
495b0453382SBill Fenner LENCHECK(i + 8);
496ee67461eSJoseph Mingrone e = GET_BE_U_4(cp + i + 4);
4973c602fabSXin LI if (rev) {
498b0453382SBill Fenner s -= thseq;
499b0453382SBill Fenner e -= thseq;
500b0453382SBill Fenner } else {
501b0453382SBill Fenner s -= thack;
502b0453382SBill Fenner e -= thack;
5034edb46e9SPaul Traina }
504ee67461eSJoseph Mingrone ND_PRINT("{%u:%u}", s, e);
505b0453382SBill Fenner }
506b0453382SBill Fenner }
5074edb46e9SPaul Traina break;
5084edb46e9SPaul Traina
509a5779b6eSRui Paulo case TCPOPT_CC:
510a5779b6eSRui Paulo case TCPOPT_CCNEW:
511a5779b6eSRui Paulo case TCPOPT_CCECHO:
5124edb46e9SPaul Traina case TCPOPT_ECHO:
5134edb46e9SPaul Traina case TCPOPT_ECHOREPLY:
514a5779b6eSRui Paulo
515a5779b6eSRui Paulo /*
516a5779b6eSRui Paulo * those options share their semantics.
517a5779b6eSRui Paulo * fall through
518a5779b6eSRui Paulo */
5194edb46e9SPaul Traina datalen = 4;
5204de76e31SBill Fenner LENCHECK(datalen);
521ee67461eSJoseph Mingrone ND_PRINT(" %u", GET_BE_U_4(cp));
5224edb46e9SPaul Traina break;
5234edb46e9SPaul Traina
5244edb46e9SPaul Traina case TCPOPT_TIMESTAMP:
5254de76e31SBill Fenner datalen = 8;
5264de76e31SBill Fenner LENCHECK(datalen);
527ee67461eSJoseph Mingrone ND_PRINT(" val %u ecr %u",
528ee67461eSJoseph Mingrone GET_BE_U_4(cp),
529ee67461eSJoseph Mingrone GET_BE_U_4(cp + 4));
5304edb46e9SPaul Traina break;
5314edb46e9SPaul Traina
5321de50e9fSSam Leffler case TCPOPT_SIGNATURE:
5331de50e9fSSam Leffler datalen = TCP_SIGLEN;
5341de50e9fSSam Leffler LENCHECK(datalen);
535ee67461eSJoseph Mingrone ND_PRINT(" ");
5361de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
5373c602fabSXin LI switch (tcp_verify_signature(ndo, ip, tp,
5381de50e9fSSam Leffler bp + TH_OFF(tp) * 4, length, cp)) {
5391de50e9fSSam Leffler
5401de50e9fSSam Leffler case SIGNATURE_VALID:
541ee67461eSJoseph Mingrone ND_PRINT("valid");
5421de50e9fSSam Leffler break;
5431de50e9fSSam Leffler
5441de50e9fSSam Leffler case SIGNATURE_INVALID:
545ee67461eSJoseph Mingrone nd_print_invalid(ndo);
5461de50e9fSSam Leffler break;
5471de50e9fSSam Leffler
5481de50e9fSSam Leffler case CANT_CHECK_SIGNATURE:
549ee67461eSJoseph Mingrone ND_PRINT("can't check - ");
5501de50e9fSSam Leffler for (i = 0; i < TCP_SIGLEN; ++i)
551ee67461eSJoseph Mingrone ND_PRINT("%02x",
552ee67461eSJoseph Mingrone GET_U_1(cp + i));
5531de50e9fSSam Leffler break;
5541de50e9fSSam Leffler }
5551de50e9fSSam Leffler #else
5561de50e9fSSam Leffler for (i = 0; i < TCP_SIGLEN; ++i)
557ee67461eSJoseph Mingrone ND_PRINT("%02x", GET_U_1(cp + i));
5581de50e9fSSam Leffler #endif
5591de50e9fSSam Leffler break;
5601de50e9fSSam Leffler
5613340d773SGleb Smirnoff case TCPOPT_SCPS:
5623340d773SGleb Smirnoff datalen = 2;
5633340d773SGleb Smirnoff LENCHECK(datalen);
564ee67461eSJoseph Mingrone ND_PRINT(" cap %02x id %u", GET_U_1(cp),
565ee67461eSJoseph Mingrone GET_U_1(cp + 1));
566a5779b6eSRui Paulo break;
567a5779b6eSRui Paulo
5683340d773SGleb Smirnoff case TCPOPT_TCPAO:
5693340d773SGleb Smirnoff datalen = len - 2;
5703340d773SGleb Smirnoff /* RFC 5925 Section 2.2:
5713340d773SGleb Smirnoff * "The Length value MUST be greater than or equal to 4."
5723340d773SGleb Smirnoff * (This includes the Kind and Length fields already processed
5733340d773SGleb Smirnoff * at this point.)
5743340d773SGleb Smirnoff */
5753340d773SGleb Smirnoff if (datalen < 2) {
576ee67461eSJoseph Mingrone nd_print_invalid(ndo);
5773340d773SGleb Smirnoff } else {
5783340d773SGleb Smirnoff LENCHECK(1);
579ee67461eSJoseph Mingrone ND_PRINT(" keyid %u", GET_U_1(cp));
5803340d773SGleb Smirnoff LENCHECK(2);
581ee67461eSJoseph Mingrone ND_PRINT(" rnextkeyid %u",
582ee67461eSJoseph Mingrone GET_U_1(cp + 1));
5833340d773SGleb Smirnoff if (datalen > 2) {
584ee67461eSJoseph Mingrone ND_PRINT(" mac 0x");
5853340d773SGleb Smirnoff for (i = 2; i < datalen; i++) {
5863340d773SGleb Smirnoff LENCHECK(i + 1);
587ee67461eSJoseph Mingrone ND_PRINT("%02x",
588ee67461eSJoseph Mingrone GET_U_1(cp + i));
5893340d773SGleb Smirnoff }
5903340d773SGleb Smirnoff }
5913340d773SGleb Smirnoff }
5923340d773SGleb Smirnoff break;
593a5779b6eSRui Paulo
594a5779b6eSRui Paulo case TCPOPT_EOL:
595a5779b6eSRui Paulo case TCPOPT_NOP:
596a5779b6eSRui Paulo case TCPOPT_SACKOK:
597a5779b6eSRui Paulo /*
598a5779b6eSRui Paulo * Nothing interesting.
599a5779b6eSRui Paulo * fall through
600a5779b6eSRui Paulo */
601a5779b6eSRui Paulo break;
602a5779b6eSRui Paulo
603ce3ed1caSRui Paulo case TCPOPT_UTO:
604ce3ed1caSRui Paulo datalen = 2;
605ce3ed1caSRui Paulo LENCHECK(datalen);
606ee67461eSJoseph Mingrone utoval = GET_BE_U_2(cp);
607ee67461eSJoseph Mingrone ND_PRINT(" 0x%x", utoval);
608ce3ed1caSRui Paulo if (utoval & 0x0001)
609ce3ed1caSRui Paulo utoval = (utoval >> 1) * 60;
610ce3ed1caSRui Paulo else
611ce3ed1caSRui Paulo utoval >>= 1;
612ee67461eSJoseph Mingrone ND_PRINT(" %u", utoval);
6133c602fabSXin LI break;
6143c602fabSXin LI
6153c602fabSXin LI case TCPOPT_MPTCP:
616ee67461eSJoseph Mingrone {
617ee67461eSJoseph Mingrone const u_char *snapend_save;
618ee67461eSJoseph Mingrone int ret;
619ee67461eSJoseph Mingrone
6203c602fabSXin LI datalen = len - 2;
6213c602fabSXin LI LENCHECK(datalen);
622ee67461eSJoseph Mingrone /* Update the snapend to the end of the option
623ee67461eSJoseph Mingrone * before calling mptcp_print(). Some options
624ee67461eSJoseph Mingrone * (MPTCP or others) may be present after a
625ee67461eSJoseph Mingrone * MPTCP option. This prevents that, in
626ee67461eSJoseph Mingrone * mptcp_print(), the remaining length < the
627ee67461eSJoseph Mingrone * remaining caplen.
628ee67461eSJoseph Mingrone */
629ee67461eSJoseph Mingrone snapend_save = ndo->ndo_snapend;
630ee67461eSJoseph Mingrone ndo->ndo_snapend = ND_MIN(cp - 2 + len,
631ee67461eSJoseph Mingrone ndo->ndo_snapend);
632ee67461eSJoseph Mingrone ret = mptcp_print(ndo, cp - 2, len, flags);
633ee67461eSJoseph Mingrone ndo->ndo_snapend = snapend_save;
634ee67461eSJoseph Mingrone if (!ret)
6353c602fabSXin LI goto bad;
6363c602fabSXin LI break;
637ee67461eSJoseph Mingrone }
6383c602fabSXin LI
6393340d773SGleb Smirnoff case TCPOPT_FASTOPEN:
6403340d773SGleb Smirnoff datalen = len - 2;
6413340d773SGleb Smirnoff LENCHECK(datalen);
642ee67461eSJoseph Mingrone ND_PRINT(" ");
6433340d773SGleb Smirnoff print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
6443340d773SGleb Smirnoff break;
6453340d773SGleb Smirnoff
6463c602fabSXin LI case TCPOPT_EXPERIMENT2:
6473c602fabSXin LI datalen = len - 2;
6483c602fabSXin LI LENCHECK(datalen);
6493c602fabSXin LI if (datalen < 2)
6503c602fabSXin LI goto bad;
6513c602fabSXin LI /* RFC6994 */
652ee67461eSJoseph Mingrone magic = GET_BE_U_2(cp);
653ee67461eSJoseph Mingrone ND_PRINT("-");
6543c602fabSXin LI
6553c602fabSXin LI switch(magic) {
6563c602fabSXin LI
6573340d773SGleb Smirnoff case 0xf989: /* TCP Fast Open RFC 7413 */
6583340d773SGleb Smirnoff print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
6593c602fabSXin LI break;
6603c602fabSXin LI
6613c602fabSXin LI default:
6623c602fabSXin LI /* Unknown magic number */
663ee67461eSJoseph Mingrone ND_PRINT("%04x", magic);
6643c602fabSXin LI break;
6653c602fabSXin LI }
666ce3ed1caSRui Paulo break;
667ce3ed1caSRui Paulo
6684edb46e9SPaul Traina default:
6694edb46e9SPaul Traina datalen = len - 2;
6703c602fabSXin LI if (datalen)
671ee67461eSJoseph Mingrone ND_PRINT(" 0x");
6724edb46e9SPaul Traina for (i = 0; i < datalen; ++i) {
6733340d773SGleb Smirnoff LENCHECK(i + 1);
674ee67461eSJoseph Mingrone ND_PRINT("%02x", GET_U_1(cp + i));
6754edb46e9SPaul Traina }
6764edb46e9SPaul Traina break;
6774edb46e9SPaul Traina }
6784edb46e9SPaul Traina
6794edb46e9SPaul Traina /* Account for data printed */
6804edb46e9SPaul Traina cp += datalen;
6814edb46e9SPaul Traina hlen -= datalen;
6824edb46e9SPaul Traina
6834edb46e9SPaul Traina /* Check specification against observed length */
6844edb46e9SPaul Traina ++datalen; /* option octet */
6854edb46e9SPaul Traina if (!ZEROLENOPT(opt))
6864edb46e9SPaul Traina ++datalen; /* size octet */
6874edb46e9SPaul Traina if (datalen != len)
688ee67461eSJoseph Mingrone ND_PRINT("[len %u]", len);
6894edb46e9SPaul Traina ch = ',';
6904de76e31SBill Fenner if (opt == TCPOPT_EOL)
6914de76e31SBill Fenner break;
6924edb46e9SPaul Traina }
693ee67461eSJoseph Mingrone ND_PRINT("]");
6944edb46e9SPaul Traina }
695b0453382SBill Fenner
696a5779b6eSRui Paulo /*
697a5779b6eSRui Paulo * Print length field before crawling down the stack.
698a5779b6eSRui Paulo */
699ee67461eSJoseph Mingrone ND_PRINT(", length %u", length);
700a5779b6eSRui Paulo
701ee67461eSJoseph Mingrone if (length == 0)
702b0453382SBill Fenner return;
703b0453382SBill Fenner
704b0453382SBill Fenner /*
705b0453382SBill Fenner * Decode payload if necessary.
706b0453382SBill Fenner */
707ee67461eSJoseph Mingrone header_len = TH_OFF(tp) * 4;
708ee67461eSJoseph Mingrone /*
709ee67461eSJoseph Mingrone * Do a bounds check before decoding the payload.
710ee67461eSJoseph Mingrone * At least the header data is required.
711ee67461eSJoseph Mingrone */
712ee67461eSJoseph Mingrone if (!ND_TTEST_LEN(bp, header_len)) {
713ee67461eSJoseph Mingrone ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
714ee67461eSJoseph Mingrone ND_BYTES_AVAILABLE_AFTER(bp), header_len);
715ee67461eSJoseph Mingrone nd_trunc_longjmp(ndo);
716ee67461eSJoseph Mingrone }
717ee67461eSJoseph Mingrone bp += header_len;
7183c602fabSXin LI if ((flags & TH_RST) && ndo->ndo_vflag) {
7193c602fabSXin LI print_tcp_rst_data(ndo, bp, length);
720a5779b6eSRui Paulo return;
721a5779b6eSRui Paulo }
722a5779b6eSRui Paulo
7233c602fabSXin LI if (ndo->ndo_packettype) {
7243c602fabSXin LI switch (ndo->ndo_packettype) {
725d03c0883SXin LI case PT_ZMTP1:
7263c602fabSXin LI zmtp1_print(ndo, bp, length);
727d03c0883SXin LI break;
7283340d773SGleb Smirnoff case PT_RESP:
7293340d773SGleb Smirnoff resp_print(ndo, bp, length);
7303340d773SGleb Smirnoff break;
731ee67461eSJoseph Mingrone case PT_DOMAIN:
732ee67461eSJoseph Mingrone /* over_tcp: TRUE, is_mdns: FALSE */
733ee67461eSJoseph Mingrone domain_print(ndo, bp, length, TRUE, FALSE);
734ee67461eSJoseph Mingrone break;
735d03c0883SXin LI }
736d03c0883SXin LI return;
737d03c0883SXin LI }
738d03c0883SXin LI
739*0a7e5f1fSJoseph Mingrone if (IS_SRC_OR_DST_PORT(FTP_PORT)) {
740*0a7e5f1fSJoseph Mingrone ND_PRINT(": ");
741*0a7e5f1fSJoseph Mingrone ftp_print(ndo, bp, length);
742*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(SSH_PORT)) {
743*0a7e5f1fSJoseph Mingrone ssh_print(ndo, bp, length);
744*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(TELNET_PORT)) {
7453c602fabSXin LI telnet_print(ndo, bp, length);
7463340d773SGleb Smirnoff } else if (IS_SRC_OR_DST_PORT(SMTP_PORT)) {
747ee67461eSJoseph Mingrone ND_PRINT(": ");
7488bdc5a62SPatrick Kelsey smtp_print(ndo, bp, length);
749ee67461eSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(WHOIS_PORT)) {
750ee67461eSJoseph Mingrone ND_PRINT(": ");
751ee67461eSJoseph Mingrone whois_print(ndo, bp, length);
752ee67461eSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(NAMESERVER_PORT)) {
753ee67461eSJoseph Mingrone /* over_tcp: TRUE, is_mdns: FALSE */
754ee67461eSJoseph Mingrone domain_print(ndo, bp, length, TRUE, FALSE);
755*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(HTTP_PORT)) {
756*0a7e5f1fSJoseph Mingrone ND_PRINT(": ");
757*0a7e5f1fSJoseph Mingrone http_print(ndo, bp, length);
758*0a7e5f1fSJoseph Mingrone #ifdef ENABLE_SMB
759*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(NETBIOS_SSN_PORT)) {
760*0a7e5f1fSJoseph Mingrone nbt_tcp_print(ndo, bp, length);
761*0a7e5f1fSJoseph Mingrone #endif
762*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(BGP_PORT)) {
763*0a7e5f1fSJoseph Mingrone bgp_print(ndo, bp, length);
7643340d773SGleb Smirnoff } else if (IS_SRC_OR_DST_PORT(RPKI_RTR_PORT)) {
7653c602fabSXin LI rpki_rtr_print(ndo, bp, length);
766*0a7e5f1fSJoseph Mingrone #ifdef ENABLE_SMB
767*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(SMB_PORT)) {
768*0a7e5f1fSJoseph Mingrone smb_tcp_print(ndo, bp, length);
769*0a7e5f1fSJoseph Mingrone #endif
770*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(RTSP_PORT)) {
771*0a7e5f1fSJoseph Mingrone ND_PRINT(": ");
772*0a7e5f1fSJoseph Mingrone rtsp_print(ndo, bp, length);
773*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(MSDP_PORT)) {
774*0a7e5f1fSJoseph Mingrone msdp_print(ndo, bp, length);
775ee67461eSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(LDP_PORT)) {
7763c602fabSXin LI ldp_print(ndo, bp, length);
777*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(PPTP_PORT))
778*0a7e5f1fSJoseph Mingrone pptp_print(ndo, bp);
779*0a7e5f1fSJoseph Mingrone else if (IS_SRC_OR_DST_PORT(REDIS_PORT))
780*0a7e5f1fSJoseph Mingrone resp_print(ndo, bp, length);
781*0a7e5f1fSJoseph Mingrone else if (IS_SRC_OR_DST_PORT(BEEP_PORT))
782*0a7e5f1fSJoseph Mingrone beep_print(ndo, bp, length);
783*0a7e5f1fSJoseph Mingrone else if (IS_SRC_OR_DST_PORT(OPENFLOW_PORT_OLD) || IS_SRC_OR_DST_PORT(OPENFLOW_PORT_IANA)) {
784*0a7e5f1fSJoseph Mingrone openflow_print(ndo, bp, length);
785*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(HTTP_PORT_ALT)) {
786*0a7e5f1fSJoseph Mingrone ND_PRINT(": ");
787*0a7e5f1fSJoseph Mingrone http_print(ndo, bp, length);
788*0a7e5f1fSJoseph Mingrone } else if (IS_SRC_OR_DST_PORT(RTSP_PORT_ALT)) {
789*0a7e5f1fSJoseph Mingrone ND_PRINT(": ");
790*0a7e5f1fSJoseph Mingrone rtsp_print(ndo, bp, length);
791ee67461eSJoseph Mingrone } else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
792ee67461eSJoseph Mingrone length >= 4 && ND_TTEST_4(bp)) {
7933c602fabSXin LI /*
7943c602fabSXin LI * If data present, header length valid, and NFS port used,
7953c602fabSXin LI * assume NFS.
7963c602fabSXin LI * Pass offset of data plus 4 bytes for RPC TCP msg length
7973c602fabSXin LI * to NFS print routines.
7983c602fabSXin LI */
7993c602fabSXin LI uint32_t fraglen;
800ee67461eSJoseph Mingrone const struct sunrpc_msg *rp;
8013c602fabSXin LI enum sunrpc_msg_type direction;
8023c602fabSXin LI
803ee67461eSJoseph Mingrone fraglen = GET_BE_U_4(bp) & 0x7FFFFFFF;
8043c602fabSXin LI if (fraglen > (length) - 4)
8053c602fabSXin LI fraglen = (length) - 4;
8063340d773SGleb Smirnoff rp = (const struct sunrpc_msg *)(bp + 4);
807ee67461eSJoseph Mingrone if (ND_TTEST_4(rp->rm_direction)) {
808ee67461eSJoseph Mingrone direction = (enum sunrpc_msg_type) GET_BE_U_4(rp->rm_direction);
8093c602fabSXin LI if (dport == NFS_PORT && direction == SUNRPC_CALL) {
810ee67461eSJoseph Mingrone ND_PRINT(": NFS request xid %u ",
811ee67461eSJoseph Mingrone GET_BE_U_4(rp->rm_xid));
812ee67461eSJoseph Mingrone nfsreq_noaddr_print(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
8133c602fabSXin LI return;
8143c602fabSXin LI }
8153c602fabSXin LI if (sport == NFS_PORT && direction == SUNRPC_REPLY) {
816ee67461eSJoseph Mingrone ND_PRINT(": NFS reply xid %u ",
817ee67461eSJoseph Mingrone GET_BE_U_4(rp->rm_xid));
818ee67461eSJoseph Mingrone nfsreply_noaddr_print(ndo, (const u_char *)rp, fraglen, (const u_char *)ip);
8193c602fabSXin LI return;
8203c602fabSXin LI }
8213c602fabSXin LI }
8221de50e9fSSam Leffler }
823a5779b6eSRui Paulo
8244edb46e9SPaul Traina return;
8254de76e31SBill Fenner bad:
826ee67461eSJoseph Mingrone ND_PRINT("[bad opt]");
8274de76e31SBill Fenner if (ch != '\0')
828ee67461eSJoseph Mingrone ND_PRINT("]");
8294de76e31SBill Fenner return;
8304edb46e9SPaul Traina trunc:
831ee67461eSJoseph Mingrone nd_print_trunc(ndo);
8324edb46e9SPaul Traina if (ch != '\0')
833ee67461eSJoseph Mingrone ND_PRINT(">");
8344edb46e9SPaul Traina }
8354edb46e9SPaul Traina
836685295f4SBill Fenner /*
837685295f4SBill Fenner * RFC1122 says the following on data in RST segments:
838685295f4SBill Fenner *
839685295f4SBill Fenner * 4.2.2.12 RST Segment: RFC-793 Section 3.4
840685295f4SBill Fenner *
841685295f4SBill Fenner * A TCP SHOULD allow a received RST segment to include data.
842685295f4SBill Fenner *
843685295f4SBill Fenner * DISCUSSION
844685295f4SBill Fenner * It has been suggested that a RST segment could contain
845685295f4SBill Fenner * ASCII text that encoded and explained the cause of the
846685295f4SBill Fenner * RST. No standard has yet been established for such
847685295f4SBill Fenner * data.
848685295f4SBill Fenner *
849685295f4SBill Fenner */
850685295f4SBill Fenner
851685295f4SBill Fenner static void
print_tcp_rst_data(netdissect_options * ndo,const u_char * sp,u_int length)8523c602fabSXin LI print_tcp_rst_data(netdissect_options *ndo,
853ee67461eSJoseph Mingrone const u_char *sp, u_int length)
854685295f4SBill Fenner {
855ee67461eSJoseph Mingrone u_char c;
856685295f4SBill Fenner
857ee67461eSJoseph Mingrone ND_PRINT(ND_TTEST_LEN(sp, length) ? " [RST" : " [!RST");
858685295f4SBill Fenner if (length > MAX_RST_DATA_LEN) {
859685295f4SBill Fenner length = MAX_RST_DATA_LEN; /* can use -X for longer */
860ee67461eSJoseph Mingrone ND_PRINT("+"); /* indicate we truncate */
861685295f4SBill Fenner }
862ee67461eSJoseph Mingrone ND_PRINT(" ");
863ee67461eSJoseph Mingrone while (length && sp < ndo->ndo_snapend) {
864ee67461eSJoseph Mingrone c = GET_U_1(sp);
865ee67461eSJoseph Mingrone sp++;
866ee67461eSJoseph Mingrone fn_print_char(ndo, c);
867ee67461eSJoseph Mingrone length--;
868685295f4SBill Fenner }
869ee67461eSJoseph Mingrone ND_PRINT("]");
870685295f4SBill Fenner }
8711de50e9fSSam Leffler
8723340d773SGleb Smirnoff static void
print_tcp_fastopen_option(netdissect_options * ndo,const u_char * cp,u_int datalen,int exp)873ee67461eSJoseph Mingrone print_tcp_fastopen_option(netdissect_options *ndo, const u_char *cp,
8743340d773SGleb Smirnoff u_int datalen, int exp)
8753340d773SGleb Smirnoff {
8763340d773SGleb Smirnoff u_int i;
8773340d773SGleb Smirnoff
8783340d773SGleb Smirnoff if (exp)
879ee67461eSJoseph Mingrone ND_PRINT("tfo");
8803340d773SGleb Smirnoff
8813340d773SGleb Smirnoff if (datalen == 0) {
8823340d773SGleb Smirnoff /* Fast Open Cookie Request */
883ee67461eSJoseph Mingrone ND_PRINT(" cookiereq");
8843340d773SGleb Smirnoff } else {
8853340d773SGleb Smirnoff /* Fast Open Cookie */
8863340d773SGleb Smirnoff if (datalen % 2 != 0 || datalen < 4 || datalen > 16) {
887ee67461eSJoseph Mingrone nd_print_invalid(ndo);
8883340d773SGleb Smirnoff } else {
889ee67461eSJoseph Mingrone ND_PRINT(" cookie ");
8903340d773SGleb Smirnoff for (i = 0; i < datalen; ++i)
891ee67461eSJoseph Mingrone ND_PRINT("%02x", GET_U_1(cp + i));
8923340d773SGleb Smirnoff }
8933340d773SGleb Smirnoff }
8943340d773SGleb Smirnoff }
8953340d773SGleb Smirnoff
8961de50e9fSSam Leffler #ifdef HAVE_LIBCRYPTO
897ee67461eSJoseph Mingrone DIAG_OFF_DEPRECATION
8981de50e9fSSam Leffler static int
tcp_verify_signature(netdissect_options * ndo,const struct ip * ip,const struct tcphdr * tp,const u_char * data,u_int length,const u_char * rcvsig)8993c602fabSXin LI tcp_verify_signature(netdissect_options *ndo,
9003c602fabSXin LI const struct ip *ip, const struct tcphdr *tp,
901ee67461eSJoseph Mingrone const u_char *data, u_int length, const u_char *rcvsig)
9021de50e9fSSam Leffler {
9031de50e9fSSam Leffler struct tcphdr tp1;
904f4d0c64aSSam Leffler u_char sig[TCP_SIGLEN];
9051de50e9fSSam Leffler char zero_proto = 0;
9061de50e9fSSam Leffler MD5_CTX ctx;
9073c602fabSXin LI uint16_t savecsum, tlen;
9083340d773SGleb Smirnoff const struct ip6_hdr *ip6;
9093c602fabSXin LI uint32_t len32;
9103c602fabSXin LI uint8_t nxt;
9111de50e9fSSam Leffler
9123c602fabSXin LI if (data + length > ndo->ndo_snapend) {
913ee67461eSJoseph Mingrone ND_PRINT("snaplen too short, ");
91427df3f5dSRui Paulo return (CANT_CHECK_SIGNATURE);
91527df3f5dSRui Paulo }
91627df3f5dSRui Paulo
9171de50e9fSSam Leffler tp1 = *tp;
9181de50e9fSSam Leffler
9193c602fabSXin LI if (ndo->ndo_sigsecret == NULL) {
920ee67461eSJoseph Mingrone ND_PRINT("shared secret not supplied with -M, ");
9211de50e9fSSam Leffler return (CANT_CHECK_SIGNATURE);
92227df3f5dSRui Paulo }
9231de50e9fSSam Leffler
9241de50e9fSSam Leffler MD5_Init(&ctx);
9251de50e9fSSam Leffler /*
9261de50e9fSSam Leffler * Step 1: Update MD5 hash with IP pseudo-header.
9271de50e9fSSam Leffler */
9281de50e9fSSam Leffler if (IP_V(ip) == 4) {
9293340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&ip->ip_src, sizeof(ip->ip_src));
9303340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&ip->ip_dst, sizeof(ip->ip_dst));
9313340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&zero_proto, sizeof(zero_proto));
9323340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&ip->ip_p, sizeof(ip->ip_p));
933ee67461eSJoseph Mingrone tlen = GET_BE_U_2(ip->ip_len) - IP_HL(ip) * 4;
9341de50e9fSSam Leffler tlen = htons(tlen);
9353340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&tlen, sizeof(tlen));
9361de50e9fSSam Leffler } else if (IP_V(ip) == 6) {
9373340d773SGleb Smirnoff ip6 = (const struct ip6_hdr *)ip;
9383340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
9393340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
940ee67461eSJoseph Mingrone len32 = htonl(GET_BE_U_2(ip6->ip6_plen));
9413340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&len32, sizeof(len32));
9421de50e9fSSam Leffler nxt = 0;
9433340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
9443340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
9453340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
9461de50e9fSSam Leffler nxt = IPPROTO_TCP;
9473340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&nxt, sizeof(nxt));
94827df3f5dSRui Paulo } else {
949ee67461eSJoseph Mingrone ND_PRINT("IP version not 4 or 6, ");
9501de50e9fSSam Leffler return (CANT_CHECK_SIGNATURE);
95127df3f5dSRui Paulo }
9521de50e9fSSam Leffler
9531de50e9fSSam Leffler /*
9541de50e9fSSam Leffler * Step 2: Update MD5 hash with TCP header, excluding options.
9551de50e9fSSam Leffler * The TCP checksum must be set to zero.
9561de50e9fSSam Leffler */
957ee67461eSJoseph Mingrone memcpy(&savecsum, tp1.th_sum, sizeof(savecsum));
958ee67461eSJoseph Mingrone memset(tp1.th_sum, 0, sizeof(tp1.th_sum));
9593340d773SGleb Smirnoff MD5_Update(&ctx, (const char *)&tp1, sizeof(struct tcphdr));
960ee67461eSJoseph Mingrone memcpy(tp1.th_sum, &savecsum, sizeof(tp1.th_sum));
9611de50e9fSSam Leffler /*
9621de50e9fSSam Leffler * Step 3: Update MD5 hash with TCP segment data, if present.
9631de50e9fSSam Leffler */
9641de50e9fSSam Leffler if (length > 0)
9651de50e9fSSam Leffler MD5_Update(&ctx, data, length);
9661de50e9fSSam Leffler /*
9671de50e9fSSam Leffler * Step 4: Update MD5 hash with shared secret.
9681de50e9fSSam Leffler */
9693c602fabSXin LI MD5_Update(&ctx, ndo->ndo_sigsecret, strlen(ndo->ndo_sigsecret));
9701de50e9fSSam Leffler MD5_Final(sig, &ctx);
9711de50e9fSSam Leffler
972b5bfcb5dSMax Laier if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
9731de50e9fSSam Leffler return (SIGNATURE_VALID);
9741de50e9fSSam Leffler else
9751de50e9fSSam Leffler return (SIGNATURE_INVALID);
9761de50e9fSSam Leffler }
977ee67461eSJoseph Mingrone DIAG_ON_DEPRECATION
9781de50e9fSSam Leffler #endif /* HAVE_LIBCRYPTO */
979