tcpdump.c revision 56648
117680Spst/* 239297Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017680Spst */ 2117680Spst 2217680Spst#ifndef lint 2326180Sfennerstatic const char copyright[] = 2439297Sfenner "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997\n\ 2517680SpstThe Regents of the University of California. All rights reserved.\n"; 2626180Sfennerstatic const char rcsid[] = 2739297Sfenner "@(#) $Header: tcpdump.c,v 1.129 97/06/13 13:10:11 leres Exp $ (LBL)"; 2817680Spst#endif 2917680Spst 3056648Sarchie/* $FreeBSD: head/contrib/tcpdump/tcpdump.c 56648 2000-01-26 18:10:21Z archie $ */ 3156648Sarchie 3217680Spst/* 3317680Spst * tcpdump - monitor tcp/ip traffic on an ethernet. 3417680Spst * 3517680Spst * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory. 3617680Spst * Mercilessly hacked and occasionally improved since then via the 3717680Spst * combined efforts of Van, Steve McCanne and Craig Leres of LBL. 3817680Spst */ 3917680Spst 4017680Spst#include <sys/types.h> 4117680Spst#include <sys/time.h> 4217680Spst 4317680Spst#include <netinet/in.h> 4417680Spst 4517680Spst#include <pcap.h> 4617680Spst#include <signal.h> 4717680Spst#include <stdio.h> 4817680Spst#include <stdlib.h> 4917680Spst#include <string.h> 5017680Spst#include <unistd.h> 5117680Spst 5217680Spst#include "interface.h" 5317680Spst#include "addrtoname.h" 5417680Spst#include "machdep.h" 5539297Sfenner#include "setsignal.h" 5639297Sfenner#include "gmt2local.h" 5717680Spst 5839297Sfennerint aflag; /* translate network and broadcast addresses */ 5939297Sfennerint dflag; /* print filter code */ 6039297Sfennerint eflag; /* print ethernet header */ 6117680Spstint fflag; /* don't translate "foreign" IP address */ 6217680Spstint nflag; /* leave addresses as numbers */ 6317680Spstint Nflag; /* remove domains from printed host names */ 6439297Sfennerint Oflag = 1; /* run filter code optimizer */ 6517680Spstint pflag; /* don't go promiscuous */ 6617680Spstint qflag; /* quick (shorter) output */ 6739297Sfennerint Sflag; /* print raw TCP sequence numbers */ 6817680Spstint tflag = 1; /* print packet arrival time */ 6917680Spstint vflag; /* verbose */ 7017680Spstint xflag; /* print packet in hex */ 7156648Sarchieint Xflag; /* print packet in emacs-hexl style */ 7239297Sfenner 7317680Spstint packettype; 7417680Spst 7517680Spst 7617680Spstchar *program_name; 7717680Spst 7817680Spstint32_t thiszone; /* seconds offset from gmt to local time */ 7917680Spst 8017680Spst/* Externs */ 8117680Spstextern void bpf_dump(struct bpf_program *, int); 8217680Spst 8317680Spst/* Forwards */ 8417680SpstRETSIGTYPE cleanup(int); 8517680Spstextern __dead void usage(void) __attribute__((volatile)); 8617680Spst 8717680Spst/* Length of saved portion of packet. */ 8817680Spstint snaplen = DEFAULT_SNAPLEN; 8917680Spst 9017680Spststruct printer { 9117680Spst pcap_handler f; 9217680Spst int type; 9317680Spst}; 9417680Spst 9517680Spststatic struct printer printers[] = { 9617680Spst { ether_if_print, DLT_EN10MB }, 9744165Sjulian { token_if_print, DLT_IEEE802 }, 9817680Spst { sl_if_print, DLT_SLIP }, 9939297Sfenner { sl_bsdos_if_print, DLT_SLIP_BSDOS }, 10017680Spst { ppp_if_print, DLT_PPP }, 10139297Sfenner { ppp_bsdos_if_print, DLT_PPP_BSDOS }, 10217680Spst { fddi_if_print, DLT_FDDI }, 10317680Spst { null_if_print, DLT_NULL }, 10439297Sfenner { raw_if_print, DLT_RAW }, 10517680Spst { atm_if_print, DLT_ATM_RFC1483 }, 10617680Spst { NULL, 0 }, 10717680Spst}; 10817680Spst 10917680Spststatic pcap_handler 11017680Spstlookup_printer(int type) 11117680Spst{ 11217680Spst struct printer *p; 11317680Spst 11417680Spst for (p = printers; p->f; ++p) 11517680Spst if (type == p->type) 11617680Spst return p->f; 11717680Spst 11817680Spst error("unknown data link type 0x%x", type); 11917680Spst /* NOTREACHED */ 12017680Spst} 12117680Spst 12217680Spststatic pcap_t *pd; 12317680Spst 12417680Spstextern int optind; 12517680Spstextern int opterr; 12617680Spstextern char *optarg; 12717680Spst 12817680Spstint 12917680Spstmain(int argc, char **argv) 13017680Spst{ 13117680Spst register int cnt, op, i; 13217680Spst bpf_u_int32 localnet, netmask; 13317680Spst register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; 13417680Spst pcap_handler printer; 13517680Spst struct bpf_program fcode; 13639297Sfenner RETSIGTYPE (*oldhandler)(int); 13717680Spst u_char *pcap_userdata; 13817680Spst char ebuf[PCAP_ERRBUF_SIZE]; 13917680Spst 14017680Spst cnt = -1; 14117680Spst device = NULL; 14217680Spst infile = NULL; 14317680Spst RFileName = NULL; 14417680Spst WFileName = NULL; 14517680Spst if ((cp = strrchr(argv[0], '/')) != NULL) 14617680Spst program_name = cp + 1; 14717680Spst else 14817680Spst program_name = argv[0]; 14917680Spst 15017680Spst if (abort_on_misalignment(ebuf) < 0) 15126180Sfenner error("%s", ebuf); 15217680Spst 15317680Spst opterr = 0; 15439297Sfenner while ( 15556648Sarchie (op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xXY")) != EOF) 15617680Spst switch (op) { 15739297Sfenner 15839297Sfenner case 'a': 15939297Sfenner ++aflag; 16039297Sfenner break; 16139297Sfenner 16217680Spst case 'c': 16317680Spst cnt = atoi(optarg); 16417680Spst if (cnt <= 0) 16517680Spst error("invalid packet count %s", optarg); 16617680Spst break; 16717680Spst 16817680Spst case 'd': 16917680Spst ++dflag; 17017680Spst break; 17117680Spst 17217680Spst case 'e': 17317680Spst ++eflag; 17417680Spst break; 17517680Spst 17617680Spst case 'f': 17717680Spst ++fflag; 17817680Spst break; 17917680Spst 18017680Spst case 'F': 18117680Spst infile = optarg; 18217680Spst break; 18317680Spst 18417680Spst case 'i': 18517680Spst device = optarg; 18617680Spst break; 18717680Spst 18817680Spst case 'l': 18917680Spst#ifdef HAVE_SETLINEBUF 19017680Spst setlinebuf(stdout); 19117680Spst#else 19217680Spst setvbuf(stdout, NULL, _IOLBF, 0); 19317680Spst#endif 19417680Spst break; 19517680Spst 19617680Spst case 'n': 19717680Spst ++nflag; 19817680Spst break; 19917680Spst 20017680Spst case 'N': 20117680Spst ++Nflag; 20217680Spst break; 20317680Spst 20417680Spst case 'O': 20517680Spst Oflag = 0; 20617680Spst break; 20717680Spst 20817680Spst case 'p': 20917680Spst ++pflag; 21017680Spst break; 21117680Spst 21217680Spst case 'q': 21317680Spst ++qflag; 21417680Spst break; 21517680Spst 21617680Spst case 'r': 21717680Spst RFileName = optarg; 21817680Spst break; 21917680Spst 22017680Spst case 's': 22117680Spst snaplen = atoi(optarg); 22217680Spst if (snaplen <= 0) 22317680Spst error("invalid snaplen %s", optarg); 22417680Spst break; 22517680Spst 22617680Spst case 'S': 22717680Spst ++Sflag; 22817680Spst break; 22917680Spst 23017680Spst case 't': 23117680Spst --tflag; 23217680Spst break; 23317680Spst 23417680Spst case 'T': 23517680Spst if (strcasecmp(optarg, "vat") == 0) 23617680Spst packettype = PT_VAT; 23717680Spst else if (strcasecmp(optarg, "wb") == 0) 23817680Spst packettype = PT_WB; 23917680Spst else if (strcasecmp(optarg, "rpc") == 0) 24017680Spst packettype = PT_RPC; 24117680Spst else if (strcasecmp(optarg, "rtp") == 0) 24217680Spst packettype = PT_RTP; 24317680Spst else if (strcasecmp(optarg, "rtcp") == 0) 24417680Spst packettype = PT_RTCP; 24517680Spst else 24617680Spst error("unknown packet type `%s'", optarg); 24717680Spst break; 24817680Spst 24917680Spst case 'v': 25017680Spst ++vflag; 25117680Spst break; 25217680Spst 25317680Spst case 'w': 25417680Spst WFileName = optarg; 25517680Spst break; 25617680Spst#ifdef YYDEBUG 25717680Spst case 'Y': 25817680Spst { 25917680Spst /* Undocumented flag */ 26017680Spst extern int yydebug; 26117680Spst yydebug = 1; 26217680Spst } 26317680Spst break; 26417680Spst#endif 26517680Spst case 'x': 26617680Spst ++xflag; 26717680Spst break; 26817680Spst 26956648Sarchie case 'X': 27056648Sarchie ++Xflag; 27156648Sarchie if (xflag == 0) ++xflag; 27256648Sarchie break; 27356648Sarchie 27417680Spst default: 27517680Spst usage(); 27617680Spst /* NOTREACHED */ 27717680Spst } 27817680Spst 27939297Sfenner if (aflag && nflag) 28039297Sfenner error("-a and -n options are incompatible"); 28139297Sfenner 28217680Spst if (tflag > 0) 28339297Sfenner thiszone = gmt2local(0); 28417680Spst 28517680Spst if (RFileName != NULL) { 28617680Spst /* 28717680Spst * We don't need network access, so set it back to the user id. 28817680Spst * Also, this prevents the user from reading anyone's 28917680Spst * trace file. 29017680Spst */ 29117680Spst setuid(getuid()); 29217680Spst 29317680Spst pd = pcap_open_offline(RFileName, ebuf); 29417680Spst if (pd == NULL) 29526180Sfenner error("%s", ebuf); 29617680Spst localnet = 0; 29717680Spst netmask = 0; 29817680Spst if (fflag != 0) 29917680Spst error("-f and -r options are incompatible"); 30017680Spst } else { 30117680Spst if (device == NULL) { 30217680Spst device = pcap_lookupdev(ebuf); 30317680Spst if (device == NULL) 30426180Sfenner error("%s", ebuf); 30517680Spst } 30617680Spst pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); 30717680Spst if (pd == NULL) 30826180Sfenner error("%s", ebuf); 30917680Spst i = pcap_snapshot(pd); 31017680Spst if (snaplen < i) { 31117680Spst warning("snaplen raised from %d to %d", snaplen, i); 31217680Spst snaplen = i; 31317680Spst } 31439297Sfenner if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { 31539297Sfenner localnet = 0; 31639297Sfenner netmask = 0; 31739297Sfenner warning("%s", ebuf); 31839297Sfenner } 31917680Spst /* 32017680Spst * Let user own process after socket has been opened. 32117680Spst */ 32217680Spst setuid(getuid()); 32317680Spst } 32417680Spst if (infile) 32517680Spst cmdbuf = read_infile(infile); 32617680Spst else 32717680Spst cmdbuf = copy_argv(&argv[optind]); 32817680Spst 32917680Spst if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 33026180Sfenner error("%s", pcap_geterr(pd)); 33117680Spst if (dflag) { 33217680Spst bpf_dump(&fcode, dflag); 33317680Spst exit(0); 33417680Spst } 33539297Sfenner init_addrtoname(localnet, netmask); 33617680Spst 33739297Sfenner (void)setsignal(SIGTERM, cleanup); 33839297Sfenner (void)setsignal(SIGINT, cleanup); 33939297Sfenner /* Cooperate with nohup(1) */ 34039297Sfenner if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) 34139297Sfenner (void)setsignal(SIGHUP, oldhandler); 34217680Spst 34317680Spst if (pcap_setfilter(pd, &fcode) < 0) 34426180Sfenner error("%s", pcap_geterr(pd)); 34517680Spst if (WFileName) { 34617680Spst pcap_dumper_t *p = pcap_dump_open(pd, WFileName); 34717680Spst if (p == NULL) 34826180Sfenner error("%s", pcap_geterr(pd)); 34917680Spst printer = pcap_dump; 35017680Spst pcap_userdata = (u_char *)p; 35117680Spst } else { 35217680Spst printer = lookup_printer(pcap_datalink(pd)); 35317680Spst pcap_userdata = 0; 35417680Spst } 35517680Spst if (RFileName == NULL) { 35617680Spst (void)fprintf(stderr, "%s: listening on %s\n", 35717680Spst program_name, device); 35817680Spst (void)fflush(stderr); 35917680Spst } 36017680Spst if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { 36117680Spst (void)fprintf(stderr, "%s: pcap_loop: %s\n", 36217680Spst program_name, pcap_geterr(pd)); 36317680Spst exit(1); 36417680Spst } 36517680Spst pcap_close(pd); 36617680Spst exit(0); 36717680Spst} 36817680Spst 36917680Spst/* make a clean exit on interrupts */ 37017680SpstRETSIGTYPE 37117680Spstcleanup(int signo) 37217680Spst{ 37317680Spst struct pcap_stat stat; 37417680Spst 37517680Spst /* Can't print the summary if reading from a savefile */ 37617680Spst if (pd != NULL && pcap_file(pd) == NULL) { 37717680Spst (void)fflush(stdout); 37817680Spst putc('\n', stderr); 37917680Spst if (pcap_stats(pd, &stat) < 0) 38017680Spst (void)fprintf(stderr, "pcap_stats: %s\n", 38117680Spst pcap_geterr(pd)); 38217680Spst else { 38317680Spst (void)fprintf(stderr, "%d packets received by filter\n", 38417680Spst stat.ps_recv); 38517680Spst (void)fprintf(stderr, "%d packets dropped by kernel\n", 38617680Spst stat.ps_drop); 38717680Spst } 38817680Spst } 38917680Spst exit(0); 39017680Spst} 39117680Spst 39256648Sarchie/* dump the buffer in `emacs-hexl' style */ 39356648Sarchievoid 39456648Sarchiedefault_print_hexl(const u_char *cp, unsigned int length, unsigned int offset) 39556648Sarchie{ 39656648Sarchie unsigned int i, j, jm; 39756648Sarchie int c; 39856648Sarchie char ln[128]; 39956648Sarchie 40056648Sarchie printf("\n"); 40156648Sarchie for (i = 0; i < length; i += 0x10) { 40256648Sarchie snprintf(ln, 40356648Sarchie sizeof(ln), 40456648Sarchie " %04x: ", (unsigned int)(i + offset)); 40556648Sarchie jm = length - i; 40656648Sarchie jm = jm > 16 ? 16 : jm; 40756648Sarchie 40856648Sarchie for (j = 0; j < jm; j++) { 40956648Sarchie if ((j % 2) == 1) 41056648Sarchie snprintf(ln + strlen(ln), 41156648Sarchie sizeof(ln) - strlen(ln), 41256648Sarchie "%02x ", (unsigned int)cp[i+j]); 41356648Sarchie else 41456648Sarchie snprintf(ln + strlen(ln), 41556648Sarchie sizeof(ln) - strlen(ln), 41656648Sarchie "%02x", (unsigned int)cp[i+j]); 41756648Sarchie } 41856648Sarchie for (; j < 16; j++) { 41956648Sarchie if ((j % 2) == 1) 42056648Sarchie snprintf(ln + strlen(ln), 42156648Sarchie sizeof(ln) - strlen(ln), 42256648Sarchie " "); 42356648Sarchie else 42456648Sarchie snprintf(ln + strlen(ln), 42556648Sarchie sizeof(ln) - strlen(ln), 42656648Sarchie " "); 42756648Sarchie } 42856648Sarchie 42956648Sarchie snprintf(ln + strlen(ln), sizeof(ln) - strlen(ln), " "); 43056648Sarchie for (j = 0; j < jm; j++) { 43156648Sarchie c = cp[i+j]; 43256648Sarchie c = isprint(c) ? c : '.'; 43356648Sarchie snprintf(ln + strlen(ln), 43456648Sarchie sizeof(ln) - strlen(ln), 43556648Sarchie "%c", c); 43656648Sarchie } 43756648Sarchie printf("%s\n", ln); 43856648Sarchie } 43956648Sarchie} 44056648Sarchie 44117680Spst/* Like default_print() but data need not be aligned */ 44217680Spstvoid 44317680Spstdefault_print_unaligned(register const u_char *cp, register u_int length) 44417680Spst{ 44517680Spst register u_int i, s; 44617680Spst register int nshorts; 44717680Spst 44856648Sarchie if (Xflag) { 44956648Sarchie /* dump the buffer in `emacs-hexl' style */ 45056648Sarchie default_print_hexl(cp, length, 0); 45156648Sarchie } else { 45256648Sarchie /* dump the buffer in old tcpdump style */ 45356648Sarchie nshorts = (u_int) length / sizeof(u_short); 45456648Sarchie i = 0; 45556648Sarchie while (--nshorts >= 0) { 45656648Sarchie if ((i++ % 8) == 0) 45756648Sarchie (void)printf("\n\t\t\t"); 45856648Sarchie s = *cp++; 45956648Sarchie (void)printf(" %02x%02x", s, *cp++); 46056648Sarchie } 46156648Sarchie if (length & 1) { 46256648Sarchie if ((i % 8) == 0) 46356648Sarchie (void)printf("\n\t\t\t"); 46456648Sarchie (void)printf(" %02x", *cp); 46556648Sarchie } 46617680Spst } 46717680Spst} 46817680Spst 46939297Sfenner/* 47039297Sfenner * By default, print the packet out in hex. 47139297Sfenner * 47239297Sfenner * (BTW, please don't send us patches to print the packet out in ascii) 47339297Sfenner */ 47417680Spstvoid 47517680Spstdefault_print(register const u_char *bp, register u_int length) 47617680Spst{ 47717680Spst register const u_short *sp; 47817680Spst register u_int i; 47917680Spst register int nshorts; 48017680Spst 48156648Sarchie if (Xflag) { 48256648Sarchie /* dump the buffer in `emacs-hexl' style */ 48356648Sarchie default_print_hexl(bp, length, 0); 48456648Sarchie } else { 48556648Sarchie /* dump the buffer in old tcpdump style */ 48656648Sarchie if ((long)bp & 1) { 48756648Sarchie default_print_unaligned(bp, length); 48856648Sarchie return; 48956648Sarchie } 49056648Sarchie sp = (u_short *)bp; 49156648Sarchie nshorts = (u_int) length / sizeof(u_short); 49256648Sarchie i = 0; 49356648Sarchie while (--nshorts >= 0) { 49456648Sarchie if ((i++ % 8) == 0) 49556648Sarchie (void)printf("\n\t\t\t"); 49656648Sarchie (void)printf(" %04x", ntohs(*sp++)); 49756648Sarchie } 49856648Sarchie if (length & 1) { 49956648Sarchie if ((i % 8) == 0) 50056648Sarchie (void)printf("\n\t\t\t"); 50156648Sarchie (void)printf(" %02x", *(u_char *)sp); 50256648Sarchie } 50317680Spst } 50417680Spst} 50517680Spst 50617680Spst__dead void 50726180Sfennerusage(void) 50817680Spst{ 50917680Spst extern char version[]; 51039297Sfenner extern char pcap_version[]; 51117680Spst 51239297Sfenner (void)fprintf(stderr, "%s version %s\n", program_name, version); 51339297Sfenner (void)fprintf(stderr, "libpcap version %s\n", pcap_version); 51417680Spst (void)fprintf(stderr, 51556648Sarchie"Usage: %s [-adeflnNOpqStvxX] [-c count] [ -F file ]\n", program_name); 51617680Spst (void)fprintf(stderr, 51717680Spst"\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n"); 51817680Spst (void)fprintf(stderr, 51917680Spst"\t\t[ -T type ] [ -w file ] [ expression ]\n"); 52017680Spst exit(-1); 52117680Spst} 522