home *** CD-ROM | disk | FTP | other *** search
/ Download Now 8 / Download Now V8.iso / Program / InternetTools / ApacheWebServer1.3.6 / apache_1_3_6_win32.exe / _SETUP.1 / logresolve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-13  |  8.7 KB  |  346 lines

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