home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / logresol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-27  |  10.1 KB  |  360 lines

  1. /***                                                                      ***\
  2.  
  3.     logresolve 1.1
  4.  
  5.     Tom Rathborne - tomr@uunet.ca - http://www.uunet.ca/~tomr/
  6.     UUNET Canada, April 16, 1995
  7.  
  8.     Rewritten by David Robinson. (drtr@ast.cam.ac.uk)
  9.  
  10.     Usage: logresolve [-s filename] [-c] < access_log > new_log
  11.  
  12.     Arguments:
  13.        -s filename     name of a file to record statistics
  14.        -c              check the DNS for a matching A record for the host.
  15.  
  16.     Notes:
  17.  
  18.     To generate meaningful statistics from an HTTPD log file, it's good
  19.     to have the domain name of each machine that accessed your site, but
  20.     doing this on the fly can slow HTTPD down.
  21.  
  22.     Compiling NCSA HTTPD with the -DMINIMAL_DNS flag turns IP#->hostname
  23.     resolution off. Before running your stats program, just run your log
  24.     file through this program (logresolve) and all of your IP numbers will
  25.     be resolved into hostnames (where possible).
  26.  
  27.     logresolve takes an HTTPD access log (in the COMMON log file format,
  28.     or any other format that has the IP number/domain name as the first
  29.     field for that matter), and outputs the same file with all of the
  30.     domain names looked up. Where no domain name can be found, the IP
  31.     number is left in.
  32.  
  33.     To minimize impact on your nameserver, logresolve has its very own
  34.     internal hash-table cache. This means that each IP number will only
  35.     be looked up the first time it is found in the log file.
  36.  
  37.     The -c option causes logresolve to apply the same check as httpd
  38.     compiled with -DMAXIMUM_DNS; after finding the hostname from the IP
  39.     address, it looks up the IP addresses for the hostname and checks
  40.     that one of these matches the original address.
  41.  
  42. \***                                                                      ***/
  43.  
  44. #ifdef __EMX__
  45. /* Need this inclide before any others under OS/2 */
  46. #include <sys/types.h>
  47. #endif
  48.  
  49. #include <ctype.h>
  50. #include <netdb.h>
  51. #include <string.h>
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54.  
  55. #ifndef __EMX__
  56. #include <sys/types.h> 
  57. #endif
  58. #include <sys/socket.h>
  59.  
  60. #include <netinet/in.h>
  61. #include <arpa/inet.h>
  62.  
  63. static void cgethost(struct in_addr ipnum, char *string, int check);
  64. static int getline(char *s, int n);
  65. static void stats(FILE *output);
  66.  
  67.  
  68. /* maximum line length */
  69. #define MAXLINE 1024
  70.  
  71. /* maximum length of a domain name */
  72. #ifndef MAXDNAME
  73. #define MAXDNAME 256
  74. #endif
  75.  
  76. /* number of buckets in cache hash table */
  77. #define BUCKETS 256
  78.  
  79. /*
  80.  * struct nsrec - record of nameservice for cache linked list
  81.  * 
  82.  * ipnum - IP number hostname - hostname noname - nonzero if IP number has no
  83.  * hostname, i.e. hostname=IP number
  84.  */
  85.  
  86. struct nsrec {
  87.     struct in_addr ipnum;
  88.     char *hostname;
  89.     int        noname;
  90.     struct nsrec *next;
  91. } *nscache[BUCKETS];
  92.  
  93. /*
  94.  * statistics - obvious
  95.  */
  96.  
  97. /* largeste value for h_errno */
  98. #define MAX_ERR (NO_ADDRESS)
  99. #define UNKNOWN_ERR (MAX_ERR+1)
  100. #define NO_REVERSE  (MAX_ERR+2)
  101.  
  102. static int cachehits = 0;
  103. static int cachesize = 0;
  104. static int entries = 0;
  105. static int resolves = 0;
  106. static int withname = 0;
  107. static int errors[MAX_ERR+3];
  108.  
  109. /*
  110.  * cgethost - gets hostname by IP address, caching, and adding unresolvable
  111.  * IP numbers with their IP number as hostname, setting noname flag
  112.  */
  113.  
  114. static void
  115. cgethost(ipnum, string, check)
  116. struct in_addr ipnum;
  117. char *string;
  118. int check;
  119. {
  120.     struct nsrec **current, *new;
  121.     struct hostent *hostdata;
  122.     char *name;
  123.     extern int h_errno;  /* some machines don't have this in their headers */
  124.  
  125.     current = &nscache[((ipnum.s_addr + (ipnum.s_addr >> 8) +
  126.                        (ipnum.s_addr >> 16) + (ipnum.s_addr >> 24)) % BUCKETS)];
  127.  
  128.     while (*current != NULL && ipnum.s_addr != (*current)->ipnum.s_addr)
  129.         current = & (*current)->next;
  130.  
  131.     if (*current == NULL)
  132.     {
  133.         cachesize++;
  134.         new = (struct nsrec *) malloc(sizeof(struct nsrec));
  135.         if (new == NULL)
  136.         {
  137.             perror("malloc");
  138.             fprintf(stderr, "Insufficient memory\n");
  139.             exit(1);
  140.         }
  141.         *current = new;
  142.         new->next = NULL;
  143.  
  144.         new->ipnum = ipnum;
  145.         
  146.         hostdata = gethostbyaddr((const char *) &ipnum, sizeof(struct in_addr),
  147.                                  AF_INET);
  148.         if (hostdata == NULL)
  149.         {
  150.             if (h_errno > MAX_ERR) errors[UNKNOWN_ERR]++;
  151.             else errors[h_errno]++;
  152.             new->noname = h_errno;
  153.             name = strdup(inet_ntoa(ipnum));
  154.         } else
  155.         {
  156.             new->noname = 0;
  157.             name = strdup(hostdata->h_name);
  158.             if (check)
  159.             {
  160.                 if (name == NULL)
  161.                 {
  162.                     perror("strdup");
  163.                     fprintf(stderr, "Insufficient memory\n");
  164.                     exit(1);
  165.                 }
  166.                 hostdata = gethostbyname(name);
  167.                 if (hostdata != NULL)
  168.                 {
  169.                     char **hptr;
  170.                     
  171.                     for (hptr=hostdata->h_addr_list; *hptr != NULL; hptr++)
  172.                         if(((struct in_addr *)(*hptr))->s_addr == ipnum.s_addr)
  173.                             break;
  174.                     if (*hptr == NULL) hostdata = NULL;
  175.                 }
  176.                 if (hostdata == NULL)
  177.                 {
  178.                     fprintf(stderr, "Bad host: %s != %s\n", name,
  179.                             inet_ntoa(ipnum));
  180.                     new->noname = NO_REVERSE;
  181.                     free(name);
  182.                     name = strdup(inet_ntoa(ipnum));
  183.                     errors[NO_REVERSE]++;
  184.                 }
  185.             }
  186.         }
  187.         new->hostname = name;
  188.         if (new->hostname == NULL)
  189.         {
  190.             perror("strdup");
  191.             fprintf(stderr, "Insufficient memory\n");
  192.             exit(1);
  193.         }
  194.     } else
  195.         cachehits++;
  196.  
  197.     strcpy(string, (*current)->hostname);
  198. }
  199.  
  200. /*
  201.  * prints various statistics to output
  202.  */
  203.  
  204. static void
  205. stats(output)
  206. FILE *output;
  207. {
  208.     int i;
  209.     char *ipstring;
  210.     struct nsrec *current;
  211.     char *errstring[MAX_ERR+3];
  212.  
  213.     for (i=0; i < MAX_ERR+3; i++) errstring[i] = "Unknown error";
  214.     errstring[HOST_NOT_FOUND] = "Host not found";
  215.     errstring[TRY_AGAIN] = "Try again";
  216.     errstring[NO_RECOVERY] = "Non recoverable error";
  217.     errstring[NO_DATA] = "No data record";
  218.     errstring[NO_ADDRESS] = "No address";
  219.     errstring[NO_REVERSE] = "No reverse entry";
  220.     
  221.     fprintf(output, "logresolve Statistics:\n");
  222.  
  223.     fprintf(output, "Entries: %d\n", entries);
  224.     fprintf(output, "    With name   : %d\n", withname);
  225.     fprintf(output, "    Resolves    : %d\n", resolves);
  226.     if (errors[HOST_NOT_FOUND])
  227.         fprintf(output, "    - Not found : %d\n", errors[HOST_NOT_FOUND]);
  228.     if (errors[TRY_AGAIN])
  229.         fprintf(output, "    - Try again : %d\n", errors[TRY_AGAIN]);
  230.     if (errors[NO_DATA])
  231.         fprintf(output, "    - No data   : %d\n", errors[NO_DATA]);
  232.     if (errors[NO_ADDRESS])
  233.         fprintf(output, "    - No address: %d\n", errors[NO_ADDRESS]);
  234.     if (errors[NO_REVERSE])
  235.         fprintf(output, "    - No reverse: %d\n", errors[NO_REVERSE]);
  236.     fprintf(output, "Cache hits      : %d\n", cachehits);
  237.     fprintf(output, "Cache size      : %d\n", cachesize);
  238.     fprintf(output, "Cache buckets   :     IP number * hostname\n");
  239.  
  240.     for (i = 0; i < BUCKETS; i++)
  241.         for (current = nscache[i]; current != NULL; current = current->next)
  242.         {
  243.             ipstring = inet_ntoa(current->ipnum);
  244.             if (current->noname == 0)
  245.                 fprintf(output, "  %3d  %15s - %s\n", i, ipstring,
  246.                         current->hostname);
  247.             else
  248.             {
  249.                 if (current->noname > MAX_ERR+2)
  250.                     fprintf(output, "  %3d  %15s : Unknown error\n", i,
  251.                             ipstring);
  252.                 else
  253.                     fprintf(output, "  %3d  %15s : %s\n", i, ipstring,
  254.                             errstring[current->noname]);
  255.             }
  256.         }
  257. }
  258.  
  259.  
  260. /*
  261.  * gets a line from stdin
  262.  */
  263.  
  264. static int
  265. getline(s, n)
  266. char *s;
  267. int n;
  268. {
  269.     char *cp;
  270.     
  271.     if (!fgets(s, n, stdin))
  272.         return (0);
  273.     cp = strchr(s, '\n');
  274.     if (cp)
  275.         *cp = '\0';
  276.     return (1);
  277. }
  278.  
  279. int
  280. main(argc, argv)
  281. int argc;
  282. char *argv[];
  283. {
  284.     struct in_addr ipnum;
  285.     char *bar, hoststring[MAXDNAME+1], line[MAXLINE], *statfile;
  286.     int i, check;
  287.  
  288.     check = 0;
  289.     statfile = NULL;
  290.     for (i=1; i < argc; i++)
  291.     {
  292.         if (strcmp(argv[i], "-c") == 0) check = 1;
  293.         else if (strcmp(argv[i], "-s") == 0)
  294.         {
  295.             if (i == argc-1)
  296.             {
  297.                 fprintf(stderr, "logresolve: missing filename to -s\n");
  298.                 exit(1);
  299.             }
  300.             i++;
  301.             statfile = argv[i];
  302.         }
  303.         else
  304.         {
  305.             fprintf(stderr, "Usage: logresolve [-s statfile] [-c] < input > output");
  306.             exit(0);
  307.         }
  308.     }
  309.     
  310.  
  311.     for (i = 0; i < BUCKETS; i++) nscache[i] = NULL;
  312.     for (i=0; i < MAX_ERR+2; i++) errors[i] = 0;
  313.  
  314.     while (getline(line, MAXLINE))
  315.     {
  316.         if (line[0] == '\0') continue;
  317.         entries++;
  318.         if (!isdigit(line[0]))
  319.         { /* short cut */
  320.             puts(line);
  321.             withname++;
  322.             continue;
  323.         }
  324.         bar = strchr(line, ' ');
  325.         if (bar != NULL) *bar = '\0';
  326.         ipnum.s_addr = inet_addr(line);
  327.         if (ipnum.s_addr == 0xffffffffu)
  328.         {
  329.             if (bar != NULL) *bar = ' ';
  330.             puts(line);
  331.             withname++;
  332.             continue;
  333.         }
  334.  
  335.         resolves++;
  336.  
  337.         cgethost(ipnum, hoststring, check);
  338.         if (bar != NULL)
  339.             printf("%s %s\n", hoststring, bar+1);
  340.         else
  341.             puts(hoststring);
  342.     }
  343.     
  344.     if (statfile != NULL)
  345.     {
  346.         FILE *fp;
  347.         fp = fopen(statfile, "w");
  348.         if (fp == NULL)
  349.         {
  350.             fprintf(stderr, "logresolve: could not open statistics file '%s'\n"
  351.                     , statfile);
  352.             exit(1);
  353.         }
  354.         stats(fp);
  355.         fclose(fp);
  356.     }
  357.     
  358.     return (0);
  359. }
  360.