+ }
+ }
+#ifdef INET6
+ if (ip6) {
+ if (ip6->ip6_nxt == IPPROTO_TCP) {
+ (void)printf("%s.%s > %s.%s: ",
+ ip6addr_string(&ip6->ip6_src),
+ tcpport_string(sport),
+ ip6addr_string(&ip6->ip6_dst),
+ tcpport_string(dport));
+ } else {
+ (void)printf("%s > %s: ",
+ tcpport_string(sport), tcpport_string(dport));
+ }
+ } else
+#endif /*INET6*/
+ {
+ if (ip->ip_p == IPPROTO_TCP) {
+ (void)printf("%s.%s > %s.%s: ",
+ ipaddr_string(&ip->ip_src),
+ tcpport_string(sport),
+ ipaddr_string(&ip->ip_dst),
+ tcpport_string(dport));
+ } else {
+ (void)printf("%s > %s: ",
+ tcpport_string(sport), tcpport_string(dport));
+ }
+ }
+
+ if (hlen < sizeof(*tp)) {
+ (void)printf(" tcp %d [bad hdr length %u - too short, < %lu]",
+ length - hlen, hlen, (unsigned long)sizeof(*tp));
+ return;
+ }
+
+ TCHECK(*tp);
+
+ seq = EXTRACT_32BITS(&tp->th_seq);
+ ack = EXTRACT_32BITS(&tp->th_ack);
+ win = EXTRACT_16BITS(&tp->th_win);
+ urp = EXTRACT_16BITS(&tp->th_urp);
+
+ if (qflag) {
+ (void)printf("tcp %d", length - hlen);
+ if (hlen > length) {
+ (void)printf(" [bad hdr length %u - too long, > %u]",
+ hlen, length);
+ }
+ return;
+ }
+
+ flags = tp->th_flags;
+ 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
+ rev = 0;
+ if (ip6) {
+ 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)
+ rev = 1;
+ }
+ if (rev) {
+ memcpy(&tha.src, dst, sizeof ip6->ip6_dst);
+ 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);
+ 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)
+ 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;
+ }
+ }
+#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;
+
+ 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;
+ }
+
+ thseq = th->seq;
+ thack = th->ack;
+ } else {
+ /*fool gcc*/
+ thseq = thack = threv = 0;
+ }
+ if (hlen > length) {
+ (void)printf(" [bad hdr length %u - too long, > %u]",
+ hlen, length);
+ return;
+ }
+
+ if (vflag && !Kflag && !fragmented) {
+ /* Check the checksum, if possible. */
+ u_int16_t sum, tcp_sum;
+
+ 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(", 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
+ 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(", 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)) {
+ (void)printf(", seq %u", seq);
+
+ if (length > 0) {
+ (void)printf(":%u", seq + length);
+ }
+ }
+
+ if (flags & TH_ACK) {
+ (void)printf(", ack %u", ack);
+ }
+
+ (void)printf(", win %d", win);
+
+ if (flags & TH_URG)
+ (void)printf(", urg %d", urp);
+ /*
+ * Handle any options.
+ */
+ if (hlen > sizeof(*tp)) {
+ register const u_char *cp;
+ register u_int i, opt, datalen;
+ register u_int len;
+
+ hlen -= sizeof(*tp);
+ cp = (const u_char *)tp + sizeof(*tp);
+ printf(", options [");
+ while (hlen > 0) {
+ if (ch != '\0')
+ putchar(ch);
+ TCHECK(*cp);
+ opt = *cp++;
+ if (ZEROLENOPT(opt))
+ len = 1;
+ else {
+ TCHECK(*cp);
+ len = *cp++; /* total including type, len */
+ if (len < 2 || len > hlen)
+ goto bad;
+ --hlen; /* account for length byte */
+ }
+ --hlen; /* account for type byte */
+ datalen = 0;