X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/e8b523758959c1854689d71c7a4686c631e5501c..47fc89d711eec0a073d9b3b293a1af901b5bd791:/print-tcp.c diff --git a/print-tcp.c b/print-tcp.c index e2559ecf..bb76ac7c 100644 --- a/print-tcp.c +++ b/print-tcp.c @@ -24,8 +24,6 @@ */ #ifndef lint -static const char rcsid[] _U_ = -"@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.135 2008-11-09 23:35:03 mcr Exp $ (LBL)"; #else __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $"); #endif @@ -70,13 +68,8 @@ static void print_tcp_rst_data(register const u_char *sp, u_int length); struct tha { -#ifndef INET6 struct in_addr src; struct in_addr dst; -#else - struct in6_addr src; - struct in6_addr dst; -#endif /*INET6*/ u_int port; }; @@ -87,14 +80,32 @@ struct tcp_seq_hash { tcp_seq ack; }; +#ifdef INET6 +struct tha6 { + struct in6_addr src; + struct in6_addr dst; + u_int port; +}; + +struct tcp_seq_hash6 { + struct tcp_seq_hash6 *nxt; + struct tha6 addr; + tcp_seq seq; + tcp_seq ack; +}; +#endif + #define TSEQ_HASHSIZE 919 /* These tcp optinos do not have the size octet */ #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) -static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; +static struct tcp_seq_hash tcp_seq_hash4[TSEQ_HASHSIZE]; +#ifdef INET6 +static struct tcp_seq_hash6 tcp_seq_hash6[TSEQ_HASHSIZE]; +#endif -struct tok tcp_flag_values[] = { +static const struct tok tcp_flag_values[] = { { TH_FIN, "F" }, { TH_SYN, "S" }, { TH_RST, "R" }, @@ -106,7 +117,7 @@ struct tok tcp_flag_values[] = { { 0, NULL } }; -struct tok tcp_option_values[] = { +static const struct tok tcp_option_values[] = { { TCPOPT_EOL, "eol" }, { TCPOPT_NOP, "nop" }, { TCPOPT_MAXSEG, "mss" }, @@ -122,6 +133,8 @@ struct tok tcp_option_values[] = { { TCPOPT_SIGNATURE, "md5" }, { TCPOPT_AUTH, "enhanced auth" }, { TCPOPT_UTO, "uto" }, + { TCPOPT_MPTCP, "mptcp" }, + { TCPOPT_EXPERIMENT2, "exp" }, { 0, NULL } }; @@ -129,31 +142,8 @@ static int tcp_cksum(register const struct ip *ip, register const struct tcphdr *tp, register u_int len) { - union phu { - struct phdr { - u_int32_t src; - u_int32_t dst; - u_char mbz; - u_char proto; - u_int16_t len; - } ph; - u_int16_t pa[6]; - } phu; - const u_int16_t *sp; - - /* pseudo-header.. */ - phu.ph.len = htons((u_int16_t)len); - phu.ph.mbz = 0; - phu.ph.proto = IPPROTO_TCP; - memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); - if (IP_HL(ip) == 5) - memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); - else - phu.ph.dst = ip_finddst(ip); - - sp = &phu.pa[0]; - return in_cksum((u_short *)tp, len, - sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]); + return (nextproto4_cksum(ip, (const u_int8_t *)tp, len, + IPPROTO_TCP)); } void @@ -168,7 +158,8 @@ tcp_print(register const u_char *bp, register u_int length, u_int16_t sport, dport, win, urp; u_int32_t seq, ack, thseq, thack; u_int utoval; - int threv; + u_int16_t magic; + register int rev; #ifdef INET6 register const struct ip6_hdr *ip6; #endif @@ -194,42 +185,6 @@ tcp_print(register const u_char *bp, register u_int length, hlen = TH_OFF(tp) * 4; - /* - * 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. - */ - if (!qflag && hlen >= sizeof(*tp) && hlen <= length && - (length - hlen) >= 4) { - u_char *fraglenp; - u_int32_t fraglen; - register struct sunrpc_msg *rp; - enum sunrpc_msg_type direction; - - fraglenp = (u_char *)tp + hlen; - if (TTEST2(*fraglenp, 4)) { - fraglen = EXTRACT_32BITS(fraglenp) & 0x7FFFFFFF; - if (fraglen > (length - hlen) - 4) - fraglen = (length - hlen) - 4; - rp = (struct sunrpc_msg *)(fraglenp + 4); - if (TTEST(rp->rm_direction)) { - direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction); - if (dport == NFS_PORT && - direction == SUNRPC_CALL) { - nfsreq_print((u_char *)rp, fraglen, - (u_char *)ip); - return; - } - if (sport == NFS_PORT && - direction == SUNRPC_REPLY) { - nfsreply_print((u_char *)rp, fraglen, - (u_char *)ip); - return; - } - } - } - } #ifdef INET6 if (ip6) { if (ip6->ip6_nxt == IPPROTO_TCP) { @@ -283,109 +238,127 @@ tcp_print(register const u_char *bp, register u_int length, printf("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags)); if (!Sflag && (flags & TH_ACK)) { - register struct tcp_seq_hash *th; - const void *src, *dst; - register int rev; - struct tha tha; /* * 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). */ -#ifdef INET6 - memset(&tha, 0, sizeof(tha)); rev = 0; +#ifdef INET6 if (ip6) { + register struct tcp_seq_hash6 *th; + struct tcp_seq_hash6 *tcp_seq_hash; + const struct in6_addr *src, *dst; + struct tha6 tha; + + tcp_seq_hash = tcp_seq_hash6; src = &ip6->ip6_src; dst = &ip6->ip6_dst; if (sport > dport) rev = 1; else if (sport == dport) { - if (memcmp(src, dst, sizeof ip6->ip6_dst) > 0) + if (UNALIGNED_MEMCMP(src, dst, sizeof ip6->ip6_dst) > 0) rev = 1; } if (rev) { - memcpy(&tha.src, dst, sizeof ip6->ip6_dst); - memcpy(&tha.dst, src, sizeof ip6->ip6_src); + UNALIGNED_MEMCPY(&tha.src, dst, sizeof ip6->ip6_dst); + UNALIGNED_MEMCPY(&tha.dst, src, sizeof ip6->ip6_src); tha.port = dport << 16 | sport; } else { - memcpy(&tha.dst, dst, sizeof ip6->ip6_dst); - memcpy(&tha.src, src, sizeof ip6->ip6_src); + UNALIGNED_MEMCPY(&tha.dst, dst, sizeof ip6->ip6_dst); + UNALIGNED_MEMCPY(&tha.src, src, sizeof ip6->ip6_src); tha.port = sport << 16 | dport; } + + for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; + th->nxt; th = th->nxt) + if (memcmp((char *)&tha, (char *)&th->addr, + sizeof(th->addr)) == 0) + break; + + if (!th->nxt || (flags & TH_SYN)) { + /* didn't find it or new conversation */ + if (th->nxt == NULL) { + th->nxt = (struct tcp_seq_hash6 *) + calloc(1, sizeof(*th)); + if (th->nxt == NULL) + error("tcp_print: calloc"); + } + th->addr = tha; + if (rev) + th->ack = seq, th->seq = ack - 1; + else + th->seq = seq, th->ack = ack - 1; + } else { + if (rev) + seq -= th->ack, ack -= th->seq; + else + seq -= th->seq, ack -= th->ack; + } + + thseq = th->seq; + thack = th->ack; } else { +#else /*INET6*/ + { +#endif /*INET6*/ + register struct tcp_seq_hash *th; + struct tcp_seq_hash *tcp_seq_hash; + const struct in_addr *src, *dst; + struct tha tha; + + tcp_seq_hash = tcp_seq_hash4; src = &ip->ip_src; dst = &ip->ip_dst; if (sport > dport) rev = 1; else if (sport == dport) { - if (memcmp(src, dst, sizeof ip->ip_dst) > 0) + if (UNALIGNED_MEMCMP(src, dst, sizeof ip->ip_dst) > 0) rev = 1; } if (rev) { - memcpy(&tha.src, dst, sizeof ip->ip_dst); - memcpy(&tha.dst, src, sizeof ip->ip_src); + UNALIGNED_MEMCPY(&tha.src, dst, sizeof ip->ip_dst); + UNALIGNED_MEMCPY(&tha.dst, src, sizeof ip->ip_src); tha.port = dport << 16 | sport; } else { - memcpy(&tha.dst, dst, sizeof ip->ip_dst); - memcpy(&tha.src, src, sizeof ip->ip_src); + UNALIGNED_MEMCPY(&tha.dst, dst, sizeof ip->ip_dst); + UNALIGNED_MEMCPY(&tha.src, src, sizeof ip->ip_src); tha.port = sport << 16 | dport; } - } -#else - rev = 0; - src = &ip->ip_src; - dst = &ip->ip_dst; - if (sport > dport) - rev = 1; - else if (sport == dport) { - if (memcmp(src, dst, sizeof ip->ip_dst) > 0) - rev = 1; - } - if (rev) { - memcpy(&tha.src, dst, sizeof ip->ip_dst); - memcpy(&tha.dst, src, sizeof ip->ip_src); - tha.port = dport << 16 | sport; - } else { - memcpy(&tha.dst, dst, sizeof ip->ip_dst); - memcpy(&tha.src, src, sizeof ip->ip_src); - tha.port = sport << 16 | dport; - } -#endif - threv = rev; - for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; - th->nxt; th = th->nxt) - if (memcmp((char *)&tha, (char *)&th->addr, - sizeof(th->addr)) == 0) - break; + for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; + th->nxt; th = th->nxt) + if (memcmp((char *)&tha, (char *)&th->addr, + sizeof(th->addr)) == 0) + break; - if (!th->nxt || (flags & TH_SYN)) { - /* didn't find it or new conversation */ - if (th->nxt == NULL) { - th->nxt = (struct tcp_seq_hash *) - calloc(1, sizeof(*th)); - if (th->nxt == NULL) - error("tcp_print: calloc"); + if (!th->nxt || (flags & TH_SYN)) { + /* didn't find it or new conversation */ + if (th->nxt == NULL) { + th->nxt = (struct tcp_seq_hash *) + calloc(1, sizeof(*th)); + if (th->nxt == NULL) + error("tcp_print: calloc"); + } + th->addr = tha; + if (rev) + th->ack = seq, th->seq = ack - 1; + else + th->seq = seq, th->ack = ack - 1; + } else { + if (rev) + seq -= th->ack, ack -= th->seq; + else + seq -= th->seq, ack -= th->ack; } - th->addr = tha; - if (rev) - th->ack = seq, th->seq = ack - 1; - else - th->seq = seq, th->ack = ack - 1; - } else { - if (rev) - seq -= th->ack, ack -= th->seq; - else - seq -= th->seq, ack -= th->ack; - } - thseq = th->seq; - thack = th->ack; + thseq = th->seq; + thack = th->ack; + } } else { /*fool gcc*/ - thseq = thack = threv = 0; + thseq = thack = rev = 0; } if (hlen > length) { (void)printf(" [bad hdr length %u - too long, > %u]", @@ -393,34 +366,40 @@ tcp_print(register const u_char *bp, register u_int length, return; } - if (IP_V(ip) == 4 && vflag && !Kflag && !fragmented) { + if (vflag && !Kflag && !fragmented) { + /* Check the checksum, if possible. */ u_int16_t sum, tcp_sum; - if (TTEST2(tp->th_sport, length)) { - sum = tcp_cksum(ip, tp, length); - (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum)); - if (sum != 0) { + if (IP_V(ip) == 4) { + if (TTEST2(tp->th_sport, length)) { + sum = tcp_cksum(ip, tp, length); tcp_sum = EXTRACT_16BITS(&tp->th_sum); - (void)printf(" (incorrect -> 0x%04x)",in_cksum_shouldbe(tcp_sum, sum)); - } else - (void)printf(" (correct)"); + + (void)printf(", cksum 0x%04x", tcp_sum); + if (sum != 0) + (void)printf(" (incorrect -> 0x%04x)", + in_cksum_shouldbe(tcp_sum, sum)); + else + (void)printf(" (correct)"); + } } - } #ifdef INET6 - if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !Kflag && !fragmented) { - u_int16_t sum,tcp_sum; - if (TTEST2(tp->th_sport, length)) { - sum = nextproto6_cksum(ip6, (u_short *)tp, length, IPPROTO_TCP); - (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum)); - if (sum != 0) { + else if (IP_V(ip) == 6 && ip6->ip6_plen) { + if (TTEST2(tp->th_sport, length)) { + sum = nextproto6_cksum(ip6, (const u_int8_t *)tp, length, IPPROTO_TCP); tcp_sum = EXTRACT_16BITS(&tp->th_sum); - (void)printf(" (incorrect -> 0x%04x)",in_cksum_shouldbe(tcp_sum, sum)); - } else - (void)printf(" (correct)"); + (void)printf(", cksum 0x%04x", tcp_sum); + if (sum != 0) + (void)printf(" (incorrect -> 0x%04x)", + in_cksum_shouldbe(tcp_sum, sum)); + else + (void)printf(" (correct)"); + + } } - } #endif + } length -= hlen; if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) { @@ -471,7 +450,7 @@ tcp_print(register const u_char *bp, register u_int length, #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } - printf("%s", tok2str(tcp_option_values, "Unknown Option %u", opt)); + printf("%s", tok2str(tcp_option_values, "unknown-%u", opt)); switch (opt) { @@ -500,7 +479,7 @@ tcp_print(register const u_char *bp, register u_int length, s = EXTRACT_32BITS(cp + i); LENCHECK(i + 8); e = EXTRACT_32BITS(cp + i + 4); - if (threv) { + if (rev) { s -= thseq; e -= thseq; } else { @@ -593,8 +572,52 @@ tcp_print(register const u_char *bp, register u_int length, (void)printf(" %u", utoval); break; + case TCPOPT_MPTCP: + datalen = len - 2; + LENCHECK(datalen); + if (!mptcp_print(cp-2, len, flags)) + goto bad; + break; + + case TCPOPT_EXPERIMENT2: + datalen = len - 2; + LENCHECK(datalen); + if (datalen < 2) + goto bad; + /* RFC6994 */ + magic = EXTRACT_16BITS(cp); + (void)printf("-"); + + switch(magic) { + + case 0xf989: + /* TCP Fast Open: draft-ietf-tcpm-fastopen-04 */ + if (datalen == 2) { + /* Fast Open Cookie Request */ + (void)printf("tfo cookiereq"); + } else { + /* Fast Open Cookie */ + if (datalen % 2 != 0 || datalen < 6 || datalen > 18) { + (void)printf("tfo malformed"); + } else { + (void)printf("tfo cookie "); + for (i = 2; i < datalen; ++i) + (void)printf("%02x", cp[i]); + } + } + break; + + default: + /* Unknown magic number */ + (void)printf("%04x", magic); + break; + } + break; + default: datalen = len - 2; + if (datalen) + printf(" 0x"); for (i = 0; i < datalen; ++i) { LENCHECK(i); (void)printf("%02x", cp[i]); @@ -634,7 +657,16 @@ tcp_print(register const u_char *bp, register u_int length, if ((flags & TH_RST) && vflag) { print_tcp_rst_data(bp, length); return; - } + } + + if (packettype) { + switch (packettype) { + case PT_ZMTP1: + zmtp1_print(bp, length); + break; + } + return; + } if (sport == TELNET_PORT || dport == TELNET_PORT) { if (!qflag && vflag) @@ -651,6 +683,8 @@ tcp_print(register const u_char *bp, register u_int length, #endif else if (sport == BEEP_PORT || dport == BEEP_PORT) beep_print(bp, length); + else if (sport == OPENFLOW_PORT || dport == OPENFLOW_PORT) + openflow_print(bp, length); else if (length > 2 && (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT || sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) { @@ -661,10 +695,42 @@ tcp_print(register const u_char *bp, register u_int length, ns_print(bp + 2, length - 2, 0); } else if (sport == MSDP_PORT || dport == MSDP_PORT) { msdp_print(bp, length); + } else if (sport == RPKI_RTR_PORT || dport == RPKI_RTR_PORT) { + rpki_rtr_print(bp, length); } else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { ldp_print(bp, length); } + else if ((sport == NFS_PORT || dport == NFS_PORT) && + length >= 4 && TTEST2(*bp, 4)) { + /* + * 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. + */ + u_int32_t fraglen; + register struct sunrpc_msg *rp; + enum sunrpc_msg_type direction; + + fraglen = EXTRACT_32BITS(bp) & 0x7FFFFFFF; + if (fraglen > (length) - 4) + fraglen = (length) - 4; + rp = (struct sunrpc_msg *)(bp + 4); + if (TTEST(rp->rm_direction)) { + direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction); + if (dport == NFS_PORT && direction == SUNRPC_CALL) { + (void)printf(": NFS request xid %u ", EXTRACT_32BITS(&rp->rm_xid)); + nfsreq_print_noaddr((u_char *)rp, fraglen, (u_char *)ip); + return; + } + if (sport == NFS_PORT && direction == SUNRPC_REPLY) { + (void)printf(": NFS reply xid %u ", EXTRACT_32BITS(&rp->rm_xid)); + nfsreply_print_noaddr((u_char *)rp, fraglen, (u_char *)ip); + return; + } + } + } return; bad: @@ -715,6 +781,7 @@ print_tcp_rst_data(register const u_char *sp, u_int length) } #ifdef HAVE_LIBCRYPTO +USES_APPLE_DEPRECATED_API static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, const u_char *data, int length, const u_char *rcvsig) @@ -801,6 +868,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, else return (SIGNATURE_INVALID); } +USES_APPLE_RST #endif /* HAVE_LIBCRYPTO */ /*