+#define CONFIGFILE "/etc/nss-icmp.conf"
+
+struct cache {
+ struct cache *next, *prev;
+ char *addr;
+ socklen_t addrlen;
+ int af;
+ int notfound;
+ char **names;
+ time_t at, ttl;
+};
+
+static int inited = 0;
+static int timeout = -1;
+static int usecache = 1;
+static time_t nfttl = 300;
+static struct cache *cache = NULL;
+
+static void readconfig(void)
+{
+ FILE *f;
+ char linebuf[1024];
+ char *p, *p2;
+
+ if((f = fopen(CONFIGFILE, "r")) == NULL)
+ return;
+
+ while(fgets(linebuf, sizeof(linebuf), f) != NULL) {
+ if(linebuf[0] == '#')
+ continue;
+ if((p = strchr(linebuf, '\n')) != NULL)
+ *p = 0;
+ if((p = strchr(linebuf, ' ')) != NULL) {
+ p2 = p + 1;
+ *p = 0;
+ }
+ if(!strcmp(linebuf, "timeout")) {
+ if(p2 == NULL)
+ continue;
+ timeout = atoi(p2);
+ }
+ if(!strcmp(linebuf, "ttlnotfound")) {
+ if(p2 == NULL)
+ continue;
+ nfttl = atoi(p2);
+ }
+ if(!strcmp(linebuf, "nocache")) {
+ usecache = 0;
+ }
+ }
+
+ fclose(f);
+}
+
+static void freecache(struct cache *cc)
+{
+ int i;
+
+ if(cc->next != NULL)
+ cc->next->prev = cc->prev;
+ if(cc->prev != NULL)
+ cc->prev->next = cc->next;
+ if(cc == cache)
+ cache = cc->next;
+ if(cc->addr != NULL)
+ free(cc->addr);
+ if(cc->names != NULL) {
+ for(i = 0; cc->names[i] != NULL; i++)
+ free(cc->names[i]);
+ free(cc->names);
+ }
+ free(cc);
+}
+
+static void cachenotfound(const void *addr, socklen_t len, int af, time_t ttl)
+{
+ struct cache *cc;
+
+ for(cc = cache; cc != NULL; cc = cc->next) {
+ if((cc->af == af) && (cc->addrlen == len) && !memcmp(cc->addr, addr, len))
+ break;
+ }
+ if(cc == NULL) {
+ if((cc = malloc(sizeof(*cc))) == NULL)
+ return;
+ memset(cc, 0, sizeof(*cc));
+ if((cc->addr = malloc(len)) == NULL) {
+ freecache(cc);
+ return;
+ }
+ memcpy(cc->addr, addr, len);
+ cc->addrlen = len;
+ cc->af = af;
+ cc->at = time(NULL);
+ cc->ttl = ttl;
+
+ cc->notfound = 1;
+
+ cc->next = cache;
+ if(cache != NULL)
+ cache->prev = cc;
+ cache = cc;
+ }
+}
+
+static void updatecache(const void *addr, socklen_t len, int af, char **names, time_t ttl)
+{
+ int i;
+ struct cache *cc;
+
+ for(cc = cache; cc != NULL; cc = cc->next) {
+ if((cc->af == af) && (cc->addrlen == len) && !memcmp(cc->addr, addr, len))
+ break;
+ }
+ if(cc == NULL) {
+ if((cc = malloc(sizeof(*cc))) == NULL)
+ return;
+ memset(cc, 0, sizeof(*cc));
+ if((cc->addr = malloc(len)) == NULL) {
+ freecache(cc);
+ return;
+ }
+ memcpy(cc->addr, addr, len);
+ cc->addrlen = len;
+ cc->af = af;
+ cc->at = time(NULL);
+ cc->ttl = ttl;
+
+ for(i = 0; names[i] != NULL; i++);
+ if((cc->names = malloc(sizeof(*(cc->names)) * (i + 1))) == NULL) {
+ freecache(cc);
+ return;
+ }
+ memset(cc->names, 0, sizeof(*(cc->names)) * (i + 1));
+ for(i = 0; names[i] != NULL; i++) {
+ if((cc->names[i] = malloc(strlen(names[i]) + 1)) == NULL) {
+ freecache(cc);
+ return;
+ }
+ strcpy(cc->names[i], names[i]);
+ }
+
+ cc->next = cache;
+ if(cache != NULL)
+ cache->prev = cc;
+ cache = cc;
+ }
+}
+
+static void expirecache(void)
+{
+ struct cache *cc, *next;
+ time_t now;
+
+ now = time(NULL);
+ for(cc = cache; cc != NULL; cc = next) {
+ next = cc->next;
+ if(now - cc->at > cc->ttl) {
+ freecache(cc);
+ continue;
+ }
+ }
+}
+