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