tcpdump.c revision 44165
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 3017680Spst/* 3117680Spst * tcpdump - monitor tcp/ip traffic on an ethernet. 3217680Spst * 3317680Spst * First written in 1987 by Van Jacobson, Lawrence Berkeley Laboratory. 3417680Spst * Mercilessly hacked and occasionally improved since then via the 3517680Spst * combined efforts of Van, Steve McCanne and Craig Leres of LBL. 3617680Spst */ 3717680Spst 3817680Spst#include <sys/types.h> 3917680Spst#include <sys/time.h> 4017680Spst 4117680Spst#include <netinet/in.h> 4217680Spst 4317680Spst#include <pcap.h> 4417680Spst#include <signal.h> 4517680Spst#include <stdio.h> 4617680Spst#include <stdlib.h> 4717680Spst#include <string.h> 4817680Spst#include <unistd.h> 4917680Spst 5017680Spst#include "interface.h" 5117680Spst#include "addrtoname.h" 5217680Spst#include "machdep.h" 5339297Sfenner#include "setsignal.h" 5439297Sfenner#include "gmt2local.h" 5517680Spst 5639297Sfennerint aflag; /* translate network and broadcast addresses */ 5739297Sfennerint dflag; /* print filter code */ 5839297Sfennerint eflag; /* print ethernet header */ 5917680Spstint fflag; /* don't translate "foreign" IP address */ 6017680Spstint nflag; /* leave addresses as numbers */ 6117680Spstint Nflag; /* remove domains from printed host names */ 6239297Sfennerint Oflag = 1; /* run filter code optimizer */ 6317680Spstint pflag; /* don't go promiscuous */ 6417680Spstint qflag; /* quick (shorter) output */ 6539297Sfennerint Sflag; /* print raw TCP sequence numbers */ 6617680Spstint tflag = 1; /* print packet arrival time */ 6717680Spstint vflag; /* verbose */ 6817680Spstint xflag; /* print packet in hex */ 6939297Sfenner 7017680Spstint packettype; 7117680Spst 7217680Spst 7317680Spstchar *program_name; 7417680Spst 7517680Spstint32_t thiszone; /* seconds offset from gmt to local time */ 7617680Spst 7717680Spst/* Externs */ 7817680Spstextern void bpf_dump(struct bpf_program *, int); 7917680Spst 8017680Spst/* Forwards */ 8117680SpstRETSIGTYPE cleanup(int); 8217680Spstextern __dead void usage(void) __attribute__((volatile)); 8317680Spst 8417680Spst/* Length of saved portion of packet. */ 8517680Spstint snaplen = DEFAULT_SNAPLEN; 8617680Spst 8717680Spststruct printer { 8817680Spst pcap_handler f; 8917680Spst int type; 9017680Spst}; 9117680Spst 9217680Spststatic struct printer printers[] = { 9317680Spst { ether_if_print, DLT_EN10MB }, 9444165Sjulian { token_if_print, DLT_IEEE802 }, 9517680Spst { sl_if_print, DLT_SLIP }, 9639297Sfenner { sl_bsdos_if_print, DLT_SLIP_BSDOS }, 9717680Spst { ppp_if_print, DLT_PPP }, 9839297Sfenner { ppp_bsdos_if_print, DLT_PPP_BSDOS }, 9917680Spst { fddi_if_print, DLT_FDDI }, 10017680Spst { null_if_print, DLT_NULL }, 10139297Sfenner { raw_if_print, DLT_RAW }, 10217680Spst { atm_if_print, DLT_ATM_RFC1483 }, 10317680Spst { NULL, 0 }, 10417680Spst}; 10517680Spst 10617680Spststatic pcap_handler 10717680Spstlookup_printer(int type) 10817680Spst{ 10917680Spst struct printer *p; 11017680Spst 11117680Spst for (p = printers; p->f; ++p) 11217680Spst if (type == p->type) 11317680Spst return p->f; 11417680Spst 11517680Spst error("unknown data link type 0x%x", type); 11617680Spst /* NOTREACHED */ 11717680Spst} 11817680Spst 11917680Spststatic pcap_t *pd; 12017680Spst 12117680Spstextern int optind; 12217680Spstextern int opterr; 12317680Spstextern char *optarg; 12417680Spst 12517680Spstint 12617680Spstmain(int argc, char **argv) 12717680Spst{ 12817680Spst register int cnt, op, i; 12917680Spst bpf_u_int32 localnet, netmask; 13017680Spst register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; 13117680Spst pcap_handler printer; 13217680Spst struct bpf_program fcode; 13339297Sfenner RETSIGTYPE (*oldhandler)(int); 13417680Spst u_char *pcap_userdata; 13517680Spst char ebuf[PCAP_ERRBUF_SIZE]; 13617680Spst 13717680Spst cnt = -1; 13817680Spst device = NULL; 13917680Spst infile = NULL; 14017680Spst RFileName = NULL; 14117680Spst WFileName = NULL; 14217680Spst if ((cp = strrchr(argv[0], '/')) != NULL) 14317680Spst program_name = cp + 1; 14417680Spst else 14517680Spst program_name = argv[0]; 14617680Spst 14717680Spst if (abort_on_misalignment(ebuf) < 0) 14826180Sfenner error("%s", ebuf); 14917680Spst 15017680Spst opterr = 0; 15139297Sfenner while ( 15239297Sfenner (op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xY")) != EOF) 15317680Spst switch (op) { 15439297Sfenner 15539297Sfenner case 'a': 15639297Sfenner ++aflag; 15739297Sfenner break; 15839297Sfenner 15917680Spst case 'c': 16017680Spst cnt = atoi(optarg); 16117680Spst if (cnt <= 0) 16217680Spst error("invalid packet count %s", optarg); 16317680Spst break; 16417680Spst 16517680Spst case 'd': 16617680Spst ++dflag; 16717680Spst break; 16817680Spst 16917680Spst case 'e': 17017680Spst ++eflag; 17117680Spst break; 17217680Spst 17317680Spst case 'f': 17417680Spst ++fflag; 17517680Spst break; 17617680Spst 17717680Spst case 'F': 17817680Spst infile = optarg; 17917680Spst break; 18017680Spst 18117680Spst case 'i': 18217680Spst device = optarg; 18317680Spst break; 18417680Spst 18517680Spst case 'l': 18617680Spst#ifdef HAVE_SETLINEBUF 18717680Spst setlinebuf(stdout); 18817680Spst#else 18917680Spst setvbuf(stdout, NULL, _IOLBF, 0); 19017680Spst#endif 19117680Spst break; 19217680Spst 19317680Spst case 'n': 19417680Spst ++nflag; 19517680Spst break; 19617680Spst 19717680Spst case 'N': 19817680Spst ++Nflag; 19917680Spst break; 20017680Spst 20117680Spst case 'O': 20217680Spst Oflag = 0; 20317680Spst break; 20417680Spst 20517680Spst case 'p': 20617680Spst ++pflag; 20717680Spst break; 20817680Spst 20917680Spst case 'q': 21017680Spst ++qflag; 21117680Spst break; 21217680Spst 21317680Spst case 'r': 21417680Spst RFileName = optarg; 21517680Spst break; 21617680Spst 21717680Spst case 's': 21817680Spst snaplen = atoi(optarg); 21917680Spst if (snaplen <= 0) 22017680Spst error("invalid snaplen %s", optarg); 22117680Spst break; 22217680Spst 22317680Spst case 'S': 22417680Spst ++Sflag; 22517680Spst break; 22617680Spst 22717680Spst case 't': 22817680Spst --tflag; 22917680Spst break; 23017680Spst 23117680Spst case 'T': 23217680Spst if (strcasecmp(optarg, "vat") == 0) 23317680Spst packettype = PT_VAT; 23417680Spst else if (strcasecmp(optarg, "wb") == 0) 23517680Spst packettype = PT_WB; 23617680Spst else if (strcasecmp(optarg, "rpc") == 0) 23717680Spst packettype = PT_RPC; 23817680Spst else if (strcasecmp(optarg, "rtp") == 0) 23917680Spst packettype = PT_RTP; 24017680Spst else if (strcasecmp(optarg, "rtcp") == 0) 24117680Spst packettype = PT_RTCP; 24217680Spst else 24317680Spst error("unknown packet type `%s'", optarg); 24417680Spst break; 24517680Spst 24617680Spst case 'v': 24717680Spst ++vflag; 24817680Spst break; 24917680Spst 25017680Spst case 'w': 25117680Spst WFileName = optarg; 25217680Spst break; 25317680Spst#ifdef YYDEBUG 25417680Spst case 'Y': 25517680Spst { 25617680Spst /* Undocumented flag */ 25717680Spst extern int yydebug; 25817680Spst yydebug = 1; 25917680Spst } 26017680Spst break; 26117680Spst#endif 26217680Spst case 'x': 26317680Spst ++xflag; 26417680Spst break; 26517680Spst 26617680Spst default: 26717680Spst usage(); 26817680Spst /* NOTREACHED */ 26917680Spst } 27017680Spst 27139297Sfenner if (aflag && nflag) 27239297Sfenner error("-a and -n options are incompatible"); 27339297Sfenner 27417680Spst if (tflag > 0) 27539297Sfenner thiszone = gmt2local(0); 27617680Spst 27717680Spst if (RFileName != NULL) { 27817680Spst /* 27917680Spst * We don't need network access, so set it back to the user id. 28017680Spst * Also, this prevents the user from reading anyone's 28117680Spst * trace file. 28217680Spst */ 28317680Spst setuid(getuid()); 28417680Spst 28517680Spst pd = pcap_open_offline(RFileName, ebuf); 28617680Spst if (pd == NULL) 28726180Sfenner error("%s", ebuf); 28817680Spst localnet = 0; 28917680Spst netmask = 0; 29017680Spst if (fflag != 0) 29117680Spst error("-f and -r options are incompatible"); 29217680Spst } else { 29317680Spst if (device == NULL) { 29417680Spst device = pcap_lookupdev(ebuf); 29517680Spst if (device == NULL) 29626180Sfenner error("%s", ebuf); 29717680Spst } 29817680Spst pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); 29917680Spst if (pd == NULL) 30026180Sfenner error("%s", ebuf); 30117680Spst i = pcap_snapshot(pd); 30217680Spst if (snaplen < i) { 30317680Spst warning("snaplen raised from %d to %d", snaplen, i); 30417680Spst snaplen = i; 30517680Spst } 30639297Sfenner if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { 30739297Sfenner localnet = 0; 30839297Sfenner netmask = 0; 30939297Sfenner warning("%s", ebuf); 31039297Sfenner } 31117680Spst /* 31217680Spst * Let user own process after socket has been opened. 31317680Spst */ 31417680Spst setuid(getuid()); 31517680Spst } 31617680Spst if (infile) 31717680Spst cmdbuf = read_infile(infile); 31817680Spst else 31917680Spst cmdbuf = copy_argv(&argv[optind]); 32017680Spst 32117680Spst if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) 32226180Sfenner error("%s", pcap_geterr(pd)); 32317680Spst if (dflag) { 32417680Spst bpf_dump(&fcode, dflag); 32517680Spst exit(0); 32617680Spst } 32739297Sfenner init_addrtoname(localnet, netmask); 32817680Spst 32939297Sfenner (void)setsignal(SIGTERM, cleanup); 33039297Sfenner (void)setsignal(SIGINT, cleanup); 33139297Sfenner /* Cooperate with nohup(1) */ 33239297Sfenner if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) 33339297Sfenner (void)setsignal(SIGHUP, oldhandler); 33417680Spst 33517680Spst if (pcap_setfilter(pd, &fcode) < 0) 33626180Sfenner error("%s", pcap_geterr(pd)); 33717680Spst if (WFileName) { 33817680Spst pcap_dumper_t *p = pcap_dump_open(pd, WFileName); 33917680Spst if (p == NULL) 34026180Sfenner error("%s", pcap_geterr(pd)); 34117680Spst printer = pcap_dump; 34217680Spst pcap_userdata = (u_char *)p; 34317680Spst } else { 34417680Spst printer = lookup_printer(pcap_datalink(pd)); 34517680Spst pcap_userdata = 0; 34617680Spst } 34717680Spst if (RFileName == NULL) { 34817680Spst (void)fprintf(stderr, "%s: listening on %s\n", 34917680Spst program_name, device); 35017680Spst (void)fflush(stderr); 35117680Spst } 35217680Spst if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { 35317680Spst (void)fprintf(stderr, "%s: pcap_loop: %s\n", 35417680Spst program_name, pcap_geterr(pd)); 35517680Spst exit(1); 35617680Spst } 35717680Spst pcap_close(pd); 35817680Spst exit(0); 35917680Spst} 36017680Spst 36117680Spst/* make a clean exit on interrupts */ 36217680SpstRETSIGTYPE 36317680Spstcleanup(int signo) 36417680Spst{ 36517680Spst struct pcap_stat stat; 36617680Spst 36717680Spst /* Can't print the summary if reading from a savefile */ 36817680Spst if (pd != NULL && pcap_file(pd) == NULL) { 36917680Spst (void)fflush(stdout); 37017680Spst putc('\n', stderr); 37117680Spst if (pcap_stats(pd, &stat) < 0) 37217680Spst (void)fprintf(stderr, "pcap_stats: %s\n", 37317680Spst pcap_geterr(pd)); 37417680Spst else { 37517680Spst (void)fprintf(stderr, "%d packets received by filter\n", 37617680Spst stat.ps_recv); 37717680Spst (void)fprintf(stderr, "%d packets dropped by kernel\n", 37817680Spst stat.ps_drop); 37917680Spst } 38017680Spst } 38117680Spst exit(0); 38217680Spst} 38317680Spst 38417680Spst/* Like default_print() but data need not be aligned */ 38517680Spstvoid 38617680Spstdefault_print_unaligned(register const u_char *cp, register u_int length) 38717680Spst{ 38817680Spst register u_int i, s; 38917680Spst register int nshorts; 39017680Spst 39117680Spst nshorts = (u_int) length / sizeof(u_short); 39217680Spst i = 0; 39317680Spst while (--nshorts >= 0) { 39417680Spst if ((i++ % 8) == 0) 39517680Spst (void)printf("\n\t\t\t"); 39617680Spst s = *cp++; 39717680Spst (void)printf(" %02x%02x", s, *cp++); 39817680Spst } 39917680Spst if (length & 1) { 40017680Spst if ((i % 8) == 0) 40117680Spst (void)printf("\n\t\t\t"); 40217680Spst (void)printf(" %02x", *cp); 40317680Spst } 40417680Spst} 40517680Spst 40639297Sfenner/* 40739297Sfenner * By default, print the packet out in hex. 40839297Sfenner * 40939297Sfenner * (BTW, please don't send us patches to print the packet out in ascii) 41039297Sfenner */ 41117680Spstvoid 41217680Spstdefault_print(register const u_char *bp, register u_int length) 41317680Spst{ 41417680Spst register const u_short *sp; 41517680Spst register u_int i; 41617680Spst register int nshorts; 41717680Spst 41817680Spst if ((long)bp & 1) { 41917680Spst default_print_unaligned(bp, length); 42017680Spst return; 42117680Spst } 42217680Spst sp = (u_short *)bp; 42317680Spst nshorts = (u_int) length / sizeof(u_short); 42417680Spst i = 0; 42517680Spst while (--nshorts >= 0) { 42617680Spst if ((i++ % 8) == 0) 42717680Spst (void)printf("\n\t\t\t"); 42817680Spst (void)printf(" %04x", ntohs(*sp++)); 42917680Spst } 43017680Spst if (length & 1) { 43117680Spst if ((i % 8) == 0) 43217680Spst (void)printf("\n\t\t\t"); 43317680Spst (void)printf(" %02x", *(u_char *)sp); 43417680Spst } 43517680Spst} 43617680Spst 43717680Spst__dead void 43826180Sfennerusage(void) 43917680Spst{ 44017680Spst extern char version[]; 44139297Sfenner extern char pcap_version[]; 44217680Spst 44339297Sfenner (void)fprintf(stderr, "%s version %s\n", program_name, version); 44439297Sfenner (void)fprintf(stderr, "libpcap version %s\n", pcap_version); 44517680Spst (void)fprintf(stderr, 44639297Sfenner"Usage: %s [-adeflnNOpqStvx] [-c count] [ -F file ]\n", program_name); 44717680Spst (void)fprintf(stderr, 44817680Spst"\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n"); 44917680Spst (void)fprintf(stderr, 45017680Spst"\t\t[ -T type ] [ -w file ] [ expression ]\n"); 45117680Spst exit(-1); 45217680Spst} 453