Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

tcpwatch

By: a guest on Sep 24th, 2010  |  syntax: C  |  size: 6.98 KB  |  views: 49  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  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. }
clone this paste RAW Paste Data