DNS Caching Code [by AOW Admin]
Snippet Posted Wednesday, August 12th @ 11:26:21 PM, by George Greer in the Utils dept.
Added Jul 6, 1998. Click the link below to read it or download it.

From: aowadmin@mallory.draper.net
Subject: DNS Caching Code

Hi,

We at AgeofWar.ORG are now seeing several hundred unique IP addresses
each day.  Blocked gethostbyaddr() delays had become a significant
problem for us.  While we feel that our own name servers are quite fast
the same is not true for other name servers out in the network.

After several iterations of "in mud caching" schemes involving linked
lists and worse, I now feel that we have a stable solution with adequate
performance.

As good netizens, and in keeping with the unencumbered spirit of Linux and
open software (hint hint mud authors), I am releasing the caching
code into the net without any type of licensing requirement whatsoever.

So... use it, modify it, curse it (don't blame me if it breaks), or
throw it out as you like.

Regards,
Reed,

**************************** aowdns.h *****************************
char *aowdns(struct in_addr sin_addr);
void dnspurge(void);

**************************** aowdns.c *****************************
/*
 **********************************************************************
 * aowdns - Maintain IP/HostName Cache
 *
 * This module is invoked from CircleMUD comm.c code to translate
 * an IP address into its corresponding HostName.  It is known to
 * run on RedHat Linux 5.0 systems.
 *
 * In order to avoid the very long delay times often associated with
 * slow DNS servers and blocked gethostbyaddr(), a database cache
 * is maintained.  If the IP address is found in the cache then
 * gethostbyaddr() delays are circumvented.  Otherwise the HostName is
 * retrieved with gethostbyaddr() and saved in the cache for future
 * use.  A pointer to a character array containing a hostname or
 * equivalent IP address is always returned
 *
 * Cached entries are held for the period defined by KEEP_DAYS.
 * About once an hour the cache is scanned and old entries are
 * purged.
 *
 * As CircleMUD and NDBM both have db.h header files a conflict exists
 * and this module must be compiled seperately.  The following command
 * seems to work well: gcc -c -o aowdns.o -g aowdns.c
 *
 * When linking with circle, remember to add -lndbm and aowdns.o
 * to the linker command string in the Makefile.
 *
 * Sample invocation from comm.c:
 *
 *
strncpy(newd->host, aowdns(peer.sin_addr), HOST_LENGTH)
 *
 * This code may be freely distributed and modified as you like.
 * No license whatsoever is required. However, I would appreciate it
 * if you kept this notice and my name intact.
 *
 * Author: Reed H. Petty, Server Admin and Sometimes Coder
 *         AgeofWar.ORG Port 4000
 *         rhp@ageofwar.org
 *
 **********************************************************************
 */


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ndbm.h>
#include <string.h>
#include <time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "aowdns.h"

#define KEEP_DAYS 10

struct {

time_t created;

char name[128];
} dnsrec;

static time_t last_cleanup=0;
DBM *dnsdb = 0;
datum key_datum;
datum data_datum;

/*************************************************************/

char *aowdns (struct in_addr sin_addr)
{

  struct hostent *from;
  struct in_addr ip = sin_addr;
  int addr;

  if (!(dnsdb = dbm_open("dnscache", O_RDWR, 0600))) {
     unlink("dnscache.db");
     if (!(dnsdb = dbm_open("dnscache", O_RDWR | O_CREAT, 0600))) {

perror("dns database open failed");

exit(1);
     }
  }

/* Purge old entries from the database if its time */
if ((last_cleanup + 600) > time(NULL)) dnspurge();

/* Retrieve cached entry, if it exists */
  key_datum.dptr  = (void *)&ip;
  key_datum.dsize = sizeof(ip);
  data_datum = dbm_fetch(dnsdb, key_datum);
  if (data_datum.dptr) {

memcpy(&dnsrec,data_datum.dptr,data_datum.dsize);

dbm_close(dnsdb);

return(dnsrec.name);
  }

/* This ip address is not cached, look it up with gethostbyaddr() */
  if (from = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET)) {
     strncpy(dnsrec.name,from->h_name,sizeof(dnsrec.name));
     dnsrec.name[ sizeof(dnsrec.name)-1 ] = 0;
  } else {
     addr = ntohl(ip.s_addr);
     sprintf(dnsrec.name, "%03u.%03u.%03u.%03u",
          (int) ((addr & 0xFF000000) >> 24),
          (int) ((addr & 0x00FF0000) >> 16),
          (int) ((addr & 0x0000FF00) >> 8),
          (int) ((addr & 0x000000FF)));
  }

/* Insert a new cache entry */
  dnsrec.created = time(NULL);
  data_datum.dptr = (void *)&dnsrec;
  data_datum.dsize = sizeof(dnsrec.created) + strlen(dnsrec.name) + 1;
  key_datum.dptr = (void *)&ip;
  key_datum.dsize = sizeof(ip);
  dbm_store(dnsdb, key_datum, data_datum, DBM_REPLACE);

  dbm_close(dnsdb);
  return(dnsrec.name);
}

/**********************************************************************/

void dnspurge(void)
{
  time_t now = time(NULL);
  last_cleanup = now;

  for (key_datum=dbm_firstkey(dnsdb); key_datum.dptr;

key_datum=dbm_nextkey(dnsdb)) {

        data_datum = dbm_fetch(dnsdb, key_datum);
        memcpy(&dnsrec,data_datum.dptr,data_datum.dsize);


if ((dnsrec.created + KEEP_DAYS) < now)


dbm_delete(dnsdb, key_datum);
  }
}


/*
 *******************************************************************
 * dnslist - List the contents of the dnscache
 *
 * This is a companion module to aowdns.c...
 *
 * Compile: gcc -o dnslist dnslist.c -g -lndbm
 *
 * Sample invocation: ./dnslist dnscache    (leave the .db off)
 *
 * This code may be freely distributed and modified as you like.
 * No license whatsover is required.  However, I would appreciate it
 * if you kept this notice and my name intact.
 *
 * Author: Reed H. Petty, Server Admin and Sometimes Coder
 *
   AgeofWar.ORG Port 4000
 *
   rhp@ageofwar.org
 *******************************************************************
 */

**************************** dnslist.c *****************************
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ndbm.h>
#include <string.h>
#include <errno.h>

int main(int argc, char **argv)
{

struct dns_file {


time_t created;


char name[80];

} dnsrec;


int dnskey = 0;

datum key_datum;

datum data_datum;

DBM *dbm_ptr;


if (argc < 2) {


printf("Usage: dnslist filename (omit the .db suffix)\n");


exit(1);

}



if (!(dbm_ptr = dbm_open(argv[1], O_RDWR, 0600))) {


perror("database open failed");


exit(1);

}


for (key_datum=dbm_firstkey(dbm_ptr); key_datum.dptr;



key_datum=dbm_nextkey(dbm_ptr)) {



data_datum = dbm_fetch(dbm_ptr, key_datum);


memcpy(&dnsrec,data_datum.dptr,data_datum.dsize);


memcpy(&dnskey,key_datum.dptr,key_datum.dsize);





fprintf(stdout,"%03u.%03u.%03u.%03u  %d %s\n",



(dnskey & 0x000000FF),



(dnskey & 0x0000FF00) >> 8,



(dnskey & 0x00FF0000) >> 16,



(dnskey & 0xFF000000) >> 24,



dnsrec.created,



dnsrec.name);

}



dbm_close(dbm_ptr);
}



<< Disintegrate Spell [by Franco] | Reply | View as text | Threaded | dnslookup server code [by Rasmus Ronlev] >>

 


Related Links
  Linux
RedHat
CircleMUD
download
Related Articles
More by greerga
 
 

CircleMUD Snippets
 
Note: Not all of these snippets will work perfectly with your version of code, so be prepared to fix one or two bugs that may arise, and please let me know what you needed to do to fix it. Sending a corrected version is always welcome.
Finally, if you wish to use any of the snippets from this page, you are more than welcome, just mention the authors in your credits. If you wish to release any of these snippets to the public on another site, contact me FIRST.