/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 1999-2004 The tcpdump.org project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
/*
* Find (or record) the initial sequence numbers for
* this conversation. (we pick an arbitrary
* collating order so there's only one entry for
* both directions).
*/
rev = 0;
if (ip6) {
struct tcp_seq_hash6 *th;
struct tcp_seq_hash6 *tcp_seq_hash;
const void *src, *dst;
struct tha6 tha;
case TCPOPT_MAXSEG:
datalen = 2;
LENCHECK(datalen);
ND_PRINT(" %u", GET_BE_U_2(cp));
break;
case TCPOPT_WSCALE:
datalen = 1;
LENCHECK(datalen);
ND_PRINT(" %u", GET_U_1(cp));
break;
case TCPOPT_SACK:
datalen = len - 2;
if (datalen % 8 != 0) {
ND_PRINT(" invalid sack");
} else {
uint32_t s, e;
ND_PRINT(" %u ", datalen / 8);
for (i = 0; i < datalen; i += 8) {
LENCHECK(i + 4);
s = GET_BE_U_4(cp + i);
LENCHECK(i + 8);
e = GET_BE_U_4(cp + i + 4);
if (rev) {
s -= thseq;
e -= thseq;
} else {
s -= thack;
e -= thack;
}
ND_PRINT("{%u:%u}", s, e);
}
}
break;
case TCPOPT_CC:
case TCPOPT_CCNEW:
case TCPOPT_CCECHO:
case TCPOPT_ECHO:
case TCPOPT_ECHOREPLY:
/*
* those options share their semantics.
* fall through
*/
datalen = 4;
LENCHECK(datalen);
ND_PRINT(" %u", GET_BE_U_4(cp));
break;
case TCPOPT_TIMESTAMP:
datalen = 8;
LENCHECK(datalen);
ND_PRINT(" val %u ecr %u",
GET_BE_U_4(cp),
GET_BE_U_4(cp + 4));
break;
case SIGNATURE_INVALID:
nd_print_invalid(ndo);
break;
case CANT_CHECK_SIGNATURE:
ND_PRINT("can't check - ");
for (i = 0; i < TCP_SIGLEN; ++i)
ND_PRINT("%02x",
GET_U_1(cp + i));
break;
}
#else
for (i = 0; i < TCP_SIGLEN; ++i)
ND_PRINT("%02x", GET_U_1(cp + i));
#endif
break;
case TCPOPT_SCPS:
datalen = 2;
LENCHECK(datalen);
ND_PRINT(" cap %02x id %u", GET_U_1(cp),
GET_U_1(cp + 1));
break;
case TCPOPT_TCPAO:
datalen = len - 2;
/* RFC 5925 Section 2.2:
* "The Length value MUST be greater than or equal to 4."
* (This includes the Kind and Length fields already processed
* at this point.)
*/
if (datalen < 2) {
nd_print_invalid(ndo);
} else {
LENCHECK(1);
ND_PRINT(" keyid %u", GET_U_1(cp));
LENCHECK(2);
ND_PRINT(" rnextkeyid %u",
GET_U_1(cp + 1));
if (datalen > 2) {
ND_PRINT(" mac 0x");
for (i = 2; i < datalen; i++) {
LENCHECK(i + 1);
ND_PRINT("%02x",
GET_U_1(cp + i));
}
}
}
break;
case TCPOPT_EOL:
case TCPOPT_NOP:
case TCPOPT_SACKOK:
/*
* Nothing interesting.
* fall through
*/
break;
case TCPOPT_MPTCP:
{
const u_char *snapend_save;
int ret;
datalen = len - 2;
LENCHECK(datalen);
/* Update the snapend to the end of the option
* before calling mptcp_print(). Some options
* (MPTCP or others) may be present after a
* MPTCP option. This prevents that, in
* mptcp_print(), the remaining length < the
* remaining caplen.
*/
snapend_save = ndo->ndo_snapend;
ndo->ndo_snapend = ND_MIN(cp - 2 + len,
ndo->ndo_snapend);
ret = mptcp_print(ndo, cp - 2, len, flags);
ndo->ndo_snapend = snapend_save;
if (!ret)
goto bad;
break;
}
case TCPOPT_FASTOPEN:
datalen = len - 2;
LENCHECK(datalen);
ND_PRINT(" ");
print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
break;
case TCPOPT_EXPERIMENT2:
datalen = len - 2;
LENCHECK(datalen);
if (datalen < 2)
goto bad;
/* RFC6994 */
magic = GET_BE_U_2(cp);
ND_PRINT("-");
switch(magic) {
case 0xf989: /* TCP Fast Open RFC 7413 */
print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
break;
default:
datalen = len - 2;
if (datalen)
ND_PRINT(" 0x");
for (i = 0; i < datalen; ++i) {
LENCHECK(i + 1);
ND_PRINT("%02x", GET_U_1(cp + i));
}
break;
}
/* Account for data printed */
cp += datalen;
hlen -= datalen;
/* Check specification against observed length */
++datalen; /* option octet */
if (!ZEROLENOPT(opt))
++datalen; /* size octet */
if (datalen != len)
ND_PRINT("[len %u]", len);
ch = ',';
if (opt == TCPOPT_EOL)
break;
}
ND_PRINT("]");
}
/*
* Print length field before crawling down the stack.
*/
ND_PRINT(", length %u", length);
if (length == 0)
return;
/*
* Decode payload if necessary.
*/
header_len = TH_OFF(tp) * 4;
/*
* Do a bounds check before decoding the payload.
* At least the header data is required.
*/
if (!ND_TTEST_LEN(bp, header_len)) {
ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
ND_BYTES_AVAILABLE_AFTER(bp), header_len);
nd_trunc_longjmp(ndo);
}
bp += header_len;
if ((flags & TH_RST) && ndo->ndo_vflag) {
print_tcp_rst_data(ndo, bp, length);
return;
}
if (ndo->ndo_packettype) {
switch (ndo->ndo_packettype) {
case PT_ZMTP1:
zmtp1_print(ndo, bp, length);
break;
case PT_RESP:
resp_print(ndo, bp, length);
break;
case PT_DOMAIN:
/* over_tcp: TRUE, is_mdns: FALSE */
domain_print(ndo, bp, length, TRUE, FALSE);
break;
}
return;
}
if (IS_SRC_OR_DST_PORT(FTP_PORT)) {
ND_PRINT(": ");
ftp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(SSH_PORT)) {
ssh_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(TELNET_PORT)) {
telnet_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(SMTP_PORT)) {
ND_PRINT(": ");
smtp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(WHOIS_PORT)) {
ND_PRINT(": ");
whois_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(NAMESERVER_PORT)) {
/* over_tcp: TRUE, is_mdns: FALSE */
domain_print(ndo, bp, length, TRUE, FALSE);
} else if (IS_SRC_OR_DST_PORT(HTTP_PORT)) {
ND_PRINT(": ");
http_print(ndo, bp, length);
#ifdef ENABLE_SMB
} else if (IS_SRC_OR_DST_PORT(NETBIOS_SSN_PORT)) {
nbt_tcp_print(ndo, bp, length);
#endif
} else if (IS_SRC_OR_DST_PORT(BGP_PORT)) {
bgp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(RPKI_RTR_PORT)) {
rpki_rtr_print(ndo, bp, length);
#ifdef ENABLE_SMB
} else if (IS_SRC_OR_DST_PORT(SMB_PORT)) {
smb_tcp_print(ndo, bp, length);
#endif
} else if (IS_SRC_OR_DST_PORT(RTSP_PORT)) {
ND_PRINT(": ");
rtsp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(MSDP_PORT)) {
msdp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(LDP_PORT)) {
ldp_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(PPTP_PORT))
pptp_print(ndo, bp);
else if (IS_SRC_OR_DST_PORT(REDIS_PORT))
resp_print(ndo, bp, length);
else if (IS_SRC_OR_DST_PORT(BEEP_PORT))
beep_print(ndo, bp, length);
else if (IS_SRC_OR_DST_PORT(OPENFLOW_PORT_OLD) || IS_SRC_OR_DST_PORT(OPENFLOW_PORT_IANA)) {
openflow_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(HTTP_PORT_ALT)) {
ND_PRINT(": ");
http_print(ndo, bp, length);
} else if (IS_SRC_OR_DST_PORT(RTSP_PORT_ALT)) {
ND_PRINT(": ");
rtsp_print(ndo, bp, length);
} else if ((IS_SRC_OR_DST_PORT(NFS_PORT)) &&
length >= 4 && ND_TTEST_4(bp)) {
/*
* If data present, header length valid, and NFS port used,
* assume NFS.
* Pass offset of data plus 4 bytes for RPC TCP msg length
* to NFS print routines.
*/
uint32_t fraglen;
const struct sunrpc_msg *rp;
enum sunrpc_msg_type direction;
return;
bad:
ND_PRINT("[bad opt]");
if (ch != '\0')
ND_PRINT("]");
return;
trunc:
nd_print_trunc(ndo);
if (ch != '\0')
ND_PRINT(">");
}
/*
* RFC1122 says the following on data in RST segments:
*
* 4.2.2.12 RST Segment: RFC-793 Section 3.4
*
* A TCP SHOULD allow a received RST segment to include data.
*
* DISCUSSION
* It has been suggested that a RST segment could contain
* ASCII text that encoded and explained the cause of the
* RST. No standard has yet been established for such
* data.
*
*/