Guest User

tcpwatch

a guest
Sep 24th, 2010
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.98 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <ctype.h>
  7. #include <syslog.h>
  8. #include <signal.h>
  9. #include <poll.h>
  10. #include <pcap.h>
  11. #include <errno.h>
  12. #include <time.h>
  13. #include <sys/time.h>
  14. #include <sys/types.h>
  15. #include <stdint.h> /* Definition of uint64_t */
  16.  
  17. #define MAXBUF 2048 /* Length of log message buffer */
  18. #define SNAP_LEN 1518   /* Packet capture snaplength */
  19. #define INTV_MIN 1ULL   /* milliseconds */
  20. #define INTV_MAX 18446744073709ULL  /* milliseconds */
  21. #define TSTAMPFMT "%Y-%m-%dT%H:%M:%S"
  22.  
  23. char *iface = NULL;
  24. char *bpf = NULL;
  25. int i, daemonize = 1;
  26. uint64_t interval = 1000ULL;
  27. int log_facility = LOG_DAEMON;
  28.  
  29. /* Signal handler flags */
  30. static int exit_request = 0;
  31.  
  32. /* from tcpdump.c */
  33. char *copy_argv(register char **argv)
  34. {
  35.     register char **p;
  36.     register u_int len = 0;
  37.     char *buf;
  38.     char *src, *dst;
  39.  
  40.     p = argv;
  41.     if (*p == 0)
  42.         return 0;
  43.  
  44.     while (*p)
  45.         len += strlen(*p++) + 1;
  46.  
  47.     buf = (char *)malloc(len);
  48.     if (buf == NULL)
  49.         fprintf(stderr, "copy_argv: malloc\n");
  50.  
  51.     p = argv;
  52.     dst = buf;
  53.     while ((src = *p++) != NULL) {
  54.         while ((*dst++ = *src++) != '\0')
  55.             ;
  56.         dst[-1] = ' ';
  57.     }
  58.     dst[-1] = '\0';
  59.  
  60.     return buf;
  61. }
  62.  
  63. /* from Pound */
  64. void logmsg(const int priority, const char *fmt, ...)
  65. {
  66.     char buf[MAXBUF + 1];
  67.     va_list ap;
  68.  
  69.     buf[MAXBUF] = '\0';
  70.     va_start(ap, fmt);
  71.     vsnprintf(buf, MAXBUF, fmt, ap);
  72.     va_end(ap);
  73.  
  74.     if(daemonize)
  75.         syslog(log_facility | priority, "%s", buf);
  76.     else
  77.         fprintf(stderr, "%s\n", buf);
  78.  
  79.     return;
  80. }
  81.  
  82. void usage(char* prog)
  83. {
  84.     printf("Usage: %s -i <iface> [options]\n", prog);
  85.     printf("Options:\n");
  86.     printf("  -w n   Set deadline to n milliseconds.\n");
  87.     printf("  -D     Run in foreground. Log to stderr.\n");
  88. }
  89.  
  90. /* from
  91.  * http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
  92.  */
  93. int getcmdline(int argc, char **argv)
  94. {
  95.     int c;
  96.  
  97.     opterr = 0;
  98.  
  99.     while((c = getopt(argc, argv, "hi:w:fD")) != -1)
  100.         switch (c)
  101.         {
  102.             case 'h':
  103.                 usage(argv[0]);
  104.                 exit(EXIT_SUCCESS);
  105.             case 'i':
  106.                 iface = optarg;
  107.                 break;
  108.             case 'w':
  109.                 /* milliseconds */
  110.                 interval = strtoll(optarg, NULL, 10);
  111.                 if(interval < INTV_MIN)
  112.                 {
  113.                     fprintf(stderr, "Fatal: Interval must be >= %lld ms\n", INTV_MIN);
  114.                     usage(argv[0]);
  115.                     exit(EXIT_FAILURE);
  116.                 }
  117.                 break;
  118.             case 'D':
  119.                 daemonize = 0;
  120.                 break;
  121.             case '?':
  122.                 if(optopt == 'i' || optopt == 'w')
  123.                     fprintf(stderr, "Option -%c requires an argument.\n", optopt);
  124.                 else if(isprint (optopt))
  125.                     fprintf(stderr, "Fatal: Unknown option `-%c'.\n", optopt);
  126.                 else
  127.                     fprintf(stderr, "Fatal: Unknown option character `\\x%x'.\n", optopt);
  128.                 usage(argv[0]);
  129.                 exit(EXIT_FAILURE);
  130.             default:
  131.                 usage(argv[0]);
  132.                 exit(EXIT_FAILURE);
  133.         }
  134.  
  135.     /* iface arg is required */
  136.     if(iface == NULL)
  137.     {
  138.         fprintf(stderr, "Fatal: No interface specified.\n");
  139.         usage(argv[0]);
  140.         exit(EXIT_FAILURE);
  141.     }
  142.  
  143.     /* the rest is the bpf, even if empty */
  144.     bpf = copy_argv(&argv[optind]);
  145.  
  146.     return 0;
  147. }
  148.  
  149. void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
  150. {
  151.     (void) args; /* avoid warning about unused parameter */
  152.     (void) header; /* avoid warning about unused parameter */
  153.     (void) packet; /* avoid warning about unused parameter */
  154. }
  155.  
  156. static void sighand_exit(int signum)
  157. {
  158.     (void) signum;
  159.     logmsg(LOG_WARNING, "Received SIGTERM; scheduling exit.");
  160.     exit_request = 1;
  161. }
  162.  
  163. int main (int argc, char **argv)
  164. {
  165.     char errbuf[PCAP_ERRBUF_SIZE];
  166.     pcap_t *descr;
  167.     struct bpf_program fp;
  168.     struct timeval tstart, tend;
  169.     uint64_t tdiff;
  170.     time_t ttmp;
  171.     char tstamp[20];
  172.     suseconds_t ustmp;
  173.     pid_t pid;
  174.  
  175.     getcmdline(argc, argv);
  176.  
  177.     /* open capture device */
  178.     descr = pcap_open_live(iface, SNAP_LEN, 1, 0, errbuf);
  179.     if (descr == NULL) {
  180.         fprintf(stderr, "pcap_open_live failed (%s): %s\n", iface, errbuf);
  181.         exit(EXIT_FAILURE);
  182.     }
  183.  
  184.     /* apply the filter */
  185.     if (pcap_compile(descr, &fp, bpf, 0, 0) == -1) {
  186.         fprintf(stderr, "pcap_compile failed (%s): %s\n", iface, pcap_geterr(descr));
  187.         exit(EXIT_FAILURE);
  188.     }
  189.  
  190.     if (pcap_setfilter(descr, &fp) == -1) {
  191.         fprintf(stderr, "pcap_setfilter failed (%s): %s\n", iface, pcap_geterr(descr));
  192.         exit(EXIT_FAILURE);
  193.     }
  194.  
  195.     signal(SIGTERM, sighand_exit);
  196.     signal(SIGINT, sighand_exit);
  197.  
  198.     /* prepare for poll loop */
  199.     int inoutage = 0;   /* state switch */
  200.     char errmsg[1024];  /* XXX - arbitrary size */
  201.     int error = 0;
  202.     int nfds;
  203.     struct pollfd pfd[1];
  204.  
  205.     /* stuff to poll */
  206.     pfd[0].fd = pcap_fileno(descr);
  207.     pfd[0].events = POLLIN;
  208.     pfd[0].revents = 0;
  209.  
  210.     if (daemonize && daemon(0, 0))
  211.         fprintf(stderr, "daemon() failed. Staying in foreground.\n");
  212.  
  213.     /* Get pid after forking. The pid is simply used to identify
  214.      * instances of the program running simultaneously.
  215.      */
  216.     pid = getpid();
  217.  
  218.     if (daemonize)
  219.         openlog("tcpwatch", LOG_CONS, LOG_DAEMON);
  220.     logmsg(LOG_NOTICE, "Starting with %llums deadline and filter: `%s'", interval, bpf);
  221.  
  222.     /* Main loop */
  223.     for(;;)
  224.     {
  225.         nfds = poll(pfd, 1, interval);
  226.         if (nfds == -1 || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))) {
  227.             if (errno != EINTR)
  228.             {
  229.                 logmsg(LOG_ERR, "Poll error: %s", strerror(errno));
  230.                 exit(EXIT_FAILURE);
  231.             }
  232.         }
  233.  
  234.         /* Handle packet arrivals */
  235.         if (pfd[0].revents) {
  236.             /* Reading a packet from the fd is tricky, so
  237.              * we leave all that work to pcap_dispatch
  238.              * (which in turn calls pcap_read_packet to do
  239.              * the actual reading).
  240.              */
  241.             (void)pcap_dispatch(descr, -1, (pcap_handler)got_packet, NULL);
  242.  
  243.             if(inoutage)
  244.             {
  245.                 if (gettimeofday(&tend, NULL) == -1)
  246.                 {
  247.                     logmsg(LOG_ERR, "gettimeofday failed: %s", strerror(errno));
  248.                     exit_request = 1;
  249.                 }
  250.  
  251.                 ttmp = time(NULL);
  252.                 strftime(tstamp, sizeof(tstamp), TSTAMPFMT, localtime(&ttmp));
  253.                 ustmp = tend.tv_usec;
  254.  
  255.                 /* Calculate timediff */
  256.                 tend.tv_sec -= tstart.tv_sec;
  257.                 tend.tv_usec -= tstart.tv_usec;
  258.  
  259.                 if(tend.tv_usec < 0)
  260.                 {
  261.                     tend.tv_sec--;
  262.                     tend.tv_usec += 1000000;
  263.                 }
  264.  
  265.                 tdiff = tend.tv_sec * 1000 + tend.tv_usec / 1000;
  266.                 logmsg(LOG_INFO, "(PID %d) %s.%03ld Outage recovered (%llu ms downtime).",
  267.                         pid,
  268.                         tstamp,
  269.                         ustmp/1000,
  270.                         tdiff);
  271.  
  272.                 inoutage = 0;
  273.             }
  274.         }
  275.  
  276.         /* Handle poll timeout */
  277.         if(!nfds)
  278.         {
  279.             if(!inoutage)
  280.             {
  281.                 if (gettimeofday(&tstart, NULL) == -1)
  282.                 {
  283.                     logmsg(LOG_ERR, "gettimeofday failed: %s", strerror(errno));
  284.                     exit_request = 1;
  285.                 }
  286.                 ttmp = time(NULL);
  287.                 strftime(tstamp, sizeof(tstamp), TSTAMPFMT, localtime(&ttmp));
  288.                 logmsg(LOG_DEBUG, "(PID %d) %s.%03ld Outage detected (%llu ms deadline).",
  289.                         pid,
  290.                         tstamp,
  291.                         tstart.tv_usec/1000,
  292.                         interval);
  293.                 inoutage = 1;
  294.             }
  295.         }
  296.  
  297.         if (error)
  298.             logmsg(LOG_WARNING, errmsg);
  299.  
  300.         if (exit_request)
  301.         {
  302.             logmsg(LOG_WARNING, "Exiting on system/user request.");
  303.             break;
  304.         }
  305.     }
  306.  
  307.     logmsg(LOG_DEBUG, "Closing packet capture device.");
  308.     pcap_close(descr);
  309.     exit(EXIT_SUCCESS);
  310.     return 0;
  311. }
Add Comment
Please, Sign In to add comment