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