int main(int argc, char **argv) { register char *cp; register int op, pid, snaplen, timeout, linktype, status; #ifdef TIOCNOTTY register int fd; #endif register pcap_t *pd; register char *interface, *rfilename; struct bpf_program code; char errbuf[PCAP_ERRBUF_SIZE]; if (argv[0] == NULL) prog = "arpwatch"; else if ((cp = strrchr(argv[0], '/')) != NULL) prog = cp + 1; else prog = argv[0]; if (abort_on_misalignment(errbuf) < 0) { (void)fprintf(stderr, "%s: %s\n", prog, errbuf); exit(1); } opterr = 0; interface = NULL; rfilename = NULL; pd = NULL; while ((op = getopt(argc, argv, "df:i:n:Nr:")) != EOF) switch (op) { case 'd': ++debug; #ifndef DEBUG (void)fprintf(stderr, "%s: Warning: Not compiled with -DDEBUG\n", prog); #endif break; case 'f': arpfile = optarg; break; case 'i': interface = optarg; break; case 'n': if (!addnet(optarg)) usage(); break; case 'N': ++nobogons; break; case 'r': rfilename = optarg; break; default: usage(); } if (optind != argc) usage(); if (rfilename != NULL) { net = 0; netmask = 0; } else { /* Determine interface if not specified */ if (interface == NULL && (interface = pcap_lookupdev(errbuf)) == NULL) { (void)fprintf(stderr, "%s: lookup_device: %s\n", prog, errbuf); exit(1); } /* Determine network and netmask */ if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) { (void)fprintf(stderr, "%s: bad interface %s: %s\n", prog, interface, errbuf); exit(1); } /* Drop into the background if not debugging */ if (!debug) { pid = fork(); if (pid < 0) { syslog(LOG_ERR, "main fork(): %m"); exit(1); } else if (pid != 0) exit(0); (void)close(fileno(stdin)); (void)close(fileno(stdout)); (void)close(fileno(stderr)); #ifdef TIOCNOTTY fd = open("/dev/tty", O_RDWR); if (fd >= 0) { (void)ioctl(fd, TIOCNOTTY, 0); (void)close(fd); } #else (void) setsid(); #endif } } openlog(prog, 0, LOG_DAEMON); if (chdir(arpdir) < 0) { syslog(LOG_ERR, "chdir(%s): %m", arpdir); syslog(LOG_ERR, "(using current working directory)"); } if (rfilename != NULL) { pd = pcap_open_offline(rfilename, errbuf); if (pd == NULL) { syslog(LOG_ERR, "pcap open %s: %s", rfilename, errbuf); exit(1); } swapped = pcap_is_swapped(pd); } else { snaplen = max(sizeof(struct ether_header), sizeof(struct fddi_header)) + sizeof(struct ether_arp); timeout = 1000; pd = pcap_open_live(interface, snaplen, 1, timeout, errbuf); if (pd == NULL) { syslog(LOG_ERR, "pcap open %s: %s", interface, errbuf); exit(1); } #ifdef WORDS_BIGENDIAN swapped = 1; #endif } /* * Revert to non-privileged user after opening sockets * (not needed on most systems). */ setgid(getgid()); setuid(getuid()); /* Must be ethernet or fddi */ linktype = pcap_datalink(pd); if (linktype != DLT_EN10MB && linktype != DLT_FDDI) { syslog(LOG_ERR, "Link layer type %d not ethernet or fddi", linktype); exit(1); } /* Compile and install filter */ if (pcap_compile(pd, &code, "arp or rarp", 1, netmask) < 0) { syslog(LOG_ERR, "pcap_compile: %s", pcap_geterr(pd)); exit(1); } if (pcap_setfilter(pd, &code) < 0) { syslog(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pd)); exit(1); } if (rfilename == NULL) syslog(LOG_INFO, "listening on %s", interface); /* Read in database */ initializing = 1; if (!readdata()) exit(1); sorteinfo(); #ifdef DEBUG if (debug > 2) { debugdump(); exit(0); } #endif initializing = 0; (void)setsignal(SIGINT, die); (void)setsignal(SIGTERM, die); (void)setsignal(SIGHUP, die); if (rfilename == NULL) { (void)setsignal(SIGQUIT, checkpoint); (void)setsignal(SIGALRM, checkpoint); (void)alarm(CHECKPOINT); } switch (linktype) { case DLT_EN10MB: status = pcap_loop(pd, 0, process_ether, NULL); break; case DLT_FDDI: status = pcap_loop(pd, 0, process_fddi, NULL); break; default: syslog(LOG_ERR, "bad linktype %d (can't happen)", linktype); exit(1); } if (status < 0) { syslog(LOG_ERR, "pcap_loop: %s", pcap_geterr(pd)); exit(1); } pcap_close(pd); if (!dump()) exit(1); exit(0); }
int main(int argc, char **argv) { register int cnt, op, i; bpf_u_int32 localnet, netmask; register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName; pcap_handler printer; struct bpf_program fcode; RETSIGTYPE (*oldhandler)(int); u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; cnt = -1; device = NULL; infile = NULL; RFileName = NULL; WFileName = NULL; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; if (abort_on_misalignment(ebuf) < 0) error("%s", ebuf); opterr = 0; while ( (op = getopt(argc, argv, "ac:defF:i:lnNOpqr:s:StT:vw:xY")) != EOF) switch (op) { case 'a': ++aflag; break; case 'c': cnt = atoi(optarg); if (cnt <= 0) error("invalid packet count %s", optarg); break; case 'd': ++dflag; break; case 'e': ++eflag; break; case 'f': ++fflag; break; case 'F': infile = optarg; break; case 'i': device = optarg; break; case 'l': #ifdef HAVE_SETLINEBUF setlinebuf(stdout); #else setvbuf(stdout, NULL, _IOLBF, 0); #endif break; case 'n': ++nflag; break; case 'N': ++Nflag; break; case 'O': Oflag = 0; break; case 'p': ++pflag; break; case 'q': ++qflag; break; case 'r': RFileName = optarg; break; case 's': snaplen = atoi(optarg); if (snaplen <= 0) error("invalid snaplen %s", optarg); break; case 'S': ++Sflag; break; case 't': --tflag; break; case 'T': if (strcasecmp(optarg, "vat") == 0) packettype = PT_VAT; else if (strcasecmp(optarg, "wb") == 0) packettype = PT_WB; else if (strcasecmp(optarg, "rpc") == 0) packettype = PT_RPC; else if (strcasecmp(optarg, "rtp") == 0) packettype = PT_RTP; else if (strcasecmp(optarg, "rtcp") == 0) packettype = PT_RTCP; else error("unknown packet type `%s'", optarg); break; case 'v': ++vflag; break; case 'w': WFileName = optarg; break; #ifdef YYDEBUG case 'Y': { /* Undocumented flag */ extern int yydebug; yydebug = 1; } break; #endif case 'x': ++xflag; break; default: usage(); /* NOTREACHED */ } if (aflag && nflag) error("-a and -n options are incompatible"); if (tflag > 0) thiszone = gmt2local(0); if (RFileName != NULL) { /* * We don't need network access, so set it back to the user id. * Also, this prevents the user from reading anyone's * trace file. */ setuid(getuid()); pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); localnet = 0; netmask = 0; if (fflag != 0) error("-f and -r options are incompatible"); } else { if (device == NULL) { device = pcap_lookupdev(ebuf); if (device == NULL) error("%s", ebuf); } pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf); if (pd == NULL) error("%s", ebuf); i = pcap_snapshot(pd); if (snaplen < i) { warning("snaplen raised from %d to %d", snaplen, i); snaplen = i; } if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { localnet = 0; netmask = 0; warning("%s", ebuf); } /* * Let user own process after socket has been opened. */ setuid(getuid()); } if (infile) cmdbuf = read_infile(infile); else cmdbuf = copy_argv(&argv[optind]); if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) error("%s", pcap_geterr(pd)); if (dflag) { bpf_dump(&fcode, dflag); exit(0); } init_addrtoname(localnet, netmask); (void)setsignal(SIGTERM, cleanup); (void)setsignal(SIGINT, cleanup); /* Cooperate with nohup(1) */ if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL) (void)setsignal(SIGHUP, oldhandler); if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); if (WFileName) { pcap_dumper_t *p = pcap_dump_open(pd, WFileName); if (p == NULL) error("%s", pcap_geterr(pd)); printer = pcap_dump; pcap_userdata = (u_char *)p; } else { printer = lookup_printer(pcap_datalink(pd)); pcap_userdata = 0; } if (RFileName == NULL) { (void)fprintf(stderr, "%s: listening on %s\n", program_name, device); (void)fflush(stderr); } if (pcap_loop(pd, cnt, printer, pcap_userdata) < 0) { (void)fprintf(stderr, "%s: pcap_loop: %s\n", program_name, pcap_geterr(pd)); exit(1); } pcap_close(pd); exit(0); }