1 /*
2     webalizer - a web server log analysis program
3 
4     Copyright (C) 1997-2013  Bradford L. Barrett
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version, and provided that the above
10     copyright and permission notice is included with all distributed
11     copies of this or derived software.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 
22 */
23 
24 /*********************************************/
25 /* STANDARD INCLUDES                         */
26 /*********************************************/
27 
28 #include <time.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <unistd.h>                           /* normal stuff             */
34 #include <ctype.h>
35 #include <sys/utsname.h>
36 #include <zlib.h>
37 
38 /* ensure sys/types */
39 #ifndef _SYS_TYPES_H
40 #include <sys/types.h>
41 #endif
42 
43 /* Need socket header? */
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 
48 /* some systems need this */
49 #ifdef HAVE_MATH_H
50 #include <math.h>
51 #endif
52 
53 #ifdef USE_DNS                   /* skip everything in this file if no DNS */
54 
55 #include <netinet/in.h>          /* include stuff we need for dns lookups, */
56 #include <arpa/inet.h>           /* DB access, file control, etc...        */
57 #include <fcntl.h>
58 #include <netdb.h>               /* ensure getaddrinfo/getnameinfo         */
59 #include <signal.h>
60 #include <sys/signal.h>
61 #include <sys/stat.h>
62 #include <sys/time.h>
63 #include <sys/wait.h>
64 #include <db.h>                                /* DB header ****************/
65 #include "webalizer.h"                         /* main header              */
66 #include "lang.h"                              /* language declares        */
67 #include "hashtab.h"                           /* hash table functions     */
68 #include "parser.h"                            /* log parser functions     */
69 #include "dns_resolv.h"                        /* our header               */
70 
71 #ifndef DB_NOTFOUND
72 #define DB_NOTFOUND 1
73 #endif
74 
75 /* local data */
76 
77 DB       *dns_db   = NULL;                     /* DNS cache database       */
78 int      dns_fd    = 0;
79 
80 DB       *geo_db   = NULL;                     /* GeoDB database           */
81 #ifdef USE_DB185
82 int      geo_dbc   = 0;                        /* GeoDB database cursor    */
83 #else
84 DBC      *geo_dbc  = NULL;                     /* GeoDB database cursor    */
85 #endif
86 
87 struct   dns_child child[MAXCHILD];            /* DNS child pipe data      */
88 
89 /* DNODEPTR host_table[MAXHASH]; */
90 
91 static char     buffer[BUFSIZE];               /* log file record buffer   */
92 static char     tmp_buf[BUFSIZE];              /* used to temp save above  */
93 static struct   utsname system_info;           /* system info structure    */
94 
95 int      raiseSigChild = 1;
96 
97 time_t runtime;
98 time_t start_time, end_time;
99 float  temp_time;
100 
101 extern char *our_gzgets(void *, char *, int);  /* external our_gzgets func */
102 
103 /* internal function prototypes */
104 
105 static void process_list(DNODEPTR);
106 static void sigChild(int);
107 static void db_put(char *, char *, int);
108 void   set_fl(int, int);
109 void   clr_fl(int, int);
110 int    iptype(char *, unsigned char *);
111 
112 /*********************************************/
113 /* RESOLVE_DNS - lookup IP in cache          */
114 /*********************************************/
115 
resolve_dns(struct log_struct * log_rec)116 void resolve_dns(struct log_struct *log_rec)
117 {
118    DBT    query, response;
119    int    i;
120    /* aligned dnsRecord to prevent Solaris from doing a dump */
121    /* (not found in debugger, as it can dereference it :(    */
122    struct dnsRecord alignedRecord;
123 
124    if (!dns_db) return;   /* ensure we have a dns db */
125 
126    memset(&query, 0, sizeof(query));
127    memset(&response, 0, sizeof(response));
128    query.data = log_rec->hostname;
129    query.size = strlen(log_rec->hostname);
130 
131    if (debug_mode) fprintf(stderr,"Checking %s...", log_rec->hostname);
132 
133 #ifdef USE_DB185
134    if ( (i=dns_db->get(dns_db, &query, &response, 0)) == 0)
135 #else
136    if ( (i=dns_db->get(dns_db, NULL, &query, &response, 0)) == 0)
137 #endif
138    {
139       memcpy(&alignedRecord, response.data, sizeof(struct dnsRecord));
140       strncpy (log_rec->hostname,
141                ((struct dnsRecord *)response.data)->hostName,
142                MAXHOST);
143       log_rec->hostname[MAXHOST-1]=0;
144       if (debug_mode)
145          fprintf(stderr," found: %s (%ld)\n",
146            log_rec->hostname, (long)alignedRecord.timeStamp);
147    }
148    else  /* not found or error occured during get */
149    {
150       if (debug_mode)
151       {
152          if (i==DB_NOTFOUND) fprintf(stderr," not found\n");
153          else                fprintf(stderr," error (%d)\n",i);
154       }
155    }
156 }
157 
158 /*********************************************/
159 /* DNS_RESOLVER - read log and lookup IP's   */
160 /*********************************************/
161 
dns_resolver(void * log_fp)162 int dns_resolver(void *log_fp)
163 {
164    DNODEPTR  h_entries;
165    DNODEPTR  l_list = NULL;
166 
167    int       i;
168    int       save_verbose=verbose;
169 
170    u_int64_t listEntries = 0;
171 
172    struct sigaction sigPipeAction;
173    struct stat dbStat;
174    /* aligned dnsRecord to prevent Solaris from doing a dump */
175    /* (not found in debugger, as it can dereference it :(    */
176    struct dnsRecord alignedRecord;
177 
178    struct    flock tmp_flock;
179 
180    tmp_flock.l_whence=SEEK_SET;    /* default flock fields */
181    tmp_flock.l_start=0;
182    tmp_flock.l_len=0;
183    tmp_flock.l_pid=0;
184 
185    time(&runtime);
186 
187    /* get processing start time */
188    start_time = time(NULL);
189 
190    /* minimal sanity check on it */
191    if(stat(dns_cache, &dbStat) < 0)
192    {
193       if(errno != ENOENT)
194       {
195          dns_cache=NULL;
196          dns_db=NULL; return 0;  /* disable cache */
197       }
198    }
199    else
200    {
201       if(!dbStat.st_size)  /* bogus file, probably from a crash */
202       {
203          unlink(dns_cache);  /* remove it so we can recreate... */
204       }
205    }
206 
207    /* open cache file */
208 #ifdef USE_DB185
209    if (!(dns_db = dbopen(dns_cache, O_RDWR|O_CREAT, 0664, DB_HASH, NULL)))
210 #else
211    if ( (db_create(&dns_db, NULL, 0) != 0)   ||
212         (dns_db->open(dns_db, NULL,
213            dns_cache, NULL, DB_HASH,
214            DB_CREATE, 0644) != 0) )
215 #endif
216    {
217       /* Error: Unable to open DNS cache file <filename> */
218       if (verbose) fprintf(stderr,"%s %s\n",msg_dns_nodb,dns_cache);
219       dns_cache=NULL;
220       dns_db=NULL;
221       return 0;                  /* disable cache */
222    }
223 
224    /* get file descriptor */
225 #ifdef USE_DB185
226    dns_fd = dns_db->fd(dns_db);
227 #else
228    dns_db->fd(dns_db, &dns_fd);
229 #endif
230 
231    tmp_flock.l_type=F_WRLCK;                    /* set read/write lock type */
232    if (fcntl(dns_fd,F_SETLK,&tmp_flock) < 0)    /* and barf if we cant lock */
233    {
234       /* Error: Unable to lock DNS cache file <filename> */
235       if (verbose) fprintf(stderr,"%s %s\n",msg_dns_nolk,dns_cache);
236 #ifdef USE_DB185
237       dns_db->close(dns_db);
238 #else
239       dns_db->close(dns_db, 0);
240 #endif
241       dns_cache=NULL;
242       dns_db=NULL;
243       return 0;                  /* disable cache */
244    }
245 
246    /* Setup signal handlers */
247    sigPipeAction.sa_handler = SIG_IGN;
248    sigPipeAction.sa_flags   = SA_RESTART;
249    sigemptyset(&sigPipeAction.sa_mask);
250 
251    sigaction(SIGPIPE, &sigPipeAction, NULL);
252 
253    /* disable warnings/errors for this run... */
254    verbose=0;
255 
256    /* Main loop to read log records (either regular or zipped) */
257    while ( (gz_log)?(our_gzgets((void *)log_fp,buffer,BUFSIZE) != Z_NULL):
258            (fgets(buffer,BUFSIZE,log_fname?(FILE *)log_fp:stdin) != NULL))
259    {
260       if (strlen(buffer) == (BUFSIZE-1))
261       {
262          /* get the rest of the record */
263          while ( (gz_log)?(our_gzgets((void *)log_fp,buffer,BUFSIZE)!=Z_NULL):
264                  (fgets(buffer,BUFSIZE,log_fname?(FILE *)log_fp:stdin)!=NULL))
265          {
266             if (strlen(buffer) < BUFSIZE-1) break;
267          }
268          continue;                        /* go get next record if any    */
269       }
270 
271       strcpy(tmp_buf, buffer);            /* save buffer in case of error */
272       if(parse_record(buffer))            /* parse the record             */
273       {
274          struct addrinfo hints, *ares;
275          memset(&hints, 0, sizeof(hints));
276          hints.ai_family   = AF_UNSPEC;
277          hints.ai_socktype = SOCK_STREAM;
278          hints.ai_flags    = AI_NUMERICHOST;
279          if (0 == getaddrinfo(log_rec.hostname, "0", &hints, &ares))
280          {
281             DBT q, r;
282             memset(&q, 0, sizeof(q));
283             memset(&r, 0, sizeof(r));
284             q.data = log_rec.hostname;
285             q.size = strlen(log_rec.hostname);
286 
287             /* Check if we have it in DB */
288 #ifdef USE_DB185
289             if ( (i=(dns_db->get)(dns_db, &q, &r, 0)) == 0 )
290 #else
291             if ( (i=dns_db->get(dns_db, NULL, &q, &r, 0)) == 0 )
292 #endif
293             {
294                /* have a record for this address */
295                memcpy(&alignedRecord, r.data, sizeof(struct dnsRecord));
296                if (alignedRecord.timeStamp != 0)
297                   /* If it's not permanent, check if it's TTL has expired */
298                   if ( (runtime-alignedRecord.timeStamp ) > (86400*cache_ttl) )
299                      put_dnode(log_rec.hostname, ares->ai_addr,
300                                ares->ai_addrlen,  host_table);
301             }
302             else
303             {
304                if (i==DB_NOTFOUND)
305                    put_dnode(log_rec.hostname, ares->ai_addr,
306                              ares->ai_addrlen, host_table);
307             }
308             freeaddrinfo(ares);
309          }
310       }
311    }
312    verbose = save_verbose;     /* restore verbosity level... */
313 
314    listEntries = 0;
315 
316    /* build our linked list l_list  */
317    for(i=0;i < MAXHASH; i++)
318    {
319       for(h_entries=host_table[i]; h_entries ; h_entries = h_entries->next)
320       {
321          h_entries->llist = l_list;
322          l_list = h_entries;
323          listEntries++;
324       }
325    }
326 
327    if(!l_list)
328    {
329       /* No valid addresses found... */
330       if (verbose>1) printf("%s\n",msg_dns_none);
331       tmp_flock.l_type=F_UNLCK;
332       fcntl(dns_fd, F_SETLK, &tmp_flock);
333 #ifdef USE_DB185
334       dns_db->close(dns_db);
335 #else
336       dns_db->close(dns_db, 0);
337 #endif
338       return 0;
339    }
340 
341    /* process our list now... */
342    process_list(l_list);
343 
344    /* get processing end time */
345    end_time = time(NULL);
346 
347    /* display DNS processing statistics */
348    if (time_me || (verbose>1))
349    {
350       if (verbose<2 && time_me) printf("DNS: ");
351       printf("%llu %s ",listEntries, msg_addresses);
352 
353       /* total processing time in seconds */
354       temp_time = difftime(end_time,start_time);
355       if (temp_time==0) temp_time=1;
356       printf("%s %.0f %s", msg_in, temp_time, msg_seconds);
357 
358       /* calculate records per second */
359       if (temp_time)
360          i=( (int)((float)listEntries/temp_time) );
361       else i=0;
362 
363       if ( (i>0) && (i<=listEntries) ) printf(", %d/sec\n", i);
364          else  printf("\n");
365    }
366 
367    /* processing done, exit   */
368    tmp_flock.l_type=F_UNLCK;
369    fcntl(dns_fd, F_SETLK, &tmp_flock);
370 #ifdef USE_DB185
371    dns_db->close(dns_db);
372 #else
373    dns_db->close(dns_db, 0);
374 #endif
375    return 0;
376 
377 }
378 
379 /*********************************************/
380 /* PROCESS_LIST - do the resoluton...        */
381 /*********************************************/
382 
process_list(DNODEPTR l_list)383 static void process_list(DNODEPTR l_list)
384 {
385    DNODEPTR  trav;
386 
387    char   child_buf[MAXHOST+3-((unsigned long)&trav+sizeof(trav))%3];
388    char   dns_buf[MAXHOST];
389    int    i;
390    int    pid;
391    int    nof_children = 0;
392    fd_set rd_set;
393    char   hbuf[NI_MAXHOST];
394 
395    struct sigaction sigChildAction;
396 
397    sigChildAction.sa_handler = sigChild;
398    sigChildAction.sa_flags   = SA_NOCLDSTOP|SA_RESTART;
399    sigemptyset(&sigChildAction.sa_mask);
400 
401    raiseSigChild = 0;
402 
403    sigaction(SIGCHLD, &sigChildAction, NULL);
404 
405    /* fire up our child processes */
406    for(i=0; i < dns_children; i++)
407    {
408       if(pipe(child[i].inpipe))
409       {
410          if (verbose) fprintf(stderr,"INPIPE creation error");
411          return;   /* exit(1) */
412       }
413 
414       if(pipe(child[i].outpipe))
415       {
416          if (verbose) fprintf(stderr,"OUTPIPE creation error");
417          return;   /* exit(1); */
418       }
419 
420       /* fork it off */
421       switch(pid=fork())
422       {
423          case -1:
424          {
425             if (verbose) fprintf(stderr,"FORK error");
426             return;  /* exit(1); */
427          }
428 
429          case 0:             /* Child */
430          {
431             int size;
432 
433             close(child[i].inpipe[0]);
434             close(child[i].outpipe[1]);
435 
436             /* get struct sockaddr_storage here */
437             while((size = read(child[i].outpipe[0], child_buf, MAXHOST)))
438             {
439                if(size < 0)
440                {
441                   perror("read error");
442                   exit(1);
443                }
444                else
445                {
446                   /* Clear out our buffer */
447                   memset(hbuf,0,NI_MAXHOST);
448 
449                   if(0 == getnameinfo((struct sockaddr*)child_buf, size,
450                                      hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD))
451                   {
452                      /* must be at least 4 chars */
453                      if (strlen(hbuf)>3)
454                      {
455                         /* If long hostname, take max domain name part */
456                         if ((size = strlen(hbuf)) > MAXHOST-2)
457                            strcpy(child_buf,(hbuf+(size-MAXHOST+1)));
458                         else strcpy(child_buf, hbuf);
459                         size = strlen(child_buf);
460                      }
461                      else
462                      {
463                         if (debug_mode)
464                            printf("Child %d getnameinfo bad hbuf!\n",i);
465                      }
466                   }
467                   else
468                   {
469                      if(debug_mode)
470                        printf("Child %d getnameinfo failed!\n",i);
471                   }
472 
473                   if (write(child[i].inpipe[1], child_buf, size) == -1)
474                   {
475                      perror("write error");
476                      exit(1);
477                   }
478                }
479             }
480             close(child[i].inpipe[1]);
481             close(child[i].outpipe[0]);
482 
483             if(debug_mode)
484                printf( "Child %d got closed input, shutting down\n", i);
485 
486             fflush(stdout);
487             exit(0);
488          }  /* case 0 */
489 
490          default:
491          {
492             child[i].pid = pid;
493             child[i].flags = DNS_CHILD_READY|DNS_CHILD_RUNNING;
494             nof_children++;
495             close(child[i].inpipe[1]);
496             close(child[i].outpipe[0]);
497 
498             set_fl(child[i].inpipe[0], O_NONBLOCK);
499          }
500       }
501    }
502 
503    trav = l_list;
504 
505    while(nof_children)
506    {
507       static struct timeval selectTimeval;
508       int res;
509       int max_fd;
510 
511       FD_ZERO(&rd_set);
512       max_fd = 0;
513 
514       if(raiseSigChild)
515       {
516          int pid;
517 
518          while((pid = waitpid(-1, NULL, WNOHANG)) > 0)
519          {
520             for(i=0;i<dns_children;i++)
521             {
522                if(child[i].pid == pid)
523                {
524                   child[i].pid = 0;
525                   child[i].flags &= ~(DNS_CHILD_READY|DNS_CHILD_RUNNING);
526                   nof_children--;
527 
528                   if(debug_mode)
529                   printf("Reaped Child %d\n", pid);
530 
531                   break;
532                }
533             }
534          }
535          raiseSigChild--;
536          continue; /* while, nof children has just changed */
537       }
538 
539       for(i=0;i<dns_children;i++)
540       {
541          if(child[i].flags & DNS_CHILD_RUNNING) /* Child is running */
542          {
543             if(child[i].flags & DNS_CHILD_READY)
544             {
545                child[i].flags  &= ~DNS_CHILD_READY;
546 
547                if(trav)  /* something to resolve */
548                {
549                   if (write(child[i].outpipe[1], &trav->addr,
550                      trav->addrlen) != -1)
551                   {
552                      /* We will watch this child */
553                      child[i].cur    = trav;
554                      FD_SET(child[i].inpipe[0], &rd_set);
555                      max_fd = MAX(max_fd, child[i].inpipe[0]);
556 
557                      if(debug_mode)
558                         printf("Giving %d bytes to Child %d\n",
559                         trav->addrlen, i);
560 
561                      trav = trav->llist;
562                   }
563                   else  /* write error */
564                   {
565                      if(errno != EINTR)           /* Could be a signal */
566                      {
567                         perror("Could not write to pipe");
568                         close(child[i].outpipe[1]);           /* kill     */
569                         child[i].flags &= ~DNS_CHILD_RUNNING; /* child    */
570                      }
571 		  }
572                }
573                else /* List is complete */
574                {
575                   close(child[i].outpipe[1]);            /* Go away       */
576                   child[i].flags &= ~DNS_CHILD_RUNNING;  /* Child is dead */
577                }
578             }
579             else
580             {
581                /* Look, the busy child... */
582                FD_SET(child[i].inpipe[0], &rd_set);
583                max_fd = MAX(max_fd, child[i].inpipe[0]);
584             }
585          }
586       }
587 
588       selectTimeval.tv_sec =  5; /* This stuff ticks in 5 second intervals */
589       selectTimeval.tv_usec = 0;
590 
591       switch(res = select(max_fd+1, &rd_set, NULL, NULL, &selectTimeval))
592       {
593          case -1:
594          {
595             if(errno != EINTR)   /* Could be a signal */
596             perror("Error in select");
597 
598             break;
599          }
600 
601          case 0:   /* Timeout, just fall once through the child loop */
602          {
603             if(debug_mode)
604             printf("tick\n");
605 
606             break;
607          }
608 
609          default:
610          {
611             for(i=0; i< dns_children;i++)
612             {
613                if(!res)   /* All file descriptors done */
614                break;
615 
616                if(FD_ISSET(child[i].inpipe[0], &rd_set))
617                {
618                   int size;
619 
620                   res--;  /* One less... */
621 
622                   switch (size=read(child[i].inpipe[0], dns_buf, MAXHOST))
623                   {
624                      case -1:
625                      {
626                         if(errno != EINTR)
627                         perror("Could not read from pipe");
628                         break;
629                      }
630                      case 0:
631                      {
632                         /* EOF. Child has closed Pipe. It shouldn't have */
633                         /*  done that, could be an error or something.   */
634                         /*  Reap it                                      */
635                         close(child[i].outpipe[1]);
636                         child[i].flags &= ~DNS_CHILD_RUNNING;
637 
638                         if(debug_mode)
639                            printf("Child %d wants to be reaped\n", i);
640 
641                         break;
642                      }
643 
644                      default:
645                      {
646                         dns_buf[size] = '\0';
647                         if( strlen(dns_buf) > 1 &&
648                              memcmp(dns_buf, &(child[i].cur->addr),
649                                     sizeof(child[i].cur->addr)))
650                         {
651                            if(debug_mode)
652                               printf("Child %d Got a result: %s -> %s\n",
653                                      i, child[i].cur->string, dns_buf);
654                            db_put(child[i].cur->string, dns_buf, 0);
655                         }
656                         else
657                         {
658                            if(debug_mode)
659                               printf("Child %d could not resolve: %s (%s)\n",
660                                      i, child[i].cur->string,
661                                      (cache_ips)?"cache":"no cache");
662                            if (cache_ips)      /* Cache non-resolved? */
663                               db_put(child[i].cur->string,
664                                      child[i].cur->string,1);
665                         }
666 
667                         if(debug_mode)
668                            printf("Child %d back in task pool\n", i);
669 
670                         /* Child is back in the task pool */
671                         child[i].flags |= DNS_CHILD_READY;
672                         break;
673                      }
674                   }
675                }
676             }
677             break;
678          }
679       }
680    }
681    return;
682 }
683 
684 /*********************************************/
685 /* SET_FL - set flag on pipe FD              */
686 /*********************************************/
687 
set_fl(int fd,int flags)688 void set_fl(int fd, int flags)
689 {
690    int val;
691 
692    /* get current flags */
693    if ((val=fcntl(fd, F_GETFL, 0)) < 0)
694       if (verbose) fprintf(stderr,"set_fl F_GETFL error\n");
695 
696    /* set them */
697    val |= flags;
698 
699    /* and write them back */
700    if ((val=fcntl(fd, F_SETFL, val)) < 0)
701       if (verbose) fprintf(stderr,"set_fl F_SETFL error\n");
702 }
703 
704 /*********************************************/
705 /* CLR_FL - clear flag on pipe FD            */
706 /*********************************************/
707 
clr_fl(int fd,int flags)708 void clr_fl(int fd, int flags)
709 {
710    int val;
711 
712    /* Get current flags */
713    if ((val=fcntl(fd, F_GETFL, 0)) < 0)
714       if (verbose) fprintf(stderr,"clr_fl F_GETFL error\n");
715 
716    /* set them */
717    val &= ~flags;
718 
719    /* and write them back */
720    if ((val=fcntl(fd, F_SETFL, val)) < 0)
721       if (verbose) fprintf(stderr,"clr_fl F_SETFL error\n");
722 }
723 
724 /*********************************************/
725 /* DB_PUT - put key/val in the cache db      */
726 /*********************************************/
727 
db_put(char * key,char * value,int numeric)728 static void db_put(char *key, char *value, int numeric)
729 {
730    DBT    k, v;
731    char   *cp;
732    struct dnsRecord *recPtr = NULL;
733    int    nameLen = strlen(value)+1;
734 
735    /* Align to multiple of eight bytes */
736    int recSize = (sizeof(struct dnsRecord)+nameLen+7) & ~0x7;
737 
738    /* make sure we have a db ;) */
739    if(dns_db)
740    {
741       if((recPtr = calloc(1, recSize)))
742       {
743          recPtr->timeStamp = runtime;
744          recPtr->numeric = numeric;
745          memcpy(&recPtr->hostName, value, nameLen);
746          memset(&k, 0, sizeof(k));
747          memset(&v, 0, sizeof(v));
748 
749          /* Ensure all data is lowercase */
750          cp=key;   while (*cp++!='\0') *cp=tolower(*cp);
751          cp=value; while (*cp++!='\0') *cp=tolower(*cp);
752 
753          k.data = key;
754          k.size = strlen(key);
755 
756          v.size = recSize;
757          v.data = recPtr;
758 
759 #ifdef USE_DB185
760          if ( (dns_db->put)(dns_db, &k, &v, 0) < 0)
761 #else
762          if ( dns_db->put(dns_db, NULL, &k, &v, 0) != 0 )
763 #endif
764             if (verbose>1) fprintf(stderr,"db_put fail!\n");
765          free(recPtr);
766       }
767    }
768 }
769 
770 /*********************************************/
771 /* SIGCHILD - raise our signal               */
772 /*********************************************/
773 
sigChild(int signum)774 static void sigChild(int signum)
775 {
776    raiseSigChild++;
777 }
778 
779 /*********************************************/
780 /* OPEN_CACHE - open our cache file RDONLY   */
781 /*********************************************/
782 
open_cache()783 int open_cache()
784 {
785    struct stat  dbStat;
786    struct flock tmp_flock;
787 
788    tmp_flock.l_whence=SEEK_SET;    /* default flock fields */
789    tmp_flock.l_start=0;
790    tmp_flock.l_len=0;
791    tmp_flock.l_pid=0;
792    tmp_flock.l_type=F_RDLCK;
793 
794    /* double check filename was specified */
795    if(!dns_cache) { dns_db=NULL; return 0; }
796 
797    /* minimal sanity check on it */
798    if(stat(dns_cache, &dbStat) < 0)
799    {
800       if(errno != ENOENT) return 0;
801    }
802    else
803    {
804       if(!dbStat.st_size)  /* bogus file, probably from a crash */
805       {
806          unlink(dns_cache);  /* remove it so we can recreate... */
807       }
808    }
809 
810    /* open cache file */
811 #ifdef USE_DB185
812    if (!(dns_db = dbopen(dns_cache, O_RDONLY, 0664, DB_HASH, NULL)))
813 #else
814    if ( (db_create(&dns_db, NULL, 0) != 0)   ||
815         (dns_db->open(dns_db, NULL,
816            dns_cache, NULL, DB_HASH,
817            DB_RDONLY, 0644) != 0) )
818 #endif
819    {
820       /* Error: Unable to open DNS cache file <filename> */
821       if (verbose) fprintf(stderr,"%s %s\n",msg_dns_nodb,dns_cache);
822       return 0;                  /* disable cache */
823    }
824 
825    /* get file descriptor */
826 #ifdef USE_DB185
827    dns_fd = dns_db->fd(dns_db);
828 #else
829    dns_db->fd(dns_db, &dns_fd);
830 #endif
831 
832    /* Get shared lock on cache file */
833    if (fcntl(dns_fd, F_SETLK, &tmp_flock) < 0)
834    {
835       if (verbose) fprintf(stderr,"%s %s\n",msg_dns_nolk,dns_cache);
836 #ifdef USE_DB185
837       dns_db->close(dns_db);
838 #else
839       dns_db->close(dns_db, 0);
840 #endif
841       return 0;
842    }
843    return 1;
844 }
845 
846 /*********************************************/
847 /* CLOSE_CACHE - close our RDONLY cache      */
848 /*********************************************/
849 
close_cache()850 int close_cache()
851 {
852    struct flock tmp_flock;
853 
854    tmp_flock.l_whence=SEEK_SET;    /* default flock fields */
855    tmp_flock.l_start=0;
856    tmp_flock.l_len=0;
857    tmp_flock.l_pid=0;
858    tmp_flock.l_type=F_UNLCK;
859 
860    /* clear lock and close cache file */
861    fcntl(dns_fd, F_SETLK, &tmp_flock);
862 #ifdef USE_DB185
863    dns_db->close(dns_db);
864 #else
865    dns_db->close(dns_db, 0);
866 #endif
867    return 1;
868 }
869 
870 /*********************************************/
871 /* GEODB_OPEN - Open GeoDB database/cursor   */
872 /*********************************************/
873 
geodb_open(char * dbname)874 DB *geodb_open(char *dbname)
875 {
876    char buf[1025];
877 
878    if (dbname==NULL)
879       snprintf(buf,sizeof(buf),"%s/GeoDB.dat",GEODB_LOC);
880    else
881       strncpy(buf,dbname,sizeof(buf)-1);
882    buf[sizeof(buf)-1]='\0';
883 
884 #ifdef USE_DB185
885    geo_db = dbopen(buf, O_RDONLY, 0664, DB_HASH, NULL);
886    if (geo_db == NULL)
887       return NULL;
888 #else
889    /* create database thingie */
890    if ( db_create(&geo_db, NULL, 0) ) return NULL;
891 
892    /* open the database */
893    if (geo_db->open(geo_db,NULL,buf,NULL,DB_BTREE,DB_RDONLY,0)) return NULL;
894 
895    /* create our cursor */
896    if (geo_db->cursor(geo_db,NULL,&geo_dbc,0))
897    {
898       geo_db->close(geo_db,0);
899       return NULL;
900    }
901 #endif
902    /* all is well in the world */
903    return geo_db;
904 }
905 
906 /*********************************************/
907 /* GEODB_VER - Get database version info     */
908 /*********************************************/
909 
geodb_ver(DB * db,char * str)910 char *geodb_ver(DB *db, char *str)
911 {
912    int       i;
913    DBT       k,v;
914    unsigned  char x[16];
915 
916    memset(&x,   0, sizeof(x));
917    memset(&k,   0, sizeof(k));
918    memset(&v,   0, sizeof(v));
919    k.data=&x;
920    k.size=sizeof(x);
921 
922 #ifdef USE_DB185
923    i=geo_db->get(geo_db, &k, &v, 0);
924 #else
925    i=geo_db->get(geo_db, NULL, &k, &v, 0);
926 #endif
927 
928    if (i) strncpy(str, "Unknown", 8);
929    else   strncpy(str, v.data+3, v.size-3);
930    return str;
931 }
932 
933 /*********************************************/
934 /* GEODB_GET_CC - Get country code for IP    */
935 /*********************************************/
936 
geodb_get_cc(DB * db,char * ip,char * buf)937 char *geodb_get_cc(DB *db, char *ip, char *buf)
938 {
939    int      i;
940    DBT      k,v;
941    unsigned char addr[16];
942 
943    memset(addr, 0, sizeof(addr));
944    strncpy(buf, "--", 3);
945 
946    /* get IP address */
947    if (!iptype(ip, addr)) return buf;
948 
949    /* kludge for IPv6 mapped IPv4 */
950    if (addr[0]==0 && addr[1]==0 && addr[2]==0) { addr[10]=0; addr[11]=0; }
951 
952    /* kludge for IPv6 6to4 (RFC3056) */
953    if (addr[0]==0x20 && addr[1]==0x02)
954    {
955       memcpy(&addr[12],&addr[2],4);
956       memset(&addr,0,12);
957    }
958 
959    memset(&k, 0, sizeof(k));
960    memset(&v, 0, sizeof(v));
961    k.data=&addr;
962    k.size=sizeof(addr);
963 
964 #ifdef USE_DB185
965    i=geo_db->get(geo_db, &k, &v, 0);
966 #else
967    i=geo_dbc->c_get(geo_dbc, &k, &v, DB_SET_RANGE);
968 #endif
969    if (!i) memcpy(buf, v.data, 2);
970    return buf;
971 }
972 
973 /*********************************************/
974 /* GEODB_CLOSE - close GeoDB database        */
975 /*********************************************/
976 
geodb_close(DB * db)977 void geodb_close(DB *db)
978 {
979 #ifdef USE_DB185
980    db->close(db);
981 #else
982    db->close(db,0);
983 #endif
984 }
985 
986 /*********************************************/
987 /* IPTYPE - get IP type and format addr buf  */
988 /*********************************************/
989 
iptype(char * ip,unsigned char * buf)990 int iptype(char *ip, unsigned char *buf)
991 {
992    if (inet_pton(AF_INET6, ip, buf)>0)     return 2;
993    if (inet_pton(AF_INET,  ip, buf+12)>0)  return 1;
994    else return 0;
995 }
996 
997 #endif  /* USE_DNS */
998