14edb46e9SPaul Traina /* 24edb46e9SPaul Traina * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 34edb46e9SPaul Traina * The Regents of the University of California. All rights reserved. 44edb46e9SPaul Traina * 54edb46e9SPaul Traina * Redistribution and use in source and binary forms, with or without 64edb46e9SPaul Traina * modification, are permitted provided that: (1) source code distributions 74edb46e9SPaul Traina * retain the above copyright notice and this paragraph in its entirety, (2) 84edb46e9SPaul Traina * distributions including binary code include the above copyright notice and 94edb46e9SPaul Traina * this paragraph in its entirety in the documentation or other materials 104edb46e9SPaul Traina * provided with the distribution, and (3) all advertising materials mentioning 114edb46e9SPaul Traina * features or use of this software display the following acknowledgement: 124edb46e9SPaul Traina * ``This product includes software developed by the University of California, 134edb46e9SPaul Traina * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 144edb46e9SPaul Traina * the University nor the names of its contributors may be used to endorse 154edb46e9SPaul Traina * or promote products derived from this software without specific prior 164edb46e9SPaul Traina * written permission. 174edb46e9SPaul Traina * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 184edb46e9SPaul Traina * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 194edb46e9SPaul Traina * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 204edb46e9SPaul Traina */ 214edb46e9SPaul Traina 224edb46e9SPaul Traina #ifndef lint 234edb46e9SPaul Traina static char rcsid[] = 244edb46e9SPaul Traina "@(#) $Header: print-tcp.c,v 1.46 96/07/23 14:17:27 leres Exp $ (LBL)"; 254edb46e9SPaul Traina #endif 264edb46e9SPaul Traina 274edb46e9SPaul Traina #include <sys/param.h> 284edb46e9SPaul Traina #include <sys/time.h> 294edb46e9SPaul Traina 304edb46e9SPaul Traina #include <netinet/in.h> 314edb46e9SPaul Traina #include <netinet/in_systm.h> 324edb46e9SPaul Traina #include <netinet/ip.h> 334edb46e9SPaul Traina #include <netinet/ip_var.h> 344edb46e9SPaul Traina #include <netinet/tcp.h> 354edb46e9SPaul Traina #include <netinet/tcpip.h> 364edb46e9SPaul Traina 374edb46e9SPaul Traina #include <stdio.h> 384edb46e9SPaul Traina #include <stdlib.h> 394edb46e9SPaul Traina #include <string.h> 404edb46e9SPaul Traina #include <unistd.h> 414edb46e9SPaul Traina 424edb46e9SPaul Traina #include "interface.h" 434edb46e9SPaul Traina #include "addrtoname.h" 444edb46e9SPaul Traina #include "extract.h" 454edb46e9SPaul Traina 464edb46e9SPaul Traina /* Compatibility */ 474edb46e9SPaul Traina #ifndef TCPOPT_WSCALE 484edb46e9SPaul Traina #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 494edb46e9SPaul Traina #endif 504edb46e9SPaul Traina #ifndef TCPOPT_SACKOK 514edb46e9SPaul Traina #define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ 524edb46e9SPaul Traina #endif 534edb46e9SPaul Traina #ifndef TCPOPT_SACK 544edb46e9SPaul Traina #define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 554edb46e9SPaul Traina #endif 564edb46e9SPaul Traina #ifndef TCPOPT_ECHO 574edb46e9SPaul Traina #define TCPOPT_ECHO 6 /* echo (rfc1072) */ 584edb46e9SPaul Traina #endif 594edb46e9SPaul Traina #ifndef TCPOPT_ECHOREPLY 604edb46e9SPaul Traina #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 614edb46e9SPaul Traina #endif 624edb46e9SPaul Traina #ifndef TCPOPT_TIMESTAMP 634edb46e9SPaul Traina #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 644edb46e9SPaul Traina #endif 654edb46e9SPaul Traina #ifndef TCPOPT_CC 664edb46e9SPaul Traina #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 674edb46e9SPaul Traina #endif 684edb46e9SPaul Traina #ifndef TCPOPT_CCNEW 694edb46e9SPaul Traina #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 704edb46e9SPaul Traina #endif 714edb46e9SPaul Traina #ifndef TCPOPT_CCECHO 724edb46e9SPaul Traina #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 734edb46e9SPaul Traina #endif 744edb46e9SPaul Traina 754edb46e9SPaul Traina struct tha { 764edb46e9SPaul Traina struct in_addr src; 774edb46e9SPaul Traina struct in_addr dst; 784edb46e9SPaul Traina u_int port; 794edb46e9SPaul Traina }; 804edb46e9SPaul Traina 814edb46e9SPaul Traina struct tcp_seq_hash { 824edb46e9SPaul Traina struct tcp_seq_hash *nxt; 834edb46e9SPaul Traina struct tha addr; 844edb46e9SPaul Traina tcp_seq seq; 854edb46e9SPaul Traina tcp_seq ack; 864edb46e9SPaul Traina }; 874edb46e9SPaul Traina 884edb46e9SPaul Traina #define TSEQ_HASHSIZE 919 894edb46e9SPaul Traina 904edb46e9SPaul Traina /* These tcp optinos do not have the size octet */ 914edb46e9SPaul Traina #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 924edb46e9SPaul Traina 934edb46e9SPaul Traina static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 944edb46e9SPaul Traina 954edb46e9SPaul Traina 964edb46e9SPaul Traina void 974edb46e9SPaul Traina tcp_print(register const u_char *bp, register u_int length, 984edb46e9SPaul Traina register const u_char *bp2) 994edb46e9SPaul Traina { 1004edb46e9SPaul Traina register const struct tcphdr *tp; 1014edb46e9SPaul Traina register const struct ip *ip; 1024edb46e9SPaul Traina register u_char flags; 1034edb46e9SPaul Traina register u_int hlen; 1044edb46e9SPaul Traina register char ch; 1054edb46e9SPaul Traina u_short sport, dport, win, urp; 1064edb46e9SPaul Traina u_int32_t seq, ack; 1074edb46e9SPaul Traina 1084edb46e9SPaul Traina tp = (struct tcphdr *)bp; 1094edb46e9SPaul Traina ip = (struct ip *)bp2; 1104edb46e9SPaul Traina ch = '\0'; 1114edb46e9SPaul Traina TCHECK(*tp); 1124edb46e9SPaul Traina if (length < sizeof(*tp)) { 1134edb46e9SPaul Traina (void)printf("truncated-tcp %d", length); 1144edb46e9SPaul Traina return; 1154edb46e9SPaul Traina } 1164edb46e9SPaul Traina 1174edb46e9SPaul Traina sport = ntohs(tp->th_sport); 1184edb46e9SPaul Traina dport = ntohs(tp->th_dport); 1194edb46e9SPaul Traina seq = ntohl(tp->th_seq); 1204edb46e9SPaul Traina ack = ntohl(tp->th_ack); 1214edb46e9SPaul Traina win = ntohs(tp->th_win); 1224edb46e9SPaul Traina urp = ntohs(tp->th_urp); 1234edb46e9SPaul Traina 1244edb46e9SPaul Traina (void)printf("%s.%s > %s.%s: ", 1254edb46e9SPaul Traina ipaddr_string(&ip->ip_src), tcpport_string(sport), 1264edb46e9SPaul Traina ipaddr_string(&ip->ip_dst), tcpport_string(dport)); 1274edb46e9SPaul Traina 1284edb46e9SPaul Traina if (qflag) { 1294edb46e9SPaul Traina (void)printf("tcp %d", length - tp->th_off * 4); 1304edb46e9SPaul Traina return; 1314edb46e9SPaul Traina } 1324edb46e9SPaul Traina if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { 1334edb46e9SPaul Traina if (flags & TH_SYN) 1344edb46e9SPaul Traina putchar('S'); 1354edb46e9SPaul Traina if (flags & TH_FIN) 1364edb46e9SPaul Traina putchar('F'); 1374edb46e9SPaul Traina if (flags & TH_RST) 1384edb46e9SPaul Traina putchar('R'); 1394edb46e9SPaul Traina if (flags & TH_PUSH) 1404edb46e9SPaul Traina putchar('P'); 1414edb46e9SPaul Traina } else 1424edb46e9SPaul Traina putchar('.'); 1434edb46e9SPaul Traina 1444edb46e9SPaul Traina if (!Sflag && (flags & TH_ACK)) { 1454edb46e9SPaul Traina register struct tcp_seq_hash *th; 1464edb46e9SPaul Traina register int rev; 1474edb46e9SPaul Traina struct tha tha; 1484edb46e9SPaul Traina /* 1494edb46e9SPaul Traina * Find (or record) the initial sequence numbers for 1504edb46e9SPaul Traina * this conversation. (we pick an arbitrary 1514edb46e9SPaul Traina * collating order so there's only one entry for 1524edb46e9SPaul Traina * both directions). 1534edb46e9SPaul Traina */ 1544edb46e9SPaul Traina if (sport < dport || 1554edb46e9SPaul Traina (sport == dport && 1564edb46e9SPaul Traina ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 1574edb46e9SPaul Traina tha.src = ip->ip_src, tha.dst = ip->ip_dst; 1584edb46e9SPaul Traina tha.port = sport << 16 | dport; 1594edb46e9SPaul Traina rev = 0; 1604edb46e9SPaul Traina } else { 1614edb46e9SPaul Traina tha.src = ip->ip_dst, tha.dst = ip->ip_src; 1624edb46e9SPaul Traina tha.port = dport << 16 | sport; 1634edb46e9SPaul Traina rev = 1; 1644edb46e9SPaul Traina } 1654edb46e9SPaul Traina 1664edb46e9SPaul Traina for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 1674edb46e9SPaul Traina th->nxt; th = th->nxt) 1684edb46e9SPaul Traina if (!memcmp((char *)&tha, (char *)&th->addr, 1694edb46e9SPaul Traina sizeof(th->addr))) 1704edb46e9SPaul Traina break; 1714edb46e9SPaul Traina 1724edb46e9SPaul Traina if (!th->nxt || flags & TH_SYN) { 1734edb46e9SPaul Traina /* didn't find it or new conversation */ 1744edb46e9SPaul Traina if (th->nxt == NULL) { 1754edb46e9SPaul Traina th->nxt = (struct tcp_seq_hash *) 1764edb46e9SPaul Traina calloc(1, sizeof(*th)); 1774edb46e9SPaul Traina if (th->nxt == NULL) 1784edb46e9SPaul Traina error("tcp_print: calloc"); 1794edb46e9SPaul Traina } 1804edb46e9SPaul Traina th->addr = tha; 1814edb46e9SPaul Traina if (rev) 1824edb46e9SPaul Traina th->ack = seq, th->seq = ack - 1; 1834edb46e9SPaul Traina else 1844edb46e9SPaul Traina th->seq = seq, th->ack = ack - 1; 1854edb46e9SPaul Traina } else { 1864edb46e9SPaul Traina if (rev) 1874edb46e9SPaul Traina seq -= th->ack, ack -= th->seq; 1884edb46e9SPaul Traina else 1894edb46e9SPaul Traina seq -= th->seq, ack -= th->ack; 1904edb46e9SPaul Traina } 1914edb46e9SPaul Traina } 1924edb46e9SPaul Traina hlen = tp->th_off * 4; 1934edb46e9SPaul Traina length -= hlen; 1944edb46e9SPaul Traina if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 1954edb46e9SPaul Traina (void)printf(" %u:%u(%d)", seq, seq + length, length); 1964edb46e9SPaul Traina if (flags & TH_ACK) 1974edb46e9SPaul Traina (void)printf(" ack %u", ack); 1984edb46e9SPaul Traina 1994edb46e9SPaul Traina (void)printf(" win %d", win); 2004edb46e9SPaul Traina 2014edb46e9SPaul Traina if (flags & TH_URG) 2024edb46e9SPaul Traina (void)printf(" urg %d", urp); 2034edb46e9SPaul Traina /* 2044edb46e9SPaul Traina * Handle any options. 2054edb46e9SPaul Traina */ 2064edb46e9SPaul Traina if ((hlen -= sizeof(*tp)) > 0) { 2074edb46e9SPaul Traina register const u_char *cp; 2084edb46e9SPaul Traina register int i, opt, len, datalen; 2094edb46e9SPaul Traina 2104edb46e9SPaul Traina cp = (const u_char *)tp + sizeof(*tp); 2114edb46e9SPaul Traina putchar(' '); 2124edb46e9SPaul Traina ch = '<'; 2134edb46e9SPaul Traina while (hlen > 0) { 2144edb46e9SPaul Traina --hlen; 2154edb46e9SPaul Traina putchar(ch); 2164edb46e9SPaul Traina if (cp > snapend) 2174edb46e9SPaul Traina goto trunc; 2184edb46e9SPaul Traina opt = *cp++; 2194edb46e9SPaul Traina if (ZEROLENOPT(opt)) 2204edb46e9SPaul Traina len = 1; 2214edb46e9SPaul Traina else { 2224edb46e9SPaul Traina if (cp > snapend) 2234edb46e9SPaul Traina goto trunc; 2244edb46e9SPaul Traina len = *cp++; 2254edb46e9SPaul Traina --hlen; 2264edb46e9SPaul Traina } 2274edb46e9SPaul Traina datalen = 0; 2284edb46e9SPaul Traina switch (opt) { 2294edb46e9SPaul Traina 2304edb46e9SPaul Traina case TCPOPT_MAXSEG: 2314edb46e9SPaul Traina (void)printf("mss"); 2324edb46e9SPaul Traina datalen = 2; 2334edb46e9SPaul Traina if (cp + datalen > snapend) 2344edb46e9SPaul Traina goto trunc; 2354edb46e9SPaul Traina (void)printf(" %u", EXTRACT_16BITS(cp)); 2364edb46e9SPaul Traina 2374edb46e9SPaul Traina break; 2384edb46e9SPaul Traina 2394edb46e9SPaul Traina case TCPOPT_EOL: 2404edb46e9SPaul Traina (void)printf("eol"); 2414edb46e9SPaul Traina break; 2424edb46e9SPaul Traina 2434edb46e9SPaul Traina case TCPOPT_NOP: 2444edb46e9SPaul Traina (void)printf("nop"); 2454edb46e9SPaul Traina break; 2464edb46e9SPaul Traina 2474edb46e9SPaul Traina case TCPOPT_WSCALE: 2484edb46e9SPaul Traina (void)printf("wscale"); 2494edb46e9SPaul Traina datalen = 1; 2504edb46e9SPaul Traina if (cp + datalen > snapend) 2514edb46e9SPaul Traina goto trunc; 2524edb46e9SPaul Traina (void)printf(" %u", *cp); 2534edb46e9SPaul Traina break; 2544edb46e9SPaul Traina 2554edb46e9SPaul Traina case TCPOPT_SACKOK: 2564edb46e9SPaul Traina (void)printf("sackOK"); 2574edb46e9SPaul Traina break; 2584edb46e9SPaul Traina 2594edb46e9SPaul Traina case TCPOPT_SACK: 2604edb46e9SPaul Traina (void)printf("sack"); 2614edb46e9SPaul Traina datalen = len - 2; 2624edb46e9SPaul Traina i = datalen; 2634edb46e9SPaul Traina for (i = datalen; i > 0; i -= 4) { 2644edb46e9SPaul Traina if (cp + i + 4 > snapend) 2654edb46e9SPaul Traina goto trunc; 2664edb46e9SPaul Traina /* block-size@relative-origin */ 2674edb46e9SPaul Traina (void)printf(" %u@%u", 2684edb46e9SPaul Traina EXTRACT_16BITS(cp + 2), 2694edb46e9SPaul Traina EXTRACT_16BITS(cp)); 2704edb46e9SPaul Traina } 2714edb46e9SPaul Traina if (datalen % 4) 2724edb46e9SPaul Traina (void)printf("[len %d]", len); 2734edb46e9SPaul Traina break; 2744edb46e9SPaul Traina 2754edb46e9SPaul Traina case TCPOPT_ECHO: 2764edb46e9SPaul Traina (void)printf("echo"); 2774edb46e9SPaul Traina datalen = 4; 2784edb46e9SPaul Traina if (cp + datalen > snapend) 2794edb46e9SPaul Traina goto trunc; 2804edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 2814edb46e9SPaul Traina break; 2824edb46e9SPaul Traina 2834edb46e9SPaul Traina case TCPOPT_ECHOREPLY: 2844edb46e9SPaul Traina (void)printf("echoreply"); 2854edb46e9SPaul Traina datalen = 4; 2864edb46e9SPaul Traina if (cp + datalen > snapend) 2874edb46e9SPaul Traina goto trunc; 2884edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 2894edb46e9SPaul Traina break; 2904edb46e9SPaul Traina 2914edb46e9SPaul Traina case TCPOPT_TIMESTAMP: 2924edb46e9SPaul Traina (void)printf("timestamp"); 2934edb46e9SPaul Traina datalen = 4; 2944edb46e9SPaul Traina if (cp + datalen > snapend) 2954edb46e9SPaul Traina goto trunc; 2964edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 2974edb46e9SPaul Traina datalen += 4; 2984edb46e9SPaul Traina if (cp + datalen > snapend) 2994edb46e9SPaul Traina goto trunc; 3004edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 3014edb46e9SPaul Traina break; 3024edb46e9SPaul Traina 3034edb46e9SPaul Traina case TCPOPT_CC: 3044edb46e9SPaul Traina (void)printf("cc"); 3054edb46e9SPaul Traina datalen = 4; 3064edb46e9SPaul Traina if (cp + datalen > snapend) 3074edb46e9SPaul Traina goto trunc; 3084edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 3094edb46e9SPaul Traina break; 3104edb46e9SPaul Traina 3114edb46e9SPaul Traina case TCPOPT_CCNEW: 3124edb46e9SPaul Traina (void)printf("ccnew"); 3134edb46e9SPaul Traina datalen = 4; 3144edb46e9SPaul Traina if (cp + datalen > snapend) 3154edb46e9SPaul Traina goto trunc; 3164edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 3174edb46e9SPaul Traina break; 3184edb46e9SPaul Traina 3194edb46e9SPaul Traina case TCPOPT_CCECHO: 3204edb46e9SPaul Traina (void)printf("ccecho"); 3214edb46e9SPaul Traina datalen = 4; 3224edb46e9SPaul Traina if (cp + datalen > snapend) 3234edb46e9SPaul Traina goto trunc; 3244edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 3254edb46e9SPaul Traina break; 3264edb46e9SPaul Traina 3274edb46e9SPaul Traina default: 3284edb46e9SPaul Traina (void)printf("opt-%d:", opt); 3294edb46e9SPaul Traina datalen = len - 2; 3304edb46e9SPaul Traina if (datalen < 0) 3314edb46e9SPaul Traina datalen = 0; 3324edb46e9SPaul Traina for (i = 0; i < datalen; ++i) { 3334edb46e9SPaul Traina if (cp + i > snapend) 3344edb46e9SPaul Traina goto trunc; 3354edb46e9SPaul Traina (void)printf("%02x", cp[i]); 3364edb46e9SPaul Traina } 3374edb46e9SPaul Traina break; 3384edb46e9SPaul Traina } 3394edb46e9SPaul Traina 3404edb46e9SPaul Traina /* Account for data printed */ 3414edb46e9SPaul Traina cp += datalen; 3424edb46e9SPaul Traina hlen -= datalen; 3434edb46e9SPaul Traina 3444edb46e9SPaul Traina /* Check specification against observed length */ 3454edb46e9SPaul Traina ++datalen; /* option octet */ 3464edb46e9SPaul Traina if (!ZEROLENOPT(opt)) 3474edb46e9SPaul Traina ++datalen; /* size octet */ 3484edb46e9SPaul Traina if (datalen != len) 3494edb46e9SPaul Traina (void)printf("[len %d]", len); 3504edb46e9SPaul Traina ch = ','; 3514edb46e9SPaul Traina } 3524edb46e9SPaul Traina putchar('>'); 3534edb46e9SPaul Traina } 3544edb46e9SPaul Traina return; 3554edb46e9SPaul Traina trunc: 3564edb46e9SPaul Traina fputs("[|tcp]", stdout); 3574edb46e9SPaul Traina if (ch != '\0') 3584edb46e9SPaul Traina putchar('>'); 3594edb46e9SPaul Traina } 3604edb46e9SPaul Traina 361