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