Imported Debian patch 2.23.05-1
[hcoop/zz_old/debian/webalizer.git] / wcmgr.c
1 /*
2 wcmgr - Webalizer (DNS) Cache file Manager
3
4 webalizer - a web server log analysis program
5
6 Copyright (C) 1997-2011 Bradford L. Barrett
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version, and provided that the above
12 copyright and permission notice is included with all distributed
13 copies of this or derived software.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
23
24 */
25
26 /*********************************************/
27 /* STANDARD INCLUDES */
28 /*********************************************/
29
30 #include <time.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <locale.h>
35
36 #ifndef USE_DNS
37
38 /* ********************************************************** */
39 /* If DNS support is not enabled, then we just compile a stub */
40 /* program that displays an appropriate warning when run. */
41 /* ********************************************************** */
42
43 int main()
44 {
45 printf("********************* NOTICE!! *********************\n");
46 printf("This version of the Webalizer was not compiled with\n");
47 printf("DNS support. In order to use this program, you must\n");
48 printf("configure the Webalizer at build time with the DNS\n");
49 printf("support enabled (--enable-dns configure option).\n");
50 printf("****************************************************\n\n");
51 exit(1); /* exit with error code */
52 }
53
54 #else /* USE_DNS defined */
55
56 #include <errno.h>
57 #include <unistd.h> /* normal stuff */
58 #include <fcntl.h>
59 #include <ctype.h>
60 #include <sys/utsname.h>
61 #include <sys/stat.h>
62
63 /* ensure getopt */
64 #ifdef HAVE_GETOPT_H
65 #include <getopt.h>
66 #endif
67
68 /* ensure sys/types */
69 #ifndef _SYS_TYPES_H
70 #include <sys/types.h>
71 #endif
72
73 #include <db.h>
74 #include "webalizer.h"
75
76 /*********************************************/
77 /* Forward reference local functions */
78 /*********************************************/
79
80 void list_cache(void);
81 void stat_cache(void);
82 void export_cache(void);
83 void import_cache(void);
84 void find_rec(void);
85 void add_rec(void);
86 void del_rec(void);
87 void purge_cache(void);
88 void create_cache(void);
89 static int db_put(char *, char *, int, time_t);
90
91 /*********************************************/
92 /* GLOBAL VARIABLES */
93 /*********************************************/
94
95 char *pname = "WCMGR - Webalizer (DNS) Cache file Manager";
96 char *version = "1.00"; /* program version */
97 char *editlvl = "03"; /* edit level */
98 char *moddate = "12-Jul-2008"; /* modification date */
99 char *copyright = "Copyright 2007-2011 by Bradford L. Barrett";
100
101 int action = 'l'; /* action flag (default=list) */
102 int create = 0; /* cache creation flag */
103 int verbose = 0; /* Verbose flag (1=be verbose) */
104 int rec_ttl = 7; /* purge TTL in days */
105 DB *dns_db = NULL; /* DNS cache database */
106 DB *out_db = NULL; /* output cache db if needed */
107 DBC *cursorp = NULL; /* database cursor */
108 DBT q, r; /* query/reply structures */
109 char *in_file = NULL; /* input cache filename */
110 char out_file[MAXHOST+4]; /* output cache filename */
111 int dns_fd = 0; /* database file descriptor */
112 time_t runtime; /* runtime for TTL calcs */
113 char addr[129]; /* buffer for IP search addr */
114 char name[MAXHOST+1]; /* buffer for name value */
115
116 extern char *optarg; /* command line processing */
117 extern int optind;
118 extern int opterr;
119
120 /* dnsRecord structure used in wcmgr */
121 struct dnsRec
122 {
123 time_t timeStamp; /* Timestamp of resolv data */
124 int numeric; /* 0: Name, 1: IP-address */
125 char hostName[MAXHOST+1]; /* Hostname buffer (variable) */
126 } dns_rec;
127
128 /*********************************************/
129 /* PRINT_VER - display version information */
130 /*********************************************/
131
132 void print_ver()
133 {
134 int v,r,l;
135 struct utsname system_info;
136 uname(&system_info);
137 printf("%s V%s-%s\n%s\n",pname,version,editlvl,copyright);
138 if (verbose)
139 {
140 db_version(&v,&r,&l);
141 printf("System : %s %s (%s)\n",
142 system_info.sysname,
143 system_info.release,
144 system_info.machine);
145 printf("DB Ver. : V%d.%d.%d\n",v,r,l);
146 printf("Mod Date: %s\n",moddate);
147 }
148 printf("\n");
149 exit(0);
150 }
151
152 /*********************************************/
153 /* PRINT_HELP - Command help display */
154 /*********************************************/
155
156 void print_help(void)
157 {
158 printf("Usage: wcmgr [options] cache-file\n\n");
159 printf("Options:\n");
160 printf(" -h This help display\n");
161 printf(" -V Version information\n");
162 printf(" -v be verbose\n");
163 printf(" -a addr Add DNS record\n");
164 printf(" -c Create new cache file\n");
165 printf(" -d addr Delete DNS record\n");
166 printf(" -f addr Find DNS record\n");
167 printf(" -i name Import cache from file\n");
168 printf(" -l List cache file contents\n");
169 printf(" -n name hostname (used for add)\n");
170 printf(" -p num Purge after num days\n");
171 printf(" -s Display cache file stats/info\n");
172 printf(" -t num TTL value (for add and stats)\n");
173 printf(" -x name Export cache to tab file\n");
174 printf("\n");
175 printf("If no options are specified, the default\n");
176 printf("action is to list the cache file contents.\n\n");
177 exit(0);
178 }
179
180 /*********************************************/
181 /* TTL_AGE - format TTL age for printing */
182 /*********************************************/
183
184 const char *ttl_age(time_t now, time_t then)
185 {
186 static char our_buffer[32]; /* string return buffer */
187 time_t age; /* age value in seconds */
188 int days, hours, mins; /* day/hour/min counters */
189
190 /* get age in seconds */
191 age=now-then;
192
193 /* now calc days/hours/min */
194 days=age/86400; age=age-(days*86400);
195 hours=age/3600; age=age-(hours*3600);
196 mins=age/60;
197
198 /* format the string */
199 sprintf(our_buffer,"%02dd:%02dh:%02dm",days, hours, mins);
200
201 /* and return to caller */
202 return our_buffer;
203 }
204
205 /*********************************************/
206 /* MAIN entry point here */
207 /*********************************************/
208
209 int main(int argc, char *argv[])
210 {
211 int i; /* gotta have one of these :-) */
212
213 /* some systems need this */
214 setlocale(LC_CTYPE,"");
215
216 /* initalize name/addr */
217 memset(addr, 0, sizeof(addr));
218 memset(name, 0, sizeof(name));
219 memset(out_file,0,sizeof(out_file));
220
221 /* Get our command line arguments */
222 opterr = 0;
223 while ((i=getopt(argc,argv,"a:cd:f:hi:ln:p::st:vVx:"))!=EOF)
224 {
225 switch (i)
226 {
227 case 'a': action='a'; strncpy(addr,optarg,sizeof(addr)-1); break;
228 case 'c': if (action!='i') action='c'; create=1; break;
229 case 'd': action='d'; strncpy(addr,optarg,sizeof(addr)-1); break;
230 case 'f': action='f'; strncpy(addr,optarg,sizeof(addr)-1); break;
231 case 'i': action='i'; strncpy(out_file,optarg,sizeof(out_file)-1);
232 break;
233 case 'h': print_help(); break;
234 case 'n': strncpy(name,optarg,sizeof(name)-1); break;
235 case 'p': action='p'; if (optarg!=NULL) rec_ttl=atoi(optarg); break;
236 case 's': action='s'; break;
237 case 't': rec_ttl=atoi(optarg); break;
238 case 'v': verbose=1; break;
239 case 'V': print_ver(); break;
240 case 'x': action='x'; strncpy(out_file,optarg,sizeof(out_file)-1);
241 break;
242 case ':': /* catch invalid options here */
243 case '?': break;
244 case 'l': /* This is the default action */
245 default: action='l'; break;
246 }
247 }
248
249 /* Get cache filename if specified */
250 if (argc - optind == 0) print_help(); /* gots to have a filename!! */
251 in_file = argv[optind];
252
253 /* Try to create our DB handle */
254 if ( db_create(&dns_db, NULL, 0) )
255 {
256 fprintf(stderr,"Error: unable to create db handle!\n");
257 exit(1);
258 }
259
260 /* force sane TTL value */
261 if (rec_ttl > 99) rec_ttl=99;
262 if (rec_ttl < 0 ) rec_ttl=7;
263
264 /* Branch on 'action' specified */
265 switch (action)
266 {
267 case 'a': add_rec(); break;
268 case 'c': create_cache(); break;
269 case 'd': del_rec(); break;
270 case 'f': find_rec(); break;
271 case 'i': import_cache(); break;
272 case 's': stat_cache(); break;
273 case 'p': purge_cache(); break;
274 case 'x': export_cache(); break;
275 case 'l':
276 default: list_cache(); break;
277 }
278 exit(0);
279 }
280
281 /*********************************************/
282 /* LIST_CACHE - Dump out cache contents */
283 /*********************************************/
284
285 void list_cache()
286 {
287 int i;
288 char ip_buf[48];
289 u_int64_t t_rec=0;
290 u_int64_t t_num=0;
291
292 /* open the database (read-only) */
293 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, DB_RDONLY, 0)))
294 {
295 /* Error opening the cache file.. tell user and exit */
296 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
297 exit(1);
298 }
299
300 /* Create a cursor */
301 if ( dns_db->cursor(dns_db, NULL, &cursorp, 0) )
302 {
303 fprintf(stderr,"Error: Unable to create cursor!\n");
304 exit(1);
305 }
306
307 /* get our runtime for TTL calculations */
308 time(&runtime);
309
310 if (verbose)
311 {
312 printf("Webalizer DNS Cache file listing generated %s\n",ctime(&runtime));
313 printf("IP Address TTL Age Hostname\n");
314 printf("--------------- ------------- ------------------------" \
315 "-----------------------\n");
316 }
317
318 /* initalize data areas */
319 memset(&q, 0, sizeof(DBT));
320 memset(&r, 0, sizeof(DBT));
321 memset(&dns_rec, 0, sizeof(struct dnsRec));
322
323 /* Loop through database */
324 while (!cursorp->c_get(cursorp, &q, &r, DB_NEXT))
325 {
326 /* got a record */
327 t_rec++;
328 memset(ip_buf, 0, sizeof(ip_buf));
329 strncpy(ip_buf, q.data, (q.size>47)?47:q.size); /* save IP address */
330 memcpy(&dns_rec, r.data, r.size);
331 if (dns_rec.numeric) t_num++;
332 printf("%-15s [%s] %s\n",ip_buf,
333 (dns_rec.timeStamp)?
334 ttl_age(runtime, dns_rec.timeStamp):
335 "-permanent-",
336 dns_rec.hostName);
337
338 /* done, clear for next rec */
339 memset(&q, 0, sizeof(DBT));
340 memset(&r, 0, sizeof(DBT));
341 }
342
343 if (verbose)
344 {
345 printf("------------------------------------------------------" \
346 "-----------------------\n");
347 printf("Filename: %s (%llu records)\n",in_file, t_rec);
348 }
349 }
350
351 /*********************************************/
352 /* PURGE_CACHE - Purge cache of expired recs */
353 /*********************************************/
354
355 void purge_cache()
356 {
357 int i;
358 char ip_buf[48];
359 u_int64_t age=0;
360 u_int64_t t_in=0;
361 u_int64_t t_out=0;
362 u_int64_t t_exp=0;
363
364 /* file control struct */
365 struct flock our_flock;
366
367 if (verbose) printf("Purging records over %d days from '%s'\n",
368 rec_ttl, in_file);
369
370 /* open the input database (read-write) */
371 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, 0, 0)))
372 {
373 /* Error opening the cache file.. tell user and exit */
374 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
375 exit(1);
376 }
377
378 /* get file descriptor */
379 dns_db->fd(dns_db, &dns_fd);
380
381 /* Try to lock the file */
382 our_flock.l_whence=SEEK_SET;
383 our_flock.l_start=0;
384 our_flock.l_len=0;
385 our_flock.l_type=F_WRLCK;
386
387 if (fcntl(dns_fd,F_SETLK,&our_flock) <0)
388 {
389 /* Error - can't lock file */
390 printf("Error: Unable to lock cache file: %s\n",strerror(errno));
391 exit(1);
392 }
393
394 /* Create a cursor */
395 if ( dns_db->cursor(dns_db, NULL, &cursorp, 0) )
396 {
397 fprintf(stderr,"Error: Unable to create cursor!\n");
398 exit(1);
399 }
400
401 /* Try to create our output DB handle */
402 if ( db_create(&out_db, NULL, 0) )
403 {
404 fprintf(stderr,"Error: unable to create output db handle!\n");
405 exit(1);
406 }
407
408 /* generate output filename */
409 memset(out_file, 0, sizeof(out_file));
410 sprintf(out_file, "%s.new", in_file);
411
412 /* open the output database (read-write) */
413 if ((i=out_db->open(out_db, NULL, out_file, NULL,
414 DB_HASH, DB_CREATE|DB_EXCL, 0644)))
415 {
416 /* Error opening the cache file.. tell user and exit */
417 fprintf(stderr,"Error: %s: %s\n",out_file,db_strerror(i));
418 exit(1);
419 }
420
421 /* get our runtime for TTL calculations */
422 time(&runtime);
423
424 /* initalize data areas */
425 memset(&q, 0, sizeof(DBT));
426 memset(&r, 0, sizeof(DBT));
427
428 /* Loop through database */
429 while (!cursorp->c_get(cursorp, &q, &r, DB_NEXT))
430 {
431 /* got a record */
432 t_in++;
433 memcpy(&dns_rec, r.data, r.size);
434
435 /* get record ttl age */
436 if (dns_rec.timeStamp==0) age=0;
437 else age = runtime - dns_rec.timeStamp;
438
439 if ( age <= (rec_ttl*86400) )
440 {
441 /* Good record.. insert into new cache file */
442 if ( (i=out_db->put(out_db, NULL, &q, &r, 0)) != 0 )
443 {
444 fprintf(stderr,"Error: db_put fail: %s!\n",db_strerror(i));
445 exit(1);
446 }
447 else t_out++;
448 }
449 else
450 {
451 /* Expired record */
452 t_exp++;
453 if (verbose)
454 {
455 memset(ip_buf, 0, sizeof(ip_buf));
456 strncpy(ip_buf, q.data, (q.size>47)?47:q.size);
457 printf("Purging %-16s [%s]\n",ip_buf,
458 ttl_age(runtime,dns_rec.timeStamp));
459 }
460 }
461
462 /* done, clear for next rec */
463 memset(&q, 0, sizeof(DBT));
464 memset(&r, 0, sizeof(DBT));
465 }
466
467 /* Successful exit! */
468 our_flock.l_type=F_UNLCK;
469 fcntl(dns_fd, F_SETLK, &our_flock);
470 dns_db->close(dns_db, 0);
471 out_db->close(out_db, 0);
472
473 /* rename files */
474 if (rename(out_file, in_file))
475 {
476 fprintf(stderr,"Error renaming file: %s\n",strerror(errno));
477 exit(1);
478 }
479
480 if (verbose)
481 printf("%llu of %llu records purged from '%s'\n",t_exp,t_in,in_file);
482 }
483
484 /*********************************************/
485 /* STAT_CACHE - Display cache stats/info */
486 /*********************************************/
487
488 void stat_cache()
489 {
490 /* Define some variables */
491 int i;
492 time_t min_age=0; /* min/max TTL age in cache */
493 time_t max_age=0;
494 u_int64_t t_rec=0; /* Various record totals */
495 u_int64_t t_err=0;
496 u_int64_t t_name=0;
497 u_int64_t t_num=0;
498 u_int64_t t_perm=0;
499 u_int64_t t_old=0;
500 time_t age;
501
502 /* open the database (read-only) */
503 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, DB_RDONLY, 0)))
504 {
505 /* Error opening the cache file.. tell user and exit */
506 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
507 exit(1);
508 }
509
510 /* Create a cursor */
511 if ( dns_db->cursor(dns_db, NULL, &cursorp, 0) )
512 {
513 fprintf(stderr,"Error: Unable to create cursor!\n");
514 exit(1);
515 }
516
517 /* get our runtime for TTL calculations */
518 time(&runtime);
519
520 /* initalize data areas */
521 memset(&q, 0, sizeof(DBT));
522 memset(&r, 0, sizeof(DBT));
523 memset(&dns_rec, 0, sizeof(struct dnsRec));
524
525 /* Loop through database */
526 while (!cursorp->c_get(cursorp, &q, &r, DB_NEXT))
527 {
528 t_rec++; /* add to total */
529 if (r.size >= sizeof(dns_rec)) { t_err++; continue; } /* size error? */
530 memcpy(&dns_rec, r.data, r.size); /* get record */
531 if (dns_rec.numeric) t_num++; else t_name++; /* resolved? */
532
533 if (dns_rec.timeStamp!=0) /* permanent? */
534 {
535 age=runtime-dns_rec.timeStamp; /* calc age */
536 if ((age < min_age) || (t_rec==1) ) min_age=age; /* min/max age */
537 if ( age > max_age ) max_age=age; /* if not perm */
538 if ( age > (rec_ttl*86400)) t_old++; /* purgable? */
539 }
540 else t_perm++; /* inc counter */
541
542 /* done, clear for next rec */
543 memset(&q, 0, sizeof(DBT));
544 memset(&r, 0, sizeof(DBT));
545 }
546
547 /* Print actual record counts */
548 printf("Report generated on: %s",ctime(&runtime));
549 printf("DNS Cache Filename : %s\n",in_file);
550
551 printf("Total Records : %llu\n",t_rec);
552 printf("Total Resolved : %llu\n",t_name);
553 printf("Total Unresolved : %llu\n",t_num);
554 printf("Total Permanent : %llu\n",t_perm);
555 printf("Newest Record age : %s\n",ttl_age(min_age,0));
556 printf("Oldest Record age : %s\n",ttl_age(max_age,0));
557 printf("Total over %02d days : %llu\n",rec_ttl,t_old);
558 if (t_err) printf("Record Size Errors : %llu\n",t_err);
559 printf("\n");
560 }
561
562 /*********************************************/
563 /* FIND_REC - Find IP record in cache */
564 /*********************************************/
565
566 void find_rec()
567 {
568 int i;
569 char ip_buf[48];
570
571 /* open the database (read-only) */
572 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, DB_RDONLY, 0)))
573 {
574 /* Error opening the cache file.. tell user and exit */
575 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
576 exit(1);
577 }
578
579 /* get our runtime for TTL calculations */
580 time(&runtime);
581
582 /* initalize data areas */
583 memset(&q, 0, sizeof(DBT));
584 memset(&r, 0, sizeof(DBT));
585 memset(&dns_rec, 0, sizeof(struct dnsRec));
586
587 /* search the cache */
588 q.data = &addr;
589 q.size = strlen(addr);
590 if ( (i=dns_db->get(dns_db, NULL, &q, &r, 0)) == 0)
591 {
592 /* We found it! display info */
593 memset(ip_buf, 0, sizeof(ip_buf));
594 strncpy(ip_buf, q.data, (q.size>47)?47:q.size); /* save IP address */
595 memcpy(&dns_rec, r.data, r.size);
596 if (verbose)
597 {
598 /* Verbose display */
599 printf("Address : %s\n",ip_buf);
600 printf("Hostname : %s\n",dns_rec.hostName);
601 printf("Resolved : %s\n",(dns_rec.numeric)?"No":"Yes");
602 if (dns_rec.timeStamp)
603 {
604 /* Not Permanent */
605 printf("Timestamp: %s",ctime(&dns_rec.timeStamp));
606 printf("TTL age : %s\n\n",ttl_age(runtime, dns_rec.timeStamp));
607 }
608 else
609 {
610 printf("Timestamp: N/A\n");
611 printf("TTL age : Permanent\n");
612 }
613 }
614 else
615 {
616 /* Standard 1 line display */
617 printf("%-15s [%s] %s\n",ip_buf,
618 (dns_rec.timeStamp)?
619 ttl_age(runtime, dns_rec.timeStamp):
620 "-permanent-",
621 dns_rec.hostName);
622 }
623 }
624 else
625 {
626 if (i==DB_NOTFOUND)
627 printf("%s not found!\n",addr);
628 else
629 printf("Error: %s\n",db_strerror(i));
630 }
631 }
632
633 /*********************************************/
634 /* DEL_REC - Delete record from cache file */
635 /*********************************************/
636
637 void del_rec()
638 {
639 int i;
640 char *cp;
641
642 /* ensure we have addr string */
643 if (addr[0]!='\0') cp=addr;
644 else
645 {
646 fprintf(stderr,"Error: No IP address specified!\n");
647 exit(1);
648 }
649
650 /* ensure IPv6 addresses are lowercase */
651 cp=addr; while (*cp!='\0') *cp++=tolower(*cp);
652
653 /* open the database (read-write) */
654 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, 0, 0)))
655 {
656 /* Error opening the cache file.. tell user and exit */
657 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
658 exit(1);
659 }
660
661 /* initalize data areas */
662 memset(&q, 0, sizeof(DBT));
663 memset(&r, 0, sizeof(DBT));
664 memset(&dns_rec, 0, sizeof(struct dnsRec));
665
666 /* search the cache */
667 q.data = &addr;
668 q.size = strlen(addr);
669
670 /* Try to delete the record */
671 if ( (i=dns_db->del(dns_db, NULL, &q, 0)) )
672 {
673 if (i==DB_NOTFOUND)
674 {
675 printf("%s not found in cache!\n",addr);
676 exit(1);
677 }
678 else
679 {
680 fprintf(stderr,"Error: %s\n",db_strerror(i));
681 exit(1);
682 }
683 }
684 dns_db->close(dns_db, 0);
685 if (verbose)
686 printf("%s sucessfully deleted from cache file\n",addr);
687 }
688
689 /*********************************************/
690 /* ADD_REC - Add record to cache file */
691 /*********************************************/
692
693 void add_rec()
694 {
695 int i;
696 char *cp;
697
698 /* ensure we have addr string */
699 if (addr[0]!='\0') cp=addr;
700 else
701 {
702 fprintf(stderr,"Error: No IP address specified!\n");
703 exit(1);
704 }
705
706 /* and check size */
707 if (strlen(addr)>47)
708 {
709 fprintf(stderr,"Error: IP address too long!\n");
710 exit(1);
711 }
712
713 /* ensure everything is lowercase */
714 cp=addr; while (*cp!='\0') *cp++=tolower(*cp);
715 if (name[0]!='\0')
716 {
717 cp=name; while (*cp!='\0') *cp++=tolower(*cp);
718 }
719
720 /* open the database (read-write) */
721 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, 0, 0)))
722 {
723 /* Error opening the cache file.. tell user and exit */
724 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
725 exit(1);
726 }
727
728 /* get our runtime for TTL calculations */
729 time(&runtime);
730
731 /* initalize data areas */
732 memset(&q, 0, sizeof(DBT));
733 memset(&r, 0, sizeof(DBT));
734 memset(&dns_rec, 0, sizeof(struct dnsRec));
735
736 /* search the cache */
737 q.data = &addr;
738 q.size = strlen(addr);
739 if ( (i=dns_db->get(dns_db, NULL, &q, &r, 0)) == 0)
740 {
741 fprintf(stderr,"Error: %s already exists in cache!\n",addr);
742 exit(1);
743 }
744 else
745 {
746 if (i!=DB_NOTFOUND)
747 {
748 fprintf(stderr,"Error: %s\n",db_strerror(i));
749 exit(1);
750 }
751 else
752 {
753 /* check hostname */
754 if (name[0]=='\0')
755 strncpy(name,addr,strlen(addr));
756
757 /* check if perm */
758 if (rec_ttl==0) runtime=0;
759
760 /* put it in the database */
761 if (db_put(addr, name, (strcmp(name,addr))?0:1, runtime)==0)
762 dns_db->close(dns_db,0);
763 if (verbose)
764 printf("%s sucessfully added to cache file\n",addr);
765 }
766 }
767 }
768
769 /*********************************************/
770 /* CREATE_CACHE - Create a new cache file */
771 /*********************************************/
772
773 void create_cache()
774 {
775 int i;
776
777 /* create the database */
778 if ((i=dns_db->open(dns_db,NULL,in_file,NULL,
779 DB_HASH,DB_CREATE|DB_EXCL,0644)))
780 {
781 /* Error opening the cache file.. tell user and exit */
782 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
783 exit(1);
784 }
785 dns_db->close(dns_db,0);
786 if (verbose) printf("Cache file %s created successfully\n",in_file);
787 }
788
789 /*********************************************/
790 /* IMPORT_CACHE - import cache from tab file */
791 /*********************************************/
792
793 void import_cache()
794 {
795 int i, flag=0;
796 u_int64_t t_rec=0;
797 FILE *in_fp;
798 char ip_buf[48];
799 char buffer[4096];
800
801 /* open the database (read-write) */
802 if (create) flag=DB_CREATE|DB_EXCL;
803 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, flag, 0644)))
804 {
805 /* Error opening the cache file.. tell user and exit */
806 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
807 exit(1);
808 }
809
810 /* open our import file */
811 in_fp=fopen(out_file,"r");
812 if (in_fp)
813 {
814 while ((fgets(buffer,4096,in_fp)) != NULL)
815 {
816 memset(&dns_rec, 0, sizeof(dns_rec));
817 memset(&ip_buf, 0, sizeof(ip_buf));
818 i = sscanf(buffer,"%s\t%lu\t%d\t%s",
819 ip_buf,
820 &dns_rec.timeStamp,
821 &dns_rec.numeric,
822 dns_rec.hostName);
823
824 if (ip_buf[0]=='#') continue; /* skip comments */
825
826 if (i!=4)
827 {
828 fprintf(stderr,"Error reading tab file %s\n",out_file);
829 exit(1);
830 }
831
832 t_rec++; /* bump totals */
833
834 /* put it in the database */
835 if (db_put(ip_buf, dns_rec.hostName,
836 dns_rec.numeric, dns_rec.timeStamp)!=0)
837 {
838 fprintf(stderr,"Error inserting cache record:\n%s\n",buffer);
839 exit(1);
840 }
841 }
842 }
843 else fprintf(stderr,"Error: File not found: %s\n",out_file);
844 dns_db->close(dns_db,0);
845
846 if (verbose) printf("%llu records imported into '%s' from file '%s'\n",
847 t_rec, in_file, out_file);
848 }
849
850 /*********************************************/
851 /* EXPORT_CACHE - export cache to tab file */
852 /*********************************************/
853
854 void export_cache()
855 {
856 int i;
857 u_int64_t t_rec=0;
858 char ip_buf[48];
859 FILE *out_fp;
860 struct stat out_stat;
861
862 /* make sure files are different! */
863 if (!strcmp(in_file,out_file))
864 {
865 fprintf(stderr,"Error: Bad export filename: %s\n",out_file);
866 exit(1);
867 }
868
869 /* open the database (read-only) */
870 if ((i=dns_db->open(dns_db, NULL, in_file, NULL, DB_HASH, DB_RDONLY, 0)))
871 {
872 /* Error opening the cache file.. tell user and exit */
873 fprintf(stderr,"Error: %s: %s\n",in_file,db_strerror(i));
874 exit(1);
875 }
876
877 /* Create a cursor */
878 if ( dns_db->cursor(dns_db, NULL, &cursorp, 0) )
879 {
880 fprintf(stderr,"Error: Unable to create cursor!\n");
881 exit(1);
882 }
883
884 /* stat output file */
885 if ( !(lstat(out_file, &out_stat)) )
886 {
887 /* check if the file is a symlink */
888 if ( S_ISLNK(out_stat.st_mode) )
889 {
890 fprintf(stderr,"%s %s\n","Error: File is a symlink:",out_file);
891 exit(1);
892 }
893 }
894
895 /* open output file */
896 if ( (out_fp=fopen(out_file,"w")) == NULL)
897 {
898 fprintf(stderr,"%s %s\n","Error: Cannot create file:",out_file);
899 exit(1);
900 }
901
902 /* initalize data areas */
903 memset(&q, 0, sizeof(DBT));
904 memset(&r, 0, sizeof(DBT));
905 memset(&dns_rec, 0, sizeof(struct dnsRec));
906
907 /* Loop through database */
908 while (!cursorp->c_get(cursorp, &q, &r, DB_NEXT))
909 {
910 /* got a record */
911 t_rec++;
912 memset(ip_buf, 0, sizeof(ip_buf));
913 strncpy(ip_buf, q.data, (q.size>47)?47:q.size); /* save IP address */
914 memcpy(&dns_rec, r.data, r.size);
915
916 /* Print out tab delimited line */
917 /* Format: IP timestamp numeric hostname */
918 fprintf(out_fp,"%s\t%lu\t%d\t%s\n",
919 ip_buf,dns_rec.timeStamp,
920 dns_rec.numeric,
921 dns_rec.hostName);
922
923 /* done, clear for next rec */
924 memset(&q, 0, sizeof(DBT));
925 memset(&r, 0, sizeof(DBT));
926 }
927 dns_db->close(dns_db,0);
928 fclose(out_fp);
929
930 if (verbose) printf("%llu records exported from '%s' to file '%s'\n",
931 t_rec, in_file, out_file);
932 }
933
934 /*********************************************/
935 /* DB_PUT - put key/val in the cache db */
936 /*********************************************/
937
938 static int db_put(char *key, char *value, int numeric, time_t ttl)
939 {
940
941 /* dnsRecord structure used in database */
942 struct dnsRecord
943 {
944 time_t timeStamp; /* Timestamp of resolv data */
945 int numeric; /* 0: Name, 1: IP-address */
946 char hostName[1]; /* Hostname buffer (variable) */
947 };
948
949 int i;
950 DBT k, v;
951 struct dnsRecord *recPtr = NULL;
952 int nameLen = strlen(value)+1;
953
954 /* Align to multiple of eight bytes */
955 int recSize = (sizeof(struct dnsRecord)+nameLen+7) & ~0x7;
956
957 /* make sure we have a db ;) */
958 if(dns_db)
959 {
960 if((recPtr = calloc(1, recSize)))
961 {
962 recPtr->timeStamp = ttl;
963 recPtr->numeric = numeric;
964 memcpy(&recPtr->hostName, value, nameLen);
965 memset(&k, 0, sizeof(k));
966 memset(&v, 0, sizeof(v));
967
968 k.data = key;
969 k.size = strlen(key);
970
971 v.size = recSize;
972 v.data = recPtr;
973
974 if ( (i=dns_db->put(dns_db, NULL, &k, &v, 0)) != 0 )
975 fprintf(stderr,"Error: db_put fail: %s!\n",db_strerror(i));
976 free(recPtr);
977 }
978 else return 1;
979 }
980 else return 1;
981 return i;
982 }
983 #endif /* USE_DNS */