diff options
Diffstat (limited to '')
-rw-r--r-- | src/dnscache.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/dnscache.c b/src/dnscache.c new file mode 100644 index 0000000..ecd7cee --- /dev/null +++ b/src/dnscache.c @@ -0,0 +1,198 @@ +/* $Id: dnscache.c,v 1.1.1.1 2000-02-16 17:32:22 sdyoung Exp $ + * + * This is a caching DNS system. When a host name is needed we look it up here + * and see if there is already an answer for it. The domains are placed in a + * hashed linked list. If the name is not here, then we need to look it up and + * add it to the system. This really speeds up the connection to servers since + * the DNS name does not need to be looked up each time. It's kind of cool. :) + * + * Copyright (C) 1999 Robert James Kaes (rjkaes@flarenet.com) + * Copyright (C) 2000 Chris Lightfoot (chris@ex-parrot.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifdef HAVE_CONFIG_H +#include <defines.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <assert.h> +#include <ctype.h> + +#include "utils.h" +#include "dnscache.h" + +#define HASH_BOX 25 +#define DNSEXPIRE (5 * 60) + +struct dnscache_s { + struct in_addr ipaddr; + char *domain; + time_t expire; + struct dnscache_s *next; +}; + +struct dnscache_s *cache[HASH_BOX]; + +static unsigned int hash(unsigned char *keystr, unsigned int box) +{ + unsigned long hashc = 0; + unsigned char ch; + + assert(keystr); + assert(box > 0); + + while ((ch = *keystr++)) + hashc += tolower(ch); + + return hashc % box; +} + +int lookup(struct in_addr *addr, char *domain) +{ + unsigned int box = hash(domain, HASH_BOX); + struct dnscache_s **rptr = &cache[box]; + struct dnscache_s *ptr = cache[box]; + + assert(addr); + assert(domain); + + while (ptr && strcasecmp(ptr->domain, domain)) { + rptr = &ptr->next; + ptr = ptr->next; + } + + if (ptr && !strcasecmp(ptr->domain, domain)) { + /* Woohoo... found it. Make sure it hasn't expired */ + if (difftime(time(NULL), ptr->expire) > DNSEXPIRE) { + /* Oops... expired */ + *rptr = ptr->next; + safefree(ptr->domain); + safefree(ptr); + return -1; + } + + /* chris - added this so that the routine can be used to just + * look stuff up. + */ + if (addr) *addr = ptr->ipaddr; + return 0; + } + + return -1; +} + +int insert(struct in_addr *addr, char *domain) +{ + unsigned int box = hash(domain, HASH_BOX); + struct dnscache_s **rptr = &cache[box]; + struct dnscache_s *ptr = cache[box]; + struct dnscache_s *newptr; + + assert(addr); + assert(domain); + + while (ptr) { + rptr = &ptr->next; + ptr = ptr->next; + } + + if (!(newptr = xmalloc(sizeof(struct dnscache_s)))) { + return -1; + } + + if (!(newptr->domain = xstrdup(domain))) { + safefree(newptr); + return -1; + } + + newptr->ipaddr = *addr; + + newptr->expire = time(NULL); + + *rptr = newptr; + newptr->next = ptr; + + return 0; +} + +int dnscache(struct in_addr *addr, char *domain) +{ + struct hostent *resolv; + + assert(addr); + assert(domain); + + if (inet_aton(domain, (struct in_addr *) addr) != 0) + return 0; + + /* Well, we're not dotted-decimal so we need to look it up */ + if (lookup(addr, domain) == 0) + return 0; + + /* Okay, so not in the list... need to actually look it up. */ + if (!(resolv = gethostbyname(domain))) + return -1; + + memcpy(addr, resolv->h_addr_list[0], resolv->h_length); + insert(addr, domain); + + return 0; +} + +static void dnsdelete(unsigned int c, struct dnscache_s *del) +{ + struct dnscache_s **rptr; + struct dnscache_s *ptr; + + assert(c > 0); + assert(del); + + rptr = &cache[c]; + ptr = cache[c]; + + while (ptr && (ptr != del)) { + rptr = &ptr->next; + ptr = ptr->next; + } + + if (ptr == del) { + *rptr = ptr->next; + safefree(ptr->domain); + safefree(ptr); + } +} + +void dnsclean(void) +{ + unsigned int c; + struct dnscache_s *ptr, *tmp; + + for (c = 0; c < HASH_BOX; c++) { + ptr = cache[c]; + + while (ptr) { + tmp = ptr->next; + + if (difftime(time(NULL), ptr->expire) > DNSEXPIRE) + dnsdelete(c, ptr); + + ptr = tmp; + } + } +} |