X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/05b7f224d84449f43e1e7714ef73e7602af27f28..f53e36817312f87f7f41463b70fe320aeb21e02e:/print-tcp.c diff --git a/print-tcp.c b/print-tcp.c index a4ddfeb2..f8e0ee72 100644 --- a/print-tcp.c +++ b/print-tcp.c @@ -25,8 +25,8 @@ #ifndef lint static const char rcsid[] _U_ = -"@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.130 2007-08-29 02:31:44 mcr Exp $ (LBL)"; - #else +"@(#) $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 @@ -58,10 +58,7 @@ __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $"); #ifdef HAVE_LIBCRYPTO #include - -#define SIGNATURE_VALID 0 -#define SIGNATURE_INVALID 1 -#define CANT_CHECK_SIGNATURE 2 +#include static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, const u_char *data, int length, const u_char *rcvsig); @@ -97,7 +94,7 @@ struct tcp_seq_hash { static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; -struct tok tcp_flag_values[] = { +static const struct tok tcp_flag_values[] = { { TH_FIN, "F" }, { TH_SYN, "S" }, { TH_RST, "R" }, @@ -109,7 +106,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" }, @@ -124,6 +121,9 @@ struct tok tcp_option_values[] = { { TCPOPT_CCECHO, "" }, { TCPOPT_SIGNATURE, "md5" }, { TCPOPT_AUTH, "enhanced auth" }, + { TCPOPT_UTO, "uto" }, + { TCPOPT_MPTCP, "mptcp" }, + { TCPOPT_EXPERIMENT2, "exp" }, { 0, NULL } }; @@ -131,64 +131,10 @@ 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)); } -#ifdef INET6 -static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp, - u_int len) -{ - size_t i; - u_int32_t sum = 0; - union { - struct { - struct in6_addr ph_src; - struct in6_addr ph_dst; - u_int32_t ph_len; - u_int8_t ph_zero[3]; - u_int8_t ph_nxt; - } ph; - u_int16_t pa[20]; - } phu; - - /* pseudo-header */ - memset(&phu, 0, sizeof(phu)); - phu.ph.ph_src = ip6->ip6_src; - phu.ph.ph_dst = ip6->ip6_dst; - phu.ph.ph_len = htonl(len); - phu.ph.ph_nxt = IPPROTO_TCP; - - for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) - sum += phu.pa[i]; - - return in_cksum((u_short *)tp, len, sum); -} -#endif - void tcp_print(register const u_char *bp, register u_int length, register const u_char *bp2, int fragmented) @@ -200,7 +146,9 @@ tcp_print(register const u_char *bp, register u_int length, register char ch; u_int16_t sport, dport, win, urp; u_int32_t seq, ack, thseq, thack; - int threv; + u_int utoval; + u_int16_t magic; + register int rev; #ifdef INET6 register const struct ip6_hdr *ip6; #endif @@ -227,23 +175,39 @@ 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) { - if ((u_char *)tp + 4 + sizeof(struct sunrpc_msg) <= snapend && - dport == NFS_PORT) { - nfsreq_print((u_char *)tp + hlen + 4, length - hlen, - (u_char *)ip); - return; - } else if ((u_char *)tp + 4 + sizeof(struct sunrpc_msg) - <= snapend && - sport == NFS_PORT) { - nfsreply_print((u_char *)tp + hlen + 4, length - hlen, - (u_char *)ip); - return; + * 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 @@ -301,7 +265,6 @@ tcp_print(register const u_char *bp, register u_int length, 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 @@ -310,7 +273,6 @@ tcp_print(register const u_char *bp, register u_int length, * both directions). */ #ifdef INET6 - memset(&tha, 0, sizeof(tha)); rev = 0; if (ip6) { src = &ip6->ip6_src; @@ -331,6 +293,27 @@ tcp_print(register const u_char *bp, register u_int length, tha.port = sport << 16 | dport; } } else { + /* + * Zero out the tha structure; the src and dst + * fields are big enough to hold an IPv6 + * address, but we only have IPv4 addresses + * and thus must clear out the remaining 124 + * bits. + * + * XXX - should we just clear those bytes after + * copying the IPv4 addresses, rather than + * zeroing out the entire structure and then + * overwriting some of the zeroes? + * + * XXX - this could fail if we see TCP packets + * with an IPv6 address with the lower 124 bits + * all zero and also see TCP packes with an + * IPv4 address with the same 32 bits as the + * upper 32 bits of the IPv6 address in question. + * Can that happen? Is it likely enough to be + * an issue? + */ + memset(&tha, 0, sizeof(tha)); src = &ip->ip_src; dst = &ip->ip_dst; if (sport > dport) @@ -370,7 +353,6 @@ tcp_print(register const u_char *bp, register u_int length, } #endif - threv = rev; for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; th->nxt; th = th->nxt) if (memcmp((char *)&tha, (char *)&th->addr, @@ -401,7 +383,7 @@ tcp_print(register const u_char *bp, register u_int length, 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]", @@ -409,37 +391,43 @@ 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 = tcp6_cksum(ip6, tp, length); - (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 || flags & (TH_SYN | TH_FIN | TH_RST)) { + if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) { (void)printf(", seq %u", seq); if (length > 0) { @@ -516,7 +504,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 { @@ -597,6 +585,60 @@ tcp_print(register const u_char *bp, register u_int length, */ break; + case TCPOPT_UTO: + datalen = 2; + LENCHECK(datalen); + utoval = EXTRACT_16BITS(cp); + (void)printf("0x%x", utoval); + if (utoval & 0x0001) + utoval = (utoval >> 1) * 60; + else + utoval >>= 1; + (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; for (i = 0; i < datalen; ++i) { @@ -640,6 +682,15 @@ tcp_print(register const u_char *bp, register u_int 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) telnet_print(bp, length); @@ -650,9 +701,13 @@ tcp_print(register const u_char *bp, register u_int length, #ifdef TCPDUMP_DO_SMB else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) nbt_tcp_print(bp, length); + else if (sport == SMB_PORT || dport == SMB_PORT) + smb_tcp_print(bp, 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)) { @@ -663,6 +718,8 @@ 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); @@ -717,6 +774,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) @@ -732,10 +790,17 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, u_int8_t nxt; #endif + if (data + length > snapend) { + printf("snaplen too short, "); + return (CANT_CHECK_SIGNATURE); + } + tp1 = *tp; - if (tcpmd5secret == NULL) + if (sigsecret == NULL) { + printf("shared secret not supplied with -M, "); return (CANT_CHECK_SIGNATURE); + } MD5_Init(&ctx); /* @@ -754,7 +819,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, ip6 = (struct ip6_hdr *)ip; MD5_Update(&ctx, (char *)&ip6->ip6_src, sizeof(ip6->ip6_src)); MD5_Update(&ctx, (char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst)); - len32 = htonl(ntohs(ip6->ip6_plen)); + len32 = htonl(EXTRACT_16BITS(&ip6->ip6_plen)); MD5_Update(&ctx, (char *)&len32, sizeof(len32)); nxt = 0; MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); @@ -763,8 +828,14 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, nxt = IPPROTO_TCP; MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); #endif - } else + } else { +#ifdef INET6 + printf("IP version not 4 or 6, "); +#else + printf("IP version not 4, "); +#endif return (CANT_CHECK_SIGNATURE); + } /* * Step 2: Update MD5 hash with TCP header, excluding options. @@ -782,7 +853,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, /* * Step 4: Update MD5 hash with shared secret. */ - MD5_Update(&ctx, tcpmd5secret, strlen(tcpmd5secret)); + MD5_Update(&ctx, sigsecret, strlen(sigsecret)); MD5_Final(sig, &ctx); if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0) @@ -790,6 +861,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, else return (SIGNATURE_INVALID); } +USES_APPLE_RST #endif /* HAVE_LIBCRYPTO */ /*