/**************************************************************************** ** ** File: ipgrab.c ** ** Author: Mike Borella ** ** Sniffs all packets on the link and dumps the fields of the data link, ** IP, TCP, and UDP headers. ** ** $Id: ipgrab.c,v 1.18 2001/11/15 19:28:45 mborella Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Library General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** *****************************************************************************/ #include "global.h" #include "datalink.h" #include "ipgrab.h" #include "open_pcap.h" #include "ip_protocols.h" #include "error.h" #include "stats.h" #include "dynports.h" #include "file.h" char * pcap_cmd; /* command string for pcap */ pcap_t * pd; /* pcap device descriptor */ int cnt; /* number of packets to read */ pcap_handler dev_prcsr; /* ptr to func that processes packet for a device */ pcap_dumper_t * p; /* pointer to pcap dump file for writing */ struct arg_t * my_args; /* Command line arguments */ RETSIGTYPE cleanup(void); RETSIGTYPE cleanup_pcap(void); /*---------------------------------------------------------------------------- * * main() * *---------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { u_int8_t * userdata; int link; /* * Initiatilize the IP family module and the stats collection module */ init_ip_protocols(); stats_init(); /* * Set the layer */ set_layer(LAYER_NONE); /* * Clear packet count */ cnt = -1; /* * Parse command line for options, take care for version and packet count */ my_args = Cmdline(argc, argv); if (my_args->v) { printf("%s\n", VERSION); return 0; } if (my_args->c) cnt = my_args->c; /* * Make stdout buffered, if necessary */ if (my_args->b) #ifdef HAVE_SETLINEBUF setlinebuf(stdout); #else setvbuf(stdout, NULL, _IOLBF, 0); #endif /* * Parse any dynamic port bindings */ if (my_args->P) dynports_parse(my_args->P); /* * If we're reading a file, do things in a generic fashion. Otherwise * use standard libpcap functions to do a live read. */ if (my_args->r) { int ret; /*Get rid of root privs, not needed for reading files */ setuid(getuid()); /* * Set the signals so that we can clean up when ctrl-C is pressed * or some other reason causes the program to stop */ signal(SIGTERM, (sighandler_t) cleanup); signal(SIGINT, (sighandler_t) cleanup); signal(SIGQUIT, (sighandler_t) cleanup); signal(SIGABRT, (sighandler_t) cleanup); /* Try to ID the trace file type */ ret = file_id(my_args->r); if (ret == 0) error_fatal("unrecognized file type: %s", my_args->r); /* Open the file */ file_open(my_args->r); /* Read the packets */ file_read(cnt); /* When done, dump the stats */ stats_dump(); } else { /* This is just for live packet capture, not reading from a file */ /* * Set the signals so that we can clean up when ctrl-C is pressed * or some other reason causes the program to stop */ signal(SIGTERM, (sighandler_t) cleanup_pcap); signal(SIGINT, (sighandler_t) cleanup_pcap); signal(SIGQUIT, (sighandler_t) cleanup_pcap); signal(SIGABRT, (sighandler_t) cleanup_pcap); /* * Copy filter command into a string only if there is a command */ if (my_args->optind) pcap_cmd = argv2str(&argv[my_args->optind]); /* * Open the pcap device for sniffing */ link = open_pcap(); /* * Get rid of root privs */ setuid(getuid()); /* * Print intro stuff to stderr so output files have consistent * format */ fprintf(stderr, "%s %s\n", PACKAGE, VERSION); fprintf(stderr, "Listening on device %s ", my_args->i); switch(link) { case DLT_NULL: fprintf(stderr,"(loopback)\n"); break; case DLT_EN10MB: fprintf(stderr, "(ethernet)\n"); break; case DLT_SLIP: fprintf(stderr, "(slip)\n"); break; #ifdef DLT_RAW /* Not supported in some arch or older pcap versions */ case DLT_RAW: fprintf(stderr, "(raw)\n"); break; #endif case DLT_PPP: fprintf(stderr, "(ppp)\n"); break; default: error_fatal("\n%s cannot handle data link type %d", argv[0], link); } /* * Put the link type into a string */ userdata = (u_char *) &link; /* * Open the file for writing if -w is used */ if (my_args->w) { p = pcap_dump_open(pd, my_args->w); if (p == NULL) error_system("pcap_dump_open: %s", pcap_geterr(pd)); /* Read the specified number of packets */ if (pcap_loop(pd, cnt, pcap_dump, (u_char *) p) < 0) error_fatal("pcap_loop: %s", pcap_geterr(pd)); } else { /* Read all packets on the device. Continue until cnt packets read */ if (pcap_loop(pd, cnt, (pcap_func_t) datalink_pcap, userdata) < 0) error_fatal("pcap_loop: %s", pcap_geterr(pd)); } cleanup_pcap(); } return 0; } /*---------------------------------------------------------------------------- * * cleanup_pcap() * * Cleanup and collect PCAP statistics * *---------------------------------------------------------------------------- */ RETSIGTYPE cleanup_pcap(void) { struct pcap_stat stats; if (pcap_stats(pd, &stats) < 0) fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd)); else { fprintf(stderr, "%d packets received\n", stats.ps_recv); fprintf(stderr, "%d packets dropped by kernel\n", stats.ps_drop); } /* Close the pcap device */ pcap_close(pd); /* If there was a dump file open for writing, close that too */ if (my_args->w) pcap_dump_close(p); /* Display any other states that were collected */ cleanup(); } /*---------------------------------------------------------------------------- ** ** cleanup() ** ** Cleans up any files and displays stats. ** **---------------------------------------------------------------------------- */ RETSIGTYPE cleanup (void) { stats_dump(); exit(0); }