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 234de76e31SBill Fenner static const char rcsid[] = 244de76e31SBill Fenner "@(#) $Header: print-tcp.c,v 1.52 96/12/03 10:59:55 vern 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; 1034de76e31SBill Fenner register 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; 1934de76e31SBill Fenner if (hlen > length) { 1944de76e31SBill Fenner (void)printf(" [bad hdr length]"); 1954de76e31SBill Fenner return; 1964de76e31SBill Fenner } 1974edb46e9SPaul Traina length -= hlen; 1984edb46e9SPaul Traina if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 1994edb46e9SPaul Traina (void)printf(" %u:%u(%d)", seq, seq + length, length); 2004edb46e9SPaul Traina if (flags & TH_ACK) 2014edb46e9SPaul Traina (void)printf(" ack %u", ack); 2024edb46e9SPaul Traina 2034edb46e9SPaul Traina (void)printf(" win %d", win); 2044edb46e9SPaul Traina 2054edb46e9SPaul Traina if (flags & TH_URG) 2064edb46e9SPaul Traina (void)printf(" urg %d", urp); 2074edb46e9SPaul Traina /* 2084edb46e9SPaul Traina * Handle any options. 2094edb46e9SPaul Traina */ 2104edb46e9SPaul Traina if ((hlen -= sizeof(*tp)) > 0) { 2114edb46e9SPaul Traina register const u_char *cp; 2124edb46e9SPaul Traina register int i, opt, len, datalen; 2134edb46e9SPaul Traina 2144edb46e9SPaul Traina cp = (const u_char *)tp + sizeof(*tp); 2154edb46e9SPaul Traina putchar(' '); 2164edb46e9SPaul Traina ch = '<'; 2174edb46e9SPaul Traina while (hlen > 0) { 2184edb46e9SPaul Traina putchar(ch); 2194de76e31SBill Fenner TCHECK(*cp); 2204edb46e9SPaul Traina opt = *cp++; 2214edb46e9SPaul Traina if (ZEROLENOPT(opt)) 2224edb46e9SPaul Traina len = 1; 2234edb46e9SPaul Traina else { 2244de76e31SBill Fenner TCHECK(*cp); 2254de76e31SBill Fenner len = *cp++; /* total including type, len */ 2264de76e31SBill Fenner if (len < 2 || len > hlen) 2274de76e31SBill Fenner goto bad; 2284de76e31SBill Fenner --hlen; /* account for length byte */ 2294edb46e9SPaul Traina } 2304de76e31SBill Fenner --hlen; /* account for type byte */ 2314edb46e9SPaul Traina datalen = 0; 2324de76e31SBill Fenner 2334de76e31SBill Fenner /* Bail if "l" bytes of data are not left or were not captured */ 2344de76e31SBill Fenner #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 2354de76e31SBill Fenner 2364edb46e9SPaul Traina switch (opt) { 2374edb46e9SPaul Traina 2384edb46e9SPaul Traina case TCPOPT_MAXSEG: 2394edb46e9SPaul Traina (void)printf("mss"); 2404edb46e9SPaul Traina datalen = 2; 2414de76e31SBill Fenner LENCHECK(datalen); 2424edb46e9SPaul Traina (void)printf(" %u", EXTRACT_16BITS(cp)); 2434edb46e9SPaul Traina 2444edb46e9SPaul Traina break; 2454edb46e9SPaul Traina 2464edb46e9SPaul Traina case TCPOPT_EOL: 2474edb46e9SPaul Traina (void)printf("eol"); 2484edb46e9SPaul Traina break; 2494edb46e9SPaul Traina 2504edb46e9SPaul Traina case TCPOPT_NOP: 2514edb46e9SPaul Traina (void)printf("nop"); 2524edb46e9SPaul Traina break; 2534edb46e9SPaul Traina 2544edb46e9SPaul Traina case TCPOPT_WSCALE: 2554edb46e9SPaul Traina (void)printf("wscale"); 2564edb46e9SPaul Traina datalen = 1; 2574de76e31SBill Fenner LENCHECK(datalen); 2584edb46e9SPaul Traina (void)printf(" %u", *cp); 2594edb46e9SPaul Traina break; 2604edb46e9SPaul Traina 2614edb46e9SPaul Traina case TCPOPT_SACKOK: 2624edb46e9SPaul Traina (void)printf("sackOK"); 2634edb46e9SPaul Traina break; 2644edb46e9SPaul Traina 2654edb46e9SPaul Traina case TCPOPT_SACK: 2664edb46e9SPaul Traina (void)printf("sack"); 2674edb46e9SPaul Traina datalen = len - 2; 2684de76e31SBill Fenner for (i = 0; i < datalen; i += 4) { 2694de76e31SBill Fenner LENCHECK(i + 4); 2704edb46e9SPaul Traina /* block-size@relative-origin */ 2714edb46e9SPaul Traina (void)printf(" %u@%u", 2724de76e31SBill Fenner EXTRACT_16BITS(cp + i + 2), 2734de76e31SBill Fenner EXTRACT_16BITS(cp + i)); 2744edb46e9SPaul Traina } 2754edb46e9SPaul Traina if (datalen % 4) 2764edb46e9SPaul Traina (void)printf("[len %d]", len); 2774edb46e9SPaul Traina break; 2784edb46e9SPaul Traina 2794edb46e9SPaul Traina case TCPOPT_ECHO: 2804edb46e9SPaul Traina (void)printf("echo"); 2814edb46e9SPaul Traina datalen = 4; 2824de76e31SBill Fenner LENCHECK(datalen); 2834edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 2844edb46e9SPaul Traina break; 2854edb46e9SPaul Traina 2864edb46e9SPaul Traina case TCPOPT_ECHOREPLY: 2874edb46e9SPaul Traina (void)printf("echoreply"); 2884edb46e9SPaul Traina datalen = 4; 2894de76e31SBill Fenner LENCHECK(datalen); 2904edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 2914edb46e9SPaul Traina break; 2924edb46e9SPaul Traina 2934edb46e9SPaul Traina case TCPOPT_TIMESTAMP: 2944edb46e9SPaul Traina (void)printf("timestamp"); 2954de76e31SBill Fenner datalen = 8; 2964de76e31SBill Fenner LENCHECK(4); 2974edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 2984de76e31SBill Fenner LENCHECK(datalen); 2994edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 3004edb46e9SPaul Traina break; 3014edb46e9SPaul Traina 3024edb46e9SPaul Traina case TCPOPT_CC: 3034edb46e9SPaul Traina (void)printf("cc"); 3044edb46e9SPaul Traina datalen = 4; 3054de76e31SBill Fenner LENCHECK(datalen); 3064edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 3074edb46e9SPaul Traina break; 3084edb46e9SPaul Traina 3094edb46e9SPaul Traina case TCPOPT_CCNEW: 3104edb46e9SPaul Traina (void)printf("ccnew"); 3114edb46e9SPaul Traina datalen = 4; 3124de76e31SBill Fenner LENCHECK(datalen); 3134edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 3144edb46e9SPaul Traina break; 3154edb46e9SPaul Traina 3164edb46e9SPaul Traina case TCPOPT_CCECHO: 3174edb46e9SPaul Traina (void)printf("ccecho"); 3184edb46e9SPaul Traina datalen = 4; 3194de76e31SBill Fenner LENCHECK(datalen); 3204edb46e9SPaul Traina (void)printf(" %u", EXTRACT_32BITS(cp)); 3214edb46e9SPaul Traina break; 3224edb46e9SPaul Traina 3234edb46e9SPaul Traina default: 3244edb46e9SPaul Traina (void)printf("opt-%d:", opt); 3254edb46e9SPaul Traina datalen = len - 2; 3264edb46e9SPaul Traina for (i = 0; i < datalen; ++i) { 3274de76e31SBill Fenner LENCHECK(i); 3284edb46e9SPaul Traina (void)printf("%02x", cp[i]); 3294edb46e9SPaul Traina } 3304edb46e9SPaul Traina break; 3314edb46e9SPaul Traina } 3324edb46e9SPaul Traina 3334edb46e9SPaul Traina /* Account for data printed */ 3344edb46e9SPaul Traina cp += datalen; 3354edb46e9SPaul Traina hlen -= datalen; 3364edb46e9SPaul Traina 3374edb46e9SPaul Traina /* Check specification against observed length */ 3384edb46e9SPaul Traina ++datalen; /* option octet */ 3394edb46e9SPaul Traina if (!ZEROLENOPT(opt)) 3404edb46e9SPaul Traina ++datalen; /* size octet */ 3414edb46e9SPaul Traina if (datalen != len) 3424edb46e9SPaul Traina (void)printf("[len %d]", len); 3434edb46e9SPaul Traina ch = ','; 3444de76e31SBill Fenner if (opt == TCPOPT_EOL) 3454de76e31SBill Fenner break; 3464edb46e9SPaul Traina } 3474edb46e9SPaul Traina putchar('>'); 3484edb46e9SPaul Traina } 3494edb46e9SPaul Traina return; 3504de76e31SBill Fenner bad: 3514de76e31SBill Fenner fputs("[bad opt]", stdout); 3524de76e31SBill Fenner if (ch != '\0') 3534de76e31SBill Fenner putchar('>'); 3544de76e31SBill Fenner return; 3554edb46e9SPaul Traina trunc: 3564edb46e9SPaul Traina fputs("[|tcp]", stdout); 3574edb46e9SPaul Traina if (ch != '\0') 3584edb46e9SPaul Traina putchar('>'); 3594edb46e9SPaul Traina } 3604edb46e9SPaul Traina 361