From 15a913c297d12c0a4b14c01437420ac0df8b6675 Mon Sep 17 00:00:00 2001 From: "fredrik@DOLDA2000.COM" Date: Fri, 29 Apr 2005 02:59:24 +0000 Subject: [PATCH] Added config file. Added cache. git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/icmp-dn@220 959494ce-11ee-0310-bf91-de5d638817bd --- nss-icmp.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 257 insertions(+), 73 deletions(-) diff --git a/nss-icmp.c b/nss-icmp.c index 305573f..b9f1013 100644 --- a/nss-icmp.c +++ b/nss-icmp.c @@ -11,9 +11,147 @@ #include #include +#define CONFIGFILE "/etc/nss-icmp.conf" + +struct cache { + struct cache *next, *prev; + char *addr; + socklen_t addrlen; + int af; + int notfound; + char **names; +}; + +static int inited = 0; +static int timeout = -1; +static int usecache = 1; +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, "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) +{ + 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->notfound = 1; + + cc->next = cache; + if(cache != NULL) + cache->prev = cc; + cache = cc; + } +} + +static void updatecache(struct hostent *he) +{ + int i; + struct cache *cc; + + for(cc = cache; cc != NULL; cc = cc->next) { + if((cc->af == he->h_addrtype) && (cc->addrlen == he->h_length) && !memcmp(cc->addr, he->h_addr_list[0], he->h_length)) + break; + } + if(cc == NULL) { + if((cc = malloc(sizeof(*cc))) == NULL) + return; + memset(cc, 0, sizeof(*cc)); + if((cc->addr = malloc(he->h_length)) == NULL) { + freecache(cc); + return; + } + memcpy(cc->addr, he->h_addr_list[0], he->h_length); + cc->addrlen = he->h_length; + cc->af = he->h_addrtype; + + for(i = 0; he->h_aliases[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; he->h_aliases[i] != NULL; i++) { + if((cc->names[i] = malloc(strlen(he->h_aliases[i]) + 1)) == NULL) { + freecache(cc); + return; + } + strcpy(cc->names[i], he->h_aliases[i]); + } + + cc->next = cache; + if(cache != NULL) + cache->prev = cc; + cache = cc; + } +} + enum nss_status _nss_icmp_gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { - int ret; + int i, ret; struct retstruct { char *aliaslist[16]; char *addrlist[2]; @@ -26,6 +164,12 @@ enum nss_status _nss_icmp_gethostbyaddr_r(const void *addr, socklen_t len, int a pid_t child; int pfd[2]; int rl; + struct cache *cc; + + if(!inited) { + readconfig(); + inited = 1; + } retbuf = (struct retstruct *)buffer; if((buflen < sizeof(*retbuf)) || (len > sizeof(retbuf->retaddr))) { @@ -34,92 +178,129 @@ enum nss_status _nss_icmp_gethostbyaddr_r(const void *addr, socklen_t len, int a return(NSS_STATUS_UNAVAIL); } - ap = (u_int8_t *)addr; - if(inet_ntop(af, addr, addrbuf, sizeof(addrbuf)) == NULL) { - *errnop = errno; - *h_errnop = NETDB_INTERNAL; - return(NSS_STATUS_UNAVAIL); - } - - if(pipe(pfd)) { - *errnop = errno; - *h_errnop = NETDB_INTERNAL; - return(NSS_STATUS_UNAVAIL); - } - /* I honestly don't know if it is considered OK to fork in other - * people's programs. We need a SUID worker, though, so there's - * little choice that I can see. */ - if((child = fork()) < 0) { - *errnop = errno; - *h_errnop = NETDB_INTERNAL; - return(NSS_STATUS_UNAVAIL); - } - - if(child == 0) { - int i, fd; - - if((fd = open("/dev/null", O_WRONLY)) < 0) - exit(127); - close(pfd[0]); - dup2(pfd[1], 1); - dup2(fd, 2); - for(i = 3; i < FD_SETSIZE; i++) - close(i); - - execlp("idnlookup", "idnlookup", addrbuf, NULL); - exit(127); + for(cc = cache; cc != NULL; cc = cc->next) { + if((cc->af == af) && (cc->addrlen == len) && !memcmp(cc->addr, addr, len)) + break; } - close(pfd[1]); - - rl = 0; - do { - ret = read(pfd[0], addrbuf + rl, sizeof(addrbuf) - rl); - if(ret < 0) { + if(cc == NULL) { + ap = (u_int8_t *)addr; + if(inet_ntop(af, addr, addrbuf, sizeof(addrbuf)) == NULL) { *errnop = errno; *h_errnop = NETDB_INTERNAL; - close(pfd[0]); return(NSS_STATUS_UNAVAIL); } - rl += ret; - if(rl >= sizeof(addrbuf) - 1) { - *errnop = ENOMEM; + + if(pipe(pfd)) { + *errnop = errno; *h_errnop = NETDB_INTERNAL; - close(pfd[0]); return(NSS_STATUS_UNAVAIL); } - } while(ret != 0); - addrbuf[rl] = 0; - close(pfd[0]); - - an = 0; - p = addrbuf; - p3 = buffer + sizeof(*retbuf); - while((p2 = strchr(p, '\n')) != NULL) { - *p2 = 0; - thislen = p2 - p; - if(thislen == 0) - continue; - if((p3 - buffer) + thislen + 1 > buflen) { - *errnop = ENOMEM; + /* I honestly don't know if it is considered OK to fork in other + * people's programs. We need a SUID worker, though, so there's + * little choice that I can see. */ + if((child = fork()) < 0) { + *errnop = errno; *h_errnop = NETDB_INTERNAL; return(NSS_STATUS_UNAVAIL); } - memcpy(p3, p, thislen + 1); - retbuf->aliaslist[an] = p3; - p3 += thislen + 1; - p = p2 + 1; - if(++an == 16) { - *errnop = ENOMEM; - *h_errnop = NETDB_INTERNAL; - return(NSS_STATUS_UNAVAIL); + + if(child == 0) { + int i, fd; + char timeoutbuf[128]; + + if((fd = open("/dev/null", O_WRONLY)) < 0) + exit(127); + close(pfd[0]); + dup2(pfd[1], 1); + dup2(fd, 2); + for(i = 3; i < FD_SETSIZE; i++) + close(i); + + if(timeout != -1) { + snprintf(timeoutbuf, sizeof(timeoutbuf), "%i", timeout); + execlp("idnlookup", "idnlookup", "-t", timeoutbuf, addrbuf, NULL); + } else { + execlp("idnlookup", "idnlookup", addrbuf, NULL); + } + exit(127); + } + + close(pfd[1]); + + rl = 0; + do { + ret = read(pfd[0], addrbuf + rl, sizeof(addrbuf) - rl); + if(ret < 0) { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + close(pfd[0]); + return(NSS_STATUS_UNAVAIL); + } + rl += ret; + if(rl >= sizeof(addrbuf) - 1) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + close(pfd[0]); + return(NSS_STATUS_UNAVAIL); + } + } while(ret != 0); + addrbuf[rl] = 0; + close(pfd[0]); + + an = 0; + p = addrbuf; + p3 = buffer + sizeof(*retbuf); + while((p2 = strchr(p, '\n')) != NULL) { + *p2 = 0; + thislen = p2 - p; + if(thislen == 0) + continue; + if((p3 - buffer) + thislen + 1 > buflen) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + memcpy(p3, p, thislen + 1); + retbuf->aliaslist[an] = p3; + p3 += thislen + 1; + p = p2 + 1; + if(++an == 16) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + } + if(an == 0) { + cachenotfound(addr, len, af); + *h_errnop = TRY_AGAIN; /* XXX: Is this correct? */ + return(NSS_STATUS_NOTFOUND); + } + retbuf->aliaslist[an] = NULL; + } else { + if(cc->notfound) { + *h_errnop = TRY_AGAIN; /* XXX: Is this correct? */ + return(NSS_STATUS_NOTFOUND); + } + + p3 = buffer + sizeof(*retbuf); + for(i = 0; cc->names[i] != NULL; i++) { + thislen = strlen(cc->names[i]); + if((p3 - buffer) + thislen + 1 > buflen) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + memcpy(p3, cc->names[i], thislen + 1); + retbuf->aliaslist[an] = p3; + p3 += thislen + 1; + if(++an == 16) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } } } - if(an == 0) { - *h_errnop = TRY_AGAIN; /* XXX: Is this correct? */ - return(NSS_STATUS_NOTFOUND); - } - retbuf->aliaslist[an] = NULL; memcpy(retbuf->retaddr, addr, len); retbuf->addrlist[0] = retbuf->retaddr; @@ -130,6 +311,9 @@ enum nss_status _nss_icmp_gethostbyaddr_r(const void *addr, socklen_t len, int a result->h_addrtype = af; result->h_length = len; + if(cc == NULL) + updatecache(result); + *h_errnop = NETDB_SUCCESS; return(NSS_STATUS_SUCCESS); } -- 2.11.0