From: wessels <> Date: Mon, 22 Jul 1996 22:40:19 +0000 (+0000) Subject: -Split ipcache.c into ipcache.c and dns.c X-Git-Tag: SQUID_3_0_PRE1~6015 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f88bb09c780151eb3736f0dc774ab5df6858ee4d;p=thirdparty%2Fsquid.git -Split ipcache.c into ipcache.c and dns.c -Moved newer functions from icp.c to client_side.c -Added fqdncache.c, like ipcache.c -Added new ACL type ACL_SRC_DOMAIN 'srcdomain' -Use aclMatchDomainList() instead of aclMatchWord() for domain names -Renamed 'stats/general' to 'stats/ipcache' --- diff --git a/src/Makefile.in b/src/Makefile.in index 5de1a1e96d..49119f3f6f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.30 1996/07/19 17:33:29 wessels Exp $ +# $Id: Makefile.in,v 1.31 1996/07/22 16:40:19 wessels Exp $ # # Uncomment and customize the following to suit your needs: # @@ -55,8 +55,8 @@ PROGS = squid client UTILS = dnsserver ftpget CGIPROGS = cachemgr.cgi OBJS = acl.o async_io.o background.o cache_cf.o errorpage.o \ - comm.o debug.o disk.o dynamic_array.o \ - fdstat.o filemap.o ftp.o gopher.o \ + client_side.o comm.o debug.o disk.o dns.o dynamic_array.o \ + fdstat.o filemap.o ftp.o fqdncache.o gopher.o \ hash.o http.o icp.o ident.o ipcache.o \ main.o mime.o neighbors.o objcache.o \ proto.o redirect.o send-announce.o ssl.o stack.o \ diff --git a/src/acl.cc b/src/acl.cc index 1d19f8e3d2..3e26d77a1e 100644 --- a/src/acl.cc +++ b/src/acl.cc @@ -1,5 +1,5 @@ /* - * $Id: acl.cc,v 1.21 1996/07/20 04:22:21 wessels Exp $ + * $Id: acl.cc,v 1.22 1996/07/22 16:40:19 wessels Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -46,7 +46,9 @@ static int aclMatchInteger _PARAMS((intlist * data, int i)); static int aclMatchIp _PARAMS((struct _acl_ip_data * data, struct in_addr c)); static int aclMatchRegex _PARAMS((relist * data, char *word)); static int aclMatchTime _PARAMS((struct _acl_time_data * data, time_t when)); +#ifdef UNUSED_CODE static int aclMatchEndOfWord _PARAMS((wordlist * data, char *word)); +#endif static intlist *aclParseIntlist _PARAMS((void)); static struct _acl_ip_data *aclParseIpList _PARAMS((void)); static intlist *aclParseMethodList _PARAMS((void)); @@ -54,6 +56,7 @@ static intlist *aclParseProtoList _PARAMS((void)); static struct _relist *aclParseRegexList _PARAMS((void)); static struct _acl_time_data *aclParseTimeSpec _PARAMS((void)); static wordlist *aclParseWordList _PARAMS((void)); +static wordlist *aclParseDomainList _PARAMS((void)); static squid_acl aclType _PARAMS((char *s)); static squid_acl aclType(s) @@ -65,6 +68,10 @@ static squid_acl aclType(s) return ACL_DST_IP; if (!strcmp(s, "domain")) return ACL_DST_DOMAIN; + if (!strcmp(s, "dstdomain")) + return ACL_DST_DOMAIN; + if (!strcmp(s, "srcdomain")) + return ACL_SRC_DOMAIN; if (!strcmp(s, "time")) return ACL_TIME; if (!strcmp(s, "pattern")) @@ -367,6 +374,21 @@ static wordlist *aclParseWordList() return head; } +static wordlist *aclParseDomainList() +{ + wordlist *head = NULL; + wordlist **Tail = &head; + wordlist *q = NULL; + char *t = NULL; + while ((t = strtok(NULL, w_space))) { + Tolower(t); + q = xcalloc(1, sizeof(wordlist)); + q->key = xstrdup(t); + *(Tail) = q; + Tail = &q->next; + } + return head; +} void aclParseAclLine() @@ -405,8 +427,9 @@ void aclParseAclLine() case ACL_DST_IP: A->data = (void *) aclParseIpList(); break; + case ACL_SRC_DOMAIN: case ACL_DST_DOMAIN: - A->data = (void *) aclParseWordList(); + A->data = (void *) aclParseDomainList(); break; case ACL_TIME: A->data = (void *) aclParseTimeSpec(); @@ -556,7 +579,6 @@ static int aclMatchWord(data, word) } return 0; } -#endif static int aclMatchEndOfWord(data, word) wordlist *data; @@ -575,6 +597,23 @@ static int aclMatchEndOfWord(data, word) } return 0; } +#endif + +static int aclMatchDomainList(data, host) + wordlist *data; + char *host; +{ + int offset; + if (host == NULL) + return 0; + debug(28, 3, "aclMatchDomainList: checking '%s'\n", host); + for (; data; data = data->next) { + debug(28, 3, "aclMatchDomainList: looking for '%s'\n", data->key); + if (matchDomainName(data->key, host)) + return 1; + } + return 0; +} static int aclMatchRegex(data, word) relist *data; @@ -631,6 +670,7 @@ int aclMatchAcl(acl, checklist) { request_t *r = checklist->request; struct hostent *hp = NULL; + char *fqdn = NULL; int k; if (!acl) return 0; @@ -643,7 +683,8 @@ int aclMatchAcl(acl, checklist) if ((hp = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS)) == NULL) { debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", acl->name, r->host); - return 0; /* cant check, return no match */ + checklist->need |= (1 << ACL_DST_IP); + return 0; } for (k = 0; *(hp->h_addr_list + k); k++) { xmemcpy(&checklist->dst_addr.s_addr, @@ -655,8 +696,17 @@ int aclMatchAcl(acl, checklist) return 0; /* NOTREACHED */ case ACL_DST_DOMAIN: - /* XXX This probably needs to use matchDomainName() */ - return aclMatchEndOfWord(acl->data, r->host); + return aclMatchDomainList(acl->data, r->host); + /* NOTREACHED */ + case ACL_SRC_DOMAIN: + fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS); + if (fqdn == NULL) { + debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", + acl->name, inet_ntoa(checklist->src_addr)); + checklist->need |= (1 << ACL_SRC_DOMAIN); + return 0; + } + return aclMatchDomainList(acl->data, fqdn); /* NOTREACHED */ case ACL_TIME: return aclMatchTime(acl->data, squid_curtime); @@ -690,8 +740,9 @@ static int aclMatchAclList(list, checklist) struct _acl_list *list; aclCheck_t *checklist; { - debug(28, 3, "aclMatchAclList: list=%p op=%d\n", list, list->op); while (list) { + debug(28, 3, "aclMatchAclList: checking %s%s\n", + list->op ? "" : "!", list->acl->name); if (aclMatchAcl(list->acl, checklist) != list->op) { debug(28, 3, "aclMatchAclList: returning 0\n"); return 0; diff --git a/src/client_side.cc b/src/client_side.cc new file mode 100644 index 0000000000..03eaed347d --- /dev/null +++ b/src/client_side.cc @@ -0,0 +1,141 @@ + +#include "squid.h" + +static void clientRedirectDone _PARAMS((void *data, char *result)); + +static int clientLookupDstIPDone(fd, hp, data) + int fd; + struct hostent *hp; + void *data; +{ + icpStateData *icpState = data; + debug(33, 5, "clientLookupDstIPDone: FD %d, '%s'\n", + fd, + icpState->url); + icpState->aclChecklist->need &= ~(1 << ACL_DST_IP); + icpState->aclChecklist->pend &= ~(1 << ACL_DST_IP); + if (hp == NULL) { + debug(33, 5, "clientLookupDstIPDone: Unknown host %s\n", + icpState->request->host); + icpState->aclChecklist->dst_addr.s_addr = INADDR_NONE; + } else { + xmemcpy(&icpState->aclChecklist->dst_addr.s_addr, + *(hp->h_addr_list), + hp->h_length); + debug(33, 5, "clientLookupDstIPDone: %s is %s\n", + icpState->request->host, + inet_ntoa(icpState->aclChecklist->dst_addr)); + } + clientAccessCheck(icpState, icpState->aclHandler); + return 1; +} + +static void clientLookupSrcFQDNDone(fd, fqdn, data) + int fd; + char *fqdn; + void *data; +{ + icpStateData *icpState = data; + debug(33, 5, "clientLookupSrcFQDNDone: FD %d, '%s', FQDN %s\n", + fd, + icpState->url, + fqdn ? fqdn : "NULL"); + icpState->aclChecklist->need &= ~(1 << ACL_SRC_DOMAIN); + icpState->aclChecklist->pend &= ~(1 << ACL_SRC_DOMAIN); + clientAccessCheck(icpState, icpState->aclHandler); +} + +static void clientLookupIdentDone(data) + void *data; +{ +} + +void clientAccessCheck(icpState, handler) + icpStateData *icpState; + void (*handler) _PARAMS((icpStateData *, int)); +{ + int answer = 1; + request_t *r = icpState->request; + aclCheck_t *ch = NULL; + if (icpState->aclChecklist == NULL) { + icpState->aclChecklist = xcalloc(1, sizeof(aclCheck_t)); + icpState->aclChecklist->src_addr = icpState->peer.sin_addr; + icpState->aclChecklist->request = requestLink(icpState->request); + } + ch = icpState->aclChecklist; + icpState->aclHandler = handler; + if (ch->pend) { + debug(33, 1, "clientAccessCheck: ACL's still pending: %x\n", + ch->pend); + return; + } + if (httpd_accel_mode && !getAccelWithProxy() && r->protocol != PROTO_CACHEOBJ) { + /* this cache is an httpd accelerator ONLY */ + if (!BIT_TEST(icpState->flags, REQ_ACCEL)) + answer = 0; + } else { + answer = aclCheck(HTTPAccessList, ch); + if (ch->need) { + if (ch->need & (1 << ACL_DST_IP)) { + ipcache_nbgethostbyname(icpState->request->host, + icpState->fd, + clientLookupDstIPDone, + icpState); + ch->pend |= (1 << ACL_DST_IP); + } else if (ch->need & (1 << ACL_SRC_DOMAIN)) { + fqdncache_nbgethostbyaddr(icpState->peer.sin_addr, + icpState->fd, + clientLookupSrcFQDNDone, + icpState); + ch->pend |= (1 << ACL_SRC_DOMAIN); + } + return; + } + } + requestUnlink(icpState->aclChecklist->request); + safe_free(icpState->aclChecklist); + icpState->aclHandler = NULL; + (*handler) (icpState, answer); +} + +void clientAccessCheckDone(icpState, answer) + icpStateData *icpState; + int answer; +{ + int fd = icpState->fd; + char *buf = NULL; + debug(33, 5, "clientAccessCheckDone: '%s' answer=%d\n", icpState->url, answer); + if (answer) { + urlCanonical(icpState->request, icpState->url); + redirectStart(icpState->url, fd, clientRedirectDone, icpState); + } else { + debug(33, 5, "Access Denied: %s\n", icpState->url); + buf = access_denied_msg(icpState->http_code = 400, + icpState->method, + icpState->url, + fd_table[fd].ipaddr); + icpSendERROR(fd, LOG_TCP_DENIED, buf, icpState, 403); + } +} + +static void clientRedirectDone(data, result) + void *data; + char *result; +{ + icpStateData *icpState = data; + int fd = icpState->fd; + debug(33, 5, "clientRedirectDone: '%s' result=%s\n", icpState->url, + result ? result : "NULL"); + if (result) { + safe_free(icpState->url); + icpState->url = xstrdup(result); + urlCanonical(icpState->request, icpState->url); + } + icpParseRequestHeaders(icpState); + fd_note(fd, icpState->url); + comm_set_select_handler(fd, + COMM_SELECT_READ, + (PF) icpDetectClientClose, + (void *) icpState); + icp_hit_or_miss(fd, icpState); +} diff --git a/src/comm.cc b/src/comm.cc index b5ce562abb..9db02cd100 100644 --- a/src/comm.cc +++ b/src/comm.cc @@ -1,6 +1,7 @@ + /* - * $Id: comm.cc,v 1.43 1996/07/20 04:22:23 wessels Exp $ + * $Id: comm.cc,v 1.44 1996/07/22 16:40:22 wessels Exp $ * * DEBUG: section 5 Socket Functions * AUTHOR: Harvest Derived @@ -684,7 +685,7 @@ int comm_select(sec, failtime) if (shutdown_pending || reread_pending) { serverConnectionsClose(); ftpServerClose(); - ipcacheShutdownServers(); + dnsShutdownServers(); redirectShutdownServers(); setSocketShutdownLifetimes(); } diff --git a/src/dns.cc b/src/dns.cc new file mode 100644 index 0000000000..9f7d2caa45 --- /dev/null +++ b/src/dns.cc @@ -0,0 +1,290 @@ +/* + * $Id: dns.cc,v 1.1 1996/07/22 16:40:22 wessels Exp $ + * + * DEBUG: section 34 Dnsserver interface + * AUTHOR: Harvest Derived + * + * SQUID Internet Object Cache http://www.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * 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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Copyright (c) 1994, 1995. All rights reserved. + * + * The Harvest software was developed by the Internet Research Task + * Force Research Group on Resource Discovery (IRTF-RD): + * + * Mic Bowman of Transarc Corporation. + * Peter Danzig of the University of Southern California. + * Darren R. Hardy of the University of Colorado at Boulder. + * Udi Manber of the University of Arizona. + * Michael F. Schwartz of the University of Colorado at Boulder. + * Duane Wessels of the University of Colorado at Boulder. + * + * This copyright notice applies to software in the Harvest + * ``src/'' directory only. Users should consult the individual + * copyright notices in the ``components/'' subdirectories for + * copyright information about other software bundled with the + * Harvest source code distribution. + * + * TERMS OF USE + * + * The Harvest software may be used and re-distributed without + * charge, provided that the software origin and research team are + * cited in any use of the system. Most commonly this is + * accomplished by including a link to the Harvest Home Page + * (http://harvest.cs.colorado.edu/) from the query page of any + * Broker you deploy, as well as in the query result pages. These + * links are generated automatically by the standard Broker + * software distribution. + * + * The Harvest software is provided ``as is'', without express or + * implied warranty, and with no support nor obligation to assist + * in its use, correction, modification or enhancement. We assume + * no liability with respect to the infringement of copyrights, + * trade secrets, or any patents, and are not responsible for + * consequential damages. Proper use of the Harvest software is + * entirely the responsibility of the user. + * + * DERIVATIVE WORKS + * + * Users may make derivative works from the Harvest software, subject + * to the following constraints: + * + * - You must include the above copyright notice and these + * accompanying paragraphs in all forms of derivative works, + * and any documentation and other materials related to such + * distribution and use acknowledge that the software was + * developed at the above institutions. + * + * - You must notify IRTF-RD regarding your distribution of + * the derivative work. + * + * - You must clearly notify users that your are distributing + * a modified version and not the original Harvest software. + * + * - Any derivative product is also subject to these copyright + * and use restrictions. + * + * Note that the Harvest software is NOT in the public domain. We + * retain copyright, as specified above. + * + * HISTORY OF FREE SOFTWARE STATUS + * + * Originally we required sites to license the software in cases + * where they were going to build commercial products/services + * around Harvest. In June 1995 we changed this policy. We now + * allow people to use the core Harvest software (the code found in + * the Harvest ``src/'' directory) for free. We made this change + * in the interest of encouraging the widest possible deployment of + * the technology. The Harvest software is really a reference + * implementation of a set of protocols and formats, some of which + * we intend to standardize. We encourage commercial + * re-implementations of code complying to this set of standards. + */ + +#include "squid.h" + +struct dnsQueueData { + struct dnsQueueData *next; + void *data; +}; + +static int dnsOpenServer _PARAMS((char *command)); + +static dnsserver_t **dns_child_table = NULL; +static int NDnsServersAlloc = 0; + +char *dns_error_message = NULL; /* possible error message */ +struct _dnsStats DnsStats; + +static int dnsOpenServer(command) + char *command; +{ + int pid; + u_short port; + struct sockaddr_in S; + int cfd; + int sfd; + int len; + int fd; + + cfd = comm_open(COMM_NOCLOEXEC, + local_addr, + 0, + "socket to dnsserver"); + if (cfd == COMM_ERROR) { + debug(34, 0, "dnsOpenServer: Failed to create dnsserver\n"); + return -1; + } + len = sizeof(S); + memset(&S, '\0', len); + if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) { + debug(34, 0, "dnsOpenServer: getsockname: %s\n", xstrerror()); + comm_close(cfd); + return -1; + } + port = ntohs(S.sin_port); + debug(34, 4, "dnsOpenServer: bind to local host.\n"); + listen(cfd, 1); + if ((pid = fork()) < 0) { + debug(34, 0, "dnsOpenServer: fork: %s\n", xstrerror()); + comm_close(cfd); + return -1; + } + if (pid > 0) { /* parent */ + comm_close(cfd); /* close shared socket with child */ + /* open new socket for parent process */ + sfd = comm_open(0, local_addr, 0, NULL); /* blocking! */ + if (sfd == COMM_ERROR) + return -1; + if (comm_connect(sfd, localhost, port) == COMM_ERROR) { + comm_close(sfd); + return -1; + } + comm_set_fd_lifetime(sfd, -1); + return sfd; + } + /* child */ + + no_suid(); /* give up extra priviliges */ + dup2(cfd, 3); + for (fd = FD_SETSIZE; fd > 3; fd--) + close(fd); + execlp(command, "(dnsserver)", "-t", NULL); + debug(34, 0, "dnsOpenServer: %s: %s\n", command, xstrerror()); + _exit(1); + return 0; +} + +dnsserver_t *dnsGetFirstAvailable() +{ + int k; + dnsserver_t *dns = NULL; + for (k = 0; k < NDnsServersAlloc; k++) { + dns = *(dns_child_table + k); + if (!(dns->flags & DNS_FLAG_BUSY)) + return dns; + } + return NULL; +} + + +void dnsOpenServers() +{ + int N = getDnsChildren(); + char *prg = getDnsProgram(); + int k; + int dnssocket; + LOCAL_ARRAY(char, fd_note_buf, FD_ASCII_NOTE_SZ); + + /* free old structures if present */ + if (dns_child_table) { + for (k = 0; k < NDnsServersAlloc; k++) { + safe_free(dns_child_table[k]->ip_inbuf); + safe_free(dns_child_table[k]); + } + safe_free(dns_child_table); + } + dns_child_table = xcalloc(N, sizeof(dnsserver_t *)); + NDnsServersAlloc = N; + debug(34, 1, "dnsOpenServers: Starting %d 'dns_server' processes\n", N); + for (k = 0; k < N; k++) { + dns_child_table[k] = xcalloc(1, sizeof(dnsserver_t)); + if ((dnssocket = dnsOpenServer(prg)) < 0) { + debug(34, 1, "dnsOpenServers: WARNING: Cannot run 'dnsserver' process.\n"); + debug(34, 1, " Fallling back to the blocking version.\n"); + dns_child_table[k]->flags &= ~DNS_FLAG_ALIVE; + } else { + debug(34, 4, "dnsOpenServers: FD %d connected to %s #%d.\n", + dnssocket, prg, k + 1); + dns_child_table[k]->flags |= DNS_FLAG_ALIVE; + dns_child_table[k]->id = k + 1; + dns_child_table[k]->inpipe = dnssocket; + dns_child_table[k]->outpipe = dnssocket; + dns_child_table[k]->lastcall = squid_curtime; + dns_child_table[k]->size = DNS_INBUF_SZ - 1; + dns_child_table[k]->offset = 0; + dns_child_table[k]->ip_inbuf = xcalloc(DNS_INBUF_SZ, 1); + + /* update fd_stat */ + + sprintf(fd_note_buf, "%s #%d", prg, dns_child_table[k]->id); + fd_note(dns_child_table[k]->inpipe, fd_note_buf); + commSetNonBlocking(dns_child_table[k]->inpipe); + debug(34, 3, "dnsOpenServers: 'dns_server' %d started\n", k); + } + } +} + + +void dnsStats(sentry) + StoreEntry *sentry; +{ + int k; + + storeAppendPrintf(sentry, "{DNSServer Statistics:\n"); + storeAppendPrintf(sentry, "{dnsserver requests: %d}\n", + DnsStats.requests); + storeAppendPrintf(sentry, "{dnsserver replies: %d}\n", + DnsStats.replies); + storeAppendPrintf(sentry, "{number of dnsservers: %d}\n", + NDnsServersAlloc); + storeAppendPrintf(sentry, "{dnsservers use histogram:}\n"); + for (k = 0; k < NDnsServersAlloc; k++) { + storeAppendPrintf(sentry, "{ dnsserver #%d: %d}\n", + k + 1, + DnsStats.hist[k]); + } + storeAppendPrintf(sentry, "}\n\n"); + storeAppendPrintf(sentry, close_bracket); +} + +void dnsShutdownServers() +{ + dnsserver_t *dnsData = NULL; + int k; + static char *shutdown = "$shutdown\n"; + + debug(34, 3, "dnsShutdownServers:\n"); + + for (k = 0; k < NDnsServersAlloc; k++) { + dnsData = *(dns_child_table + k); + if (!(dnsData->flags & DNS_FLAG_ALIVE)) + continue; + if (dnsData->flags & DNS_FLAG_BUSY) + continue; + if (dnsData->flags & DNS_FLAG_CLOSING) + continue; + debug(34, 3, "dnsShutdownServers: sending '$shutdown' to dnsserver #%d\n", dnsData->id); + debug(34, 3, "dnsShutdownServers: --> FD %d\n", dnsData->outpipe); + comm_write(dnsData->outpipe, + xstrdup(shutdown), + strlen(shutdown), + 0, /* timeout */ + NULL, /* Handler */ + NULL, /* Handler-data */ + xfree); + dnsData->flags |= DNS_FLAG_CLOSING; + } +} diff --git a/src/dnsserver.cc b/src/dnsserver.cc index 39ce74a7d3..28a6b5a0e2 100644 --- a/src/dnsserver.cc +++ b/src/dnsserver.cc @@ -1,6 +1,6 @@ /* - * $Id: dnsserver.cc,v 1.8 1996/07/09 04:47:18 wessels Exp $ + * $Id: dnsserver.cc,v 1.9 1996/07/22 16:40:23 wessels Exp $ * * DEBUG: section 0 DNS Resolver * AUTHOR: Harvest Derived @@ -231,6 +231,8 @@ int main(argc, argv) close(fd); } while (1) { + int retry_count = 0; + int addrbuf; memset(request, '\0', 256); /* read from ipcache */ @@ -249,8 +251,11 @@ int main(argc, argv) fflush(stdout); continue; } + result = NULL; + start = time(NULL); /* check if it's already an IP address in text form. */ if (inet_addr(request) != INADDR_NONE) { +#if NO_REVERSE_LOOKUP printf("$name %s\n", request); printf("$h_name %s\n", request); printf("$h_len %d\n", 4); @@ -260,13 +265,24 @@ int main(argc, argv) printf("$end\n"); fflush(stdout); continue; - } - start = time(NULL); - result = gethostbyname(request); - if (!result) { - if (h_errno == TRY_AGAIN) { +#endif + addrbuf = inet_addr(request); + for (;;) { + result = gethostbyaddr(&addrbuf, 4, AF_INET); + if (result || h_errno != TRY_AGAIN) + break; + if (++retry_count == 2) + break; + sleep(2); + } + } else { + for (;;) { + result = gethostbyname(request); + if (result || h_errno != TRY_AGAIN) + break; + if (++retry_count == 2) + break; sleep(2); - result = gethostbyname(request); /* try a little harder */ } } stop = time(NULL); @@ -321,7 +337,6 @@ int main(argc, argv) continue; } } - exit(0); /*NOTREACHED */ return 0; diff --git a/src/fqdncache.cc b/src/fqdncache.cc new file mode 100644 index 0000000000..ad350c02c9 --- /dev/null +++ b/src/fqdncache.cc @@ -0,0 +1,1026 @@ + +/* + * $Id: fqdncache.cc,v 1.1 1996/07/22 16:40:24 wessels Exp $ + * + * DEBUG: section 34 FQDN Cache + * AUTHOR: Harvest Derived + * + * SQUID Internet Object Cache http://www.nlanr.net/Squid/ + * -------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by + * the National Science Foundation. + * + * 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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Copyright (c) 1994, 1995. All rights reserved. + * + * The Harvest software was developed by the Internet Research Task + * Force Research Group on Resource Discovery (IRTF-RD): + * + * Mic Bowman of Transarc Corporation. + * Peter Danzig of the University of Southern California. + * Darren R. Hardy of the University of Colorado at Boulder. + * Udi Manber of the University of Arizona. + * Michael F. Schwartz of the University of Colorado at Boulder. + * Duane Wessels of the University of Colorado at Boulder. + * + * This copyright notice applies to software in the Harvest + * ``src/'' directory only. Users should consult the individual + * copyright notices in the ``components/'' subdirectories for + * copyright information about other software bundled with the + * Harvest source code distribution. + * + * TERMS OF USE + * + * The Harvest software may be used and re-distributed without + * charge, provided that the software origin and research team are + * cited in any use of the system. Most commonly this is + * accomplished by including a link to the Harvest Home Page + * (http://harvest.cs.colorado.edu/) from the query page of any + * Broker you deploy, as well as in the query result pages. These + * links are generated automatically by the standard Broker + * software distribution. + * + * The Harvest software is provided ``as is'', without express or + * implied warranty, and with no support nor obligation to assist + * in its use, correction, modification or enhancement. We assume + * no liability with respect to the infringement of copyrights, + * trade secrets, or any patents, and are not responsible for + * consequential damages. Proper use of the Harvest software is + * entirely the responsibility of the user. + * + * DERIVATIVE WORKS + * + * Users may make derivative works from the Harvest software, subject + * to the following constraints: + * + * - You must include the above copyright notice and these + * accompanying paragraphs in all forms of derivative works, + * and any documentation and other materials related to such + * distribution and use acknowledge that the software was + * developed at the above institutions. + * + * - You must notify IRTF-RD regarding your distribution of + * the derivative work. + * + * - You must clearly notify users that your are distributing + * a modified version and not the original Harvest software. + * + * - Any derivative product is also subject to these copyright + * and use restrictions. + * + * Note that the Harvest software is NOT in the public domain. We + * retain copyright, as specified above. + * + * HISTORY OF FREE SOFTWARE STATUS + * + * Originally we required sites to license the software in cases + * where they were going to build commercial products/services + * around Harvest. In June 1995 we changed this policy. We now + * allow people to use the core Harvest software (the code found in + * the Harvest ``src/'' directory) for free. We made this change + * in the interest of encouraging the widest possible deployment of + * the technology. The Harvest software is really a reference + * implementation of a set of protocols and formats, some of which + * we intend to standardize. We encourage commercial + * re-implementations of code complying to this set of standards. + */ + +#include "squid.h" + +#define MAX_LINELEN (4096) + +#define MAX_FQDN 1024 /* Maximum cached FQDN */ +#define FQDN_LOW_WATER 90 +#define FQDN_HIGH_WATER 95 +#define MAX_HOST_NAME 256 + +struct _fqdn_pending { + int fd; + FQDNH handler; + void *handlerData; + struct _fqdn_pending *next; +}; + +struct fqdncacheQueueData { + struct fqdncacheQueueData *next; + fqdncache_entry *f; +}; + +static struct { + int requests; + int replies; + int hits; + int misses; + int pending_hits; + int negative_hits; + int errors; + int avg_svc_time; + int ghba_calls; /* # calls to blocking gethostbyaddr() */ +} FqdncacheStats; + +typedef struct _line_entry { + char *line; + struct _line_entry *next; +} line_entry; + +static int fqdncache_compareLastRef _PARAMS((fqdncache_entry **, fqdncache_entry **)); +static int fqdncache_dnsHandleRead _PARAMS((int, dnsserver_t *)); +static int fqdncache_parsebuffer _PARAMS((char *buf, unsigned int offset, dnsserver_t *)); +static int fqdncache_purgelru _PARAMS((void)); +static void fqdncache_release _PARAMS((fqdncache_entry *)); +static fqdncache_entry *fqdncache_GetFirst _PARAMS((void)); +static fqdncache_entry *fqdncache_GetNext _PARAMS((void)); +static fqdncache_entry *fqdncache_create _PARAMS((void)); +static void free_lines _PARAMS((line_entry *)); +static void fqdncache_add_to_hash _PARAMS((fqdncache_entry *)); +static void fqdncache_call_pending _PARAMS((fqdncache_entry *)); +static void fqdncache_call_pending_badname _PARAMS((int fd, FQDNH handler, void *)); +static void fqdncache_add _PARAMS((char *, fqdncache_entry *, struct hostent *, int)); +static int fqdncacheHasPending _PARAMS((fqdncache_entry *)); +static fqdncache_entry *fqdncache_get _PARAMS((char *)); +static void dummy_handler _PARAMS((int, char *, void *)); +static int fqdncacheExpiredEntry _PARAMS((fqdncache_entry *)); +static void fqdncacheAddPending _PARAMS((fqdncache_entry *, int fd, FQDNH, void *)); +static void fqdncacheEnqueue _PARAMS((fqdncache_entry *)); +static void *fqdncacheDequeue _PARAMS((void)); +static void fqdncache_dnsDispatch _PARAMS((dnsserver_t *, fqdncache_entry *)); + +static struct hostent *static_result = NULL; +static HashID fqdn_table = 0; +static struct fqdncacheQueueData *fqdncacheQueueHead = NULL; +static struct fqdncacheQueueData **fqdncacheQueueTailP = &fqdncacheQueueHead; + +static char fqdncache_status_char[] = +{ + 'C', + 'N', + 'P', + 'D' +}; + +long fqdncache_low = 180; +long fqdncache_high = 200; + +static void fqdncacheEnqueue(f) + fqdncache_entry *f; +{ + struct fqdncacheQueueData *new = xcalloc(1, sizeof(struct fqdncacheQueueData)); + new->f = f; + *fqdncacheQueueTailP = new; + fqdncacheQueueTailP = &new->next; +} + +static void *fqdncacheDequeue() +{ + struct fqdncacheQueueData *old = NULL; + fqdncache_entry *f = NULL; + if (fqdncacheQueueHead) { + f = fqdncacheQueueHead->f; + old = fqdncacheQueueHead; + fqdncacheQueueHead = fqdncacheQueueHead->next; + if (fqdncacheQueueHead == NULL) + fqdncacheQueueTailP = &fqdncacheQueueHead; + safe_free(old); + } + return f; +} + +/* removes the given fqdncache entry */ +static void fqdncache_release(f) + fqdncache_entry *f; +{ + fqdncache_entry *result = NULL; + hash_link *table_entry = NULL; + int k; + + if ((table_entry = hash_lookup(fqdn_table, f->name)) == NULL) { + debug(34, 0, "fqdncache_release: Could not find key '%s'\n", f->name); + return; + } + result = (fqdncache_entry *) table_entry; + if (f != result) + fatal_dump("fqdncache_release: expected f == result!"); + if (f->status == FQDN_PENDING) { + debug(34, 1, "fqdncache_release: Someone called on a PENDING entry\n"); + return; + } + if (f->status == FQDN_DISPATCHED) { + debug(34, 1, "fqdncache_release: Someone called on a DISPATCHED entry\n"); + return; + } + if (hash_remove_link(fqdn_table, table_entry)) { + debug(34, 0, "fqdncache_release: hash_remove_link() failed for '%s'\n", + result->name); + return; + } + if (result->status == FQDN_CACHED) { + for (k = 0; k < (int) f->name_count; k++) + safe_free(f->names[k]); + debug(34, 5, "fqdncache_release: Released FQDN record for '%s'.\n", + result->name); + } + safe_free(result->name); + safe_free(result->error_message); + memset(result, '\0', sizeof(fqdncache_entry)); + safe_free(result); + --meta_data.fqdncache_count; + return; +} + +/* return match for given name */ +static fqdncache_entry *fqdncache_get(name) + char *name; +{ + hash_link *e; + static fqdncache_entry *f; + + f = NULL; + if (fqdn_table) { + if ((e = hash_lookup(fqdn_table, name)) != NULL) + f = (fqdncache_entry *) e; + } + return f; +} + +static fqdncache_entry *fqdncache_GetFirst() +{ + return (fqdncache_entry *) hash_first(fqdn_table); +} + +static fqdncache_entry *fqdncache_GetNext() +{ + return (fqdncache_entry *) hash_next(fqdn_table); +} + +static int fqdncache_compareLastRef(e1, e2) + fqdncache_entry **e1, **e2; +{ + if (!e1 || !e2) + fatal_dump(NULL); + if ((*e1)->lastref > (*e2)->lastref) + return (1); + if ((*e1)->lastref < (*e2)->lastref) + return (-1); + return (0); +} + +static int fqdncacheExpiredEntry(f) + fqdncache_entry *f; +{ + if (f->status == FQDN_PENDING) + return 0; + if (f->status == FQDN_DISPATCHED) + return 0; + if (f->ttl + f->timestamp > squid_curtime) + return 0; + return 1; +} + +/* finds the LRU and deletes */ +static int fqdncache_purgelru() +{ + fqdncache_entry *f = NULL; + int local_fqdn_count = 0; + int local_fqdn_notpending_count = 0; + int removed = 0; + int k; + fqdncache_entry **LRU_list = NULL; + int LRU_list_count = 0; + int LRU_cur_size = meta_data.fqdncache_count; + + LRU_list = xcalloc(LRU_cur_size, sizeof(fqdncache_entry *)); + + for (f = fqdncache_GetFirst(); f; f = fqdncache_GetNext()) { + if (fqdncacheExpiredEntry(f)) { + fqdncache_release(f); + removed++; + continue; + } + local_fqdn_count++; + + if (LRU_list_count >= LRU_cur_size) { + /* have to realloc */ + LRU_cur_size += 16; + debug(34, 3, "fqdncache_purgelru: Have to grow LRU_list to %d. This shouldn't happen.\n", + LRU_cur_size); + LRU_list = xrealloc((char *) LRU_list, + LRU_cur_size * sizeof(fqdncache_entry *)); + } + if (f->status == FQDN_PENDING) + continue; + if (f->status == FQDN_DISPATCHED) + continue; + local_fqdn_notpending_count++; + LRU_list[LRU_list_count++] = f; + } + + debug(34, 3, "fqdncache_purgelru: fqdncache_count: %5d\n", meta_data.fqdncache_count); + debug(34, 3, " actual count : %5d\n", local_fqdn_count); + debug(34, 3, " high W mark : %5d\n", fqdncache_high); + debug(34, 3, " low W mark : %5d\n", fqdncache_low); + debug(34, 3, " not pending : %5d\n", local_fqdn_notpending_count); + debug(34, 3, " LRU candidates : %5d\n", LRU_list_count); + + /* sort LRU candidate list */ + qsort((char *) LRU_list, + LRU_list_count, + sizeof(f), + (int (*)(const void *, const void *)) fqdncache_compareLastRef); + for (k = 0; LRU_list[k] && (meta_data.fqdncache_count > fqdncache_low) + && k < LRU_list_count; + ++k) { + fqdncache_release(LRU_list[k]); + removed++; + } + + debug(34, 3, " removed : %5d\n", removed); + safe_free(LRU_list); + return (removed > 0) ? 0 : -1; +} + + +/* create blank fqdncache_entry */ +static fqdncache_entry *fqdncache_create() +{ + static fqdncache_entry *new; + + if (meta_data.fqdncache_count > fqdncache_high) { + if (fqdncache_purgelru() < 0) + debug(34, 0, "HELP!! FQDN Cache is overflowing!\n"); + } + meta_data.fqdncache_count++; + new = xcalloc(1, sizeof(fqdncache_entry)); + return new; + +} + +static void fqdncache_add_to_hash(f) + fqdncache_entry *f; +{ + if (hash_join(fqdn_table, (hash_link *) f)) { + debug(34, 1, "fqdncache_add_to_hash: Cannot add %s (%p) to hash table %d.\n", + f->name, f, fqdn_table); + } + debug(34, 5, "fqdncache_add_to_hash: name <%s>\n", f->name); +} + + +static void fqdncache_add(name, f, hp, cached) + char *name; + fqdncache_entry *f; + struct hostent *hp; + int cached; +{ + int k; + + if (fqdncache_get(name)) + fatal_dump("fqdncache_add: somebody adding a duplicate!"); + debug(34, 10, "fqdncache_add: Adding name '%s' (%s).\n", name, + cached ? "cached" : "not cached"); + f->name = xstrdup(name); + if (cached) { + f->name_count = 0; + f->names[f->name_count++] = xstrdup(hp->h_name); + for (k = 0; hp->h_aliases[k]; k++) { + f->names[f->name_count++] = xstrdup(hp->h_aliases[k]); + if (f->name_count == FQDN_MAX_NAMES) + break; + } + f->lastref = f->timestamp = squid_curtime; + f->status = FQDN_CACHED; + f->ttl = DnsPositiveTtl; + } else { + f->lastref = f->timestamp = squid_curtime; + f->status = FQDN_NEGATIVE_CACHED; + f->ttl = getNegativeDNSTTL(); + } + fqdncache_add_to_hash(f); +} + +/* walks down the pending list, calling handlers */ +static void fqdncache_call_pending(f) + fqdncache_entry *f; +{ + struct _fqdn_pending *p = NULL; + int nhandler = 0; + + f->lastref = squid_curtime; + + while (f->pending_head != NULL) { + p = f->pending_head; + f->pending_head = p->next; + if (p->handler) { + nhandler++; + dns_error_message = f->error_message; + p->handler(p->fd, + (f->status == FQDN_CACHED) ? f->names[0] : NULL, + p->handlerData); + } + memset(p, '\0', sizeof(struct _fqdn_pending)); + safe_free(p); + } + f->pending_head = NULL; /* nuke list */ + debug(34, 10, "fqdncache_call_pending: Called %d handlers.\n", nhandler); +} + +static void fqdncache_call_pending_badname(fd, handler, data) + int fd; + FQDNH handler; + void *data; +{ + debug(34, 0, "fqdncache_call_pending_badname: Bad Name: Calling handler with NULL result.\n"); + handler(fd, NULL, data); +} + +/* free all lines in the list */ +static void free_lines(line) + line_entry *line; +{ + line_entry *tmp; + + while (line) { + tmp = line; + line = line->next; + safe_free(tmp->line); + safe_free(tmp); + } +} + +/* scan through buffer and do a conversion if possible + * return number of char used */ +static int fqdncache_parsebuffer(buf, offset, dnsData) + char *buf; + unsigned int offset; + dnsserver_t *dnsData; +{ + char *pos = NULL; + char *tpos = NULL; + char *endpos = NULL; + char *token = NULL; + char *tmp_ptr = NULL; + line_entry *line_head = NULL; + line_entry *line_tail = NULL; + line_entry *line_cur = NULL; + int ipcount; + int aliascount; + fqdncache_entry *f = NULL; + + + pos = buf; + while (pos < (buf + offset)) { + + /* no complete record here */ + if ((endpos = strstr(pos, "$end\n")) == NULL) { + debug(34, 2, "fqdncache_parsebuffer: DNS response incomplete.\n"); + break; + } + line_head = line_tail = NULL; + + while (pos < endpos) { + /* add the next line to the end of the list */ + line_cur = xcalloc(1, sizeof(line_entry)); + + if ((tpos = memchr(pos, '\n', 4096)) == NULL) { + debug(34, 2, "fqdncache_parsebuffer: DNS response incomplete.\n"); + return -1; + } + *tpos = '\0'; + line_cur->line = xstrdup(pos); + debug(34, 7, "fqdncache_parsebuffer: %s\n", line_cur->line); + *tpos = '\n'; + + if (line_tail) + line_tail->next = line_cur; + if (line_head == NULL) + line_head = line_cur; + line_tail = line_cur; + line_cur = NULL; + + /* update pointer */ + pos = tpos + 1; + } + pos = endpos + 5; /* strlen("$end\n") */ + + /* + * At this point, the line_head is a linked list with each + * link node containing another line of the DNS response. + * Start parsing... + */ + if (strstr(line_head->line, "$alive")) { + dnsData->answer = squid_curtime; + free_lines(line_head); + debug(34, 10, "fqdncache_parsebuffer: $alive succeeded.\n"); + } else if (strstr(line_head->line, "$fail")) { + /* + * The $fail messages look like: + * $fail host\n$message msg\n$end\n + */ + token = strtok(line_head->line, w_space); /* skip first token */ + if ((token = strtok(NULL, w_space)) == NULL) { + debug(34, 1, "fqdncache_parsebuffer: Invalid $fail?\n"); + } else { + line_cur = line_head->next; + f = dnsData->data; + f->lastref = f->timestamp = squid_curtime; + f->ttl = getNegativeDNSTTL(); + f->status = FQDN_NEGATIVE_CACHED; + if (line_cur && !strncmp(line_cur->line, "$message", 8)) + f->error_message = xstrdup(line_cur->line + 8); + dns_error_message = f->error_message; + fqdncache_call_pending(f); + } + free_lines(line_head); + } else if (strstr(line_head->line, "$name")) { + tmp_ptr = line_head->line; + /* skip the first token */ + token = strtok(tmp_ptr, w_space); + if ((token = strtok(NULL, w_space)) == NULL) { + debug(34, 0, "fqdncache_parsebuffer: Invalid OPCODE?\n"); + } else { + f = dnsData->data; + if (f->status != FQDN_DISPATCHED) { + debug(34, 0, "fqdncache_parsebuffer: DNS record already resolved.\n"); + } else { + f->lastref = f->timestamp = squid_curtime; + f->ttl = DnsPositiveTtl; + f->status = FQDN_CACHED; + + line_cur = line_head->next; + + /* get $h_name */ + if (line_cur == NULL || + !strstr(line_cur->line, "$h_name")) { + debug(34, 1, "fqdncache_parsebuffer: DNS record in invalid format? No $h_name.\n"); + /* abandon this record */ + break; + } + tmp_ptr = line_cur->line; + /* skip the first token */ + token = strtok(tmp_ptr, w_space); + tmp_ptr = NULL; + token = strtok(tmp_ptr, w_space); + f->names[0] = xstrdup(token); + f->name_count = 1; + + line_cur = line_cur->next; + + /* get $h_length */ + if (line_cur == NULL || + !strstr(line_cur->line, "$h_len")) { + debug(34, 1, "fqdncache_parsebuffer: DNS record in invalid format? No $h_len.\n"); + /* abandon this record */ + break; + } + tmp_ptr = line_cur->line; + /* skip the first token */ + token = strtok(tmp_ptr, w_space); + tmp_ptr = NULL; + token = strtok(tmp_ptr, w_space); + + line_cur = line_cur->next; + + /* get $ipcount */ + if (line_cur == NULL || + !strstr(line_cur->line, "$ipcount")) { + debug(34, 1, "fqdncache_parsebuffer: DNS record in invalid format? No $ipcount.\n"); + /* abandon this record */ + break; + } + tmp_ptr = line_cur->line; + /* skip the first token */ + token = strtok(tmp_ptr, w_space); + tmp_ptr = NULL; + token = strtok(tmp_ptr, w_space); + ipcount = atoi(token); + + /* get ip addresses */ + { + int k = 0; + line_cur = line_cur->next; + while (k < ipcount) { + if (line_cur == NULL) { + debug(34, 1, "fqdncache_parsebuffer: DNS record in invalid format? No $ipcount data.\n"); + break; + } + line_cur = line_cur->next; + k++; + } + } + + /* get $aliascount */ + if (line_cur == NULL || + !strstr(line_cur->line, "$aliascount")) { + debug(34, 1, "fqdncache_parsebuffer: DNS record in invalid format? No $aliascount.\n"); + /* abandon this record */ + break; + } + tmp_ptr = line_cur->line; + /* skip the first token */ + token = strtok(tmp_ptr, w_space); + tmp_ptr = NULL; + token = strtok(tmp_ptr, w_space); + aliascount = atoi(token); + + /* get aliases */ + { + int k = 0; + line_cur = line_cur->next; + while (k < aliascount) { + if (line_cur == NULL) { + debug(34, 1, "fqdncache_parsebuffer: DNS record in invalid format? No $aliascount data.\n"); + break; + } + if (f->name_count < FQDN_MAX_NAMES) + f->names[f->name_count++] = xstrdup(line_cur->line); + line_cur = line_cur->next; + k++; + } + } + fqdncache_call_pending(f); + debug(34, 10, "fqdncache_parsebuffer: $name succeeded.\n"); + } + } + free_lines(line_head); + } else { + free_lines(line_head); + debug(34, 1, "fqdncache_parsebuffer: Invalid OPCODE for DNS table?\n"); + return -1; + } + } + return (int) (pos - buf); +} + + +static int fqdncache_dnsHandleRead(fd, dnsData) + int fd; + dnsserver_t *dnsData; +{ + int char_scanned; + int len; + int svc_time; + int n; + fqdncache_entry *f = NULL; + + len = read(fd, + dnsData->ip_inbuf + dnsData->offset, + dnsData->size - dnsData->offset); + debug(34, 5, "fqdncache_dnsHandleRead: Result from DNS ID %d (%d bytes)\n", + dnsData->id, len); + if (len <= 0) { + debug(34, dnsData->flags & DNS_FLAG_CLOSING ? 5 : 1, + "FD %d: Connection from DNSSERVER #%d is closed, disabling\n", + fd, dnsData->id); + dnsData->flags = 0; + comm_set_select_handler(fd, + COMM_SELECT_WRITE, + NULL, + NULL); + comm_close(fd); + return 0; + } + n = ++FqdncacheStats.replies; + dnsData->offset += len; + dnsData->ip_inbuf[dnsData->offset] = '\0'; + + if (strstr(dnsData->ip_inbuf, "$end\n")) { + /* end of record found */ + svc_time = tvSubMsec(dnsData->dispatch_time, current_time); + if (n > FQDNCACHE_AV_FACTOR) + n = FQDNCACHE_AV_FACTOR; + FqdncacheStats.avg_svc_time + = (FqdncacheStats.avg_svc_time * (n - 1) + svc_time) / n; + char_scanned = fqdncache_parsebuffer(dnsData->ip_inbuf, + dnsData->offset, + dnsData); + if (char_scanned > 0) { + /* update buffer */ + xmemcpy(dnsData->ip_inbuf, + dnsData->ip_inbuf + char_scanned, + dnsData->offset - char_scanned); + dnsData->offset -= char_scanned; + dnsData->ip_inbuf[dnsData->offset] = '\0'; + } + } + if (dnsData->offset == 0) { + dnsData->data = NULL; + dnsData->flags &= ~DNS_FLAG_BUSY; + } + while ((dnsData = dnsGetFirstAvailable()) && (f = fqdncacheDequeue())) + fqdncache_dnsDispatch(dnsData, f); + return 0; +} + +static void fqdncacheAddPending(f, fd, handler, handlerData) + fqdncache_entry *f; + int fd; + FQDNH handler; + void *handlerData; +{ + struct _fqdn_pending *pending = xcalloc(1, sizeof(struct _fqdn_pending)); + struct _fqdn_pending **I = NULL; + + pending->fd = fd; + pending->handler = handler; + pending->handlerData = handlerData; + + for (I = &(f->pending_head); *I; I = &((*I)->next)); + *I = pending; +} + +int fqdncache_nbgethostbyaddr(addr, fd, handler, handlerData) + struct in_addr addr; + int fd; + FQDNH handler; + void *handlerData; +{ + fqdncache_entry *f = NULL; + dnsserver_t *dnsData = NULL; + char *name = inet_ntoa(addr); + + if (!handler) + fatal_dump("fqdncache_nbgethostbyaddr: NULL handler"); + + debug(34, 4, "fqdncache_nbgethostbyaddr: FD %d: Name '%s'.\n", fd, name); + FqdncacheStats.requests++; + + if (name == NULL || name[0] == '\0') { + debug(34, 4, "fqdncache_nbgethostbyaddr: Invalid name!\n"); + fqdncache_call_pending_badname(fd, handler, handlerData); + return 0; + } + if ((f = fqdncache_get(name))) { + if (fqdncacheExpiredEntry(f)) { + fqdncache_release(f); + f = NULL; + } + } + if (f == NULL) { + /* MISS: No entry, create the new one */ + debug(34, 5, "fqdncache_nbgethostbyaddr: MISS for '%s'\n", name); + FqdncacheStats.misses++; + f = fqdncache_create(); + f->name = xstrdup(name); + f->status = FQDN_PENDING; + fqdncacheAddPending(f, fd, handler, handlerData); + fqdncache_add_to_hash(f); + } else if (f->status == FQDN_CACHED || f->status == FQDN_NEGATIVE_CACHED) { + /* HIT */ + debug(34, 4, "fqdncache_nbgethostbyaddr: HIT for '%s'\n", name); + if (f->status == FQDN_NEGATIVE_CACHED) + FqdncacheStats.negative_hits++; + else + FqdncacheStats.hits++; + fqdncacheAddPending(f, fd, handler, handlerData); + fqdncache_call_pending(f); + return 0; + } else if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) { + debug(34, 4, "fqdncache_nbgethostbyaddr: PENDING for '%s'\n", name); + FqdncacheStats.pending_hits++; + fqdncacheAddPending(f, fd, handler, handlerData); + return 0; + } else { + fatal_dump("fqdncache_nbgethostbyaddr: BAD fqdncache_entry status"); + } + + /* for HIT, PENDING, DISPATCHED we've returned. For MISS we continue */ + + if ((dnsData = dnsGetFirstAvailable())) + fqdncache_dnsDispatch(dnsData, f); + else + fqdncacheEnqueue(f); + return 0; +} + +static void fqdncache_dnsDispatch(dns, f) + dnsserver_t *dns; + fqdncache_entry *f; +{ + char *buf = NULL; + if (!fqdncacheHasPending(f)) { + debug(34, 0, "fqdncache_dnsDispatch: skipping '%s' because no handler.\n", + f->name); + f->status = FQDN_NEGATIVE_CACHED; + fqdncache_release(f); + return; + } + f->status = FQDN_DISPATCHED; + buf = xcalloc(1, 256); + sprintf(buf, "%1.254s\n", f->name); + dns->flags |= DNS_FLAG_BUSY; + dns->data = f; + comm_write(dns->outpipe, + buf, + strlen(buf), + 0, /* timeout */ + NULL, /* Handler */ + NULL, /* Handler-data */ + xfree); + comm_set_select_handler(dns->outpipe, + COMM_SELECT_READ, + (PF) fqdncache_dnsHandleRead, + dns); + debug(34, 5, "fqdncache_dnsDispatch: Request sent to DNS server #%d.\n", + dns->id); + dns->dispatch_time = current_time; + DnsStats.requests++; + DnsStats.hist[dns->id - 1]++; +} + + +/* initialize the fqdncache */ +void fqdncache_init() +{ + + debug(34, 3, "Initializing FQDN Cache...\n"); + + memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats)); + + fqdn_table = hash_create(urlcmp, 229, hash_string); /* small hash table */ + /* init static area */ + static_result = xcalloc(1, sizeof(struct hostent)); + static_result->h_length = 4; + static_result->h_addr_list = xcalloc(2, sizeof(char *)); + *(static_result->h_addr_list + 0) = xcalloc(1, 4); + static_result->h_name = xcalloc(1, MAX_HOST_NAME + 1); + + fqdncache_high = (long) (((float) MAX_FQDN * + (float) FQDN_HIGH_WATER) / (float) 100); + fqdncache_low = (long) (((float) MAX_FQDN * + (float) FQDN_LOW_WATER) / (float) 100); +} + +/* clean up the pending entries in dnsserver */ +/* return 1 if we found the host, 0 otherwise */ +int fqdncache_unregister(name, fd) + char *name; + int fd; +{ + fqdncache_entry *f = NULL; + struct _fqdn_pending *p = NULL; + int n = 0; + + debug(34, 3, "fqdncache_unregister: FD %d, name '%s'\n", fd, name); + if ((f = fqdncache_get(name)) == NULL) + return 0; + if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) { + for (p = f->pending_head; p; p = p->next) { + if (p->fd == fd && p->handler != NULL) { + p->handler = NULL; + p->fd = -1; + n++; + } + } + } + debug(34, 3, "fqdncache_unregister: unregistered %d handlers\n", n); + return n; +} + +char *fqdncache_gethostbyaddr(addr, flags) + struct in_addr addr; + int flags; +{ + char *name = inet_ntoa(addr); + fqdncache_entry *f = NULL; + struct hostent *hp = NULL; + unsigned int ip; + + if (!name) + fatal_dump("fqdncache_gethostbyaddr: NULL name"); + FqdncacheStats.requests++; + if ((f = fqdncache_get(name))) { + if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) { + FqdncacheStats.pending_hits++; + return NULL; + } else if (f->status == FQDN_NEGATIVE_CACHED) { + FqdncacheStats.negative_hits++; + dns_error_message = f->error_message; + return NULL; + } else { + FqdncacheStats.hits++; + f->lastref = squid_curtime; + return f->names[0]; + } + } + FqdncacheStats.misses++; + /* check if it's already a FQDN address in text form. */ + if (inet_addr(name) == INADDR_NONE) { + return name; + } + if (flags & FQDN_BLOCKING_LOOKUP) { + FqdncacheStats.ghba_calls++; + ip = inet_addr(name); + hp = gethostbyaddr(&ip, 4, AF_INET); + if (hp && hp->h_name && (hp->h_name[0] != '\0') && fqdn_table) { + /* good address, cached */ + fqdncache_add(name, fqdncache_create(), hp, 1); + f = fqdncache_get(name); + return f->names[0]; + } + /* bad address, negative cached */ + if (fqdn_table) + fqdncache_add(name, fqdncache_create(), hp, 0); + return NULL; + } + if (flags & FQDN_LOOKUP_IF_MISS) + fqdncache_nbgethostbyaddr(addr, -1, dummy_handler, NULL); + return NULL; +} + + +/* process objects list */ +void fqdnStats(sentry) + StoreEntry *sentry; +{ + fqdncache_entry *f = NULL; + int k; + int ttl; + + if (!fqdn_table) + return; + + storeAppendPrintf(sentry, "{FQDN Cache Statistics:\n"); + storeAppendPrintf(sentry, "{FQDNcache Entries: %d}\n", + meta_data.fqdncache_count); + storeAppendPrintf(sentry, "{FQDNcache Requests: %d}\n", + FqdncacheStats.requests); + storeAppendPrintf(sentry, "{FQDNcache Hits: %d}\n", + FqdncacheStats.hits); + storeAppendPrintf(sentry, "{FQDNcache Pending Hits: %d}\n", + FqdncacheStats.pending_hits); + storeAppendPrintf(sentry, "{FQDNcache Negative Hits: %d}\n", + FqdncacheStats.negative_hits); + storeAppendPrintf(sentry, "{FQDNcache Misses: %d}\n", + FqdncacheStats.misses); + storeAppendPrintf(sentry, "{Blocking calls to gethostbyaddr(): %d}\n", + FqdncacheStats.ghba_calls); + storeAppendPrintf(sentry, "{dnsserver avg service time: %d msec}\n", + FqdncacheStats.avg_svc_time); + storeAppendPrintf(sentry, "}\n\n"); + storeAppendPrintf(sentry, "{FQDN Cache Contents:\n\n"); + + for (f = fqdncache_GetFirst(); f; f = fqdncache_GetNext()) { + if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) + ttl = 0; + else + ttl = (f->ttl - squid_curtime + f->timestamp); + storeAppendPrintf(sentry, " {%-32.32s %c %6d %d", + f->name, + fqdncache_status_char[f->status], + ttl, + (int) f->name_count); + for (k = 0; k < (int) f->name_count; k++) + storeAppendPrintf(sentry, " %s", f->names[k]); + storeAppendPrintf(sentry, close_bracket); + } + storeAppendPrintf(sentry, close_bracket); +} + +static void dummy_handler(u1, u2, u3) + int u1; + char *u2; + void *u3; +{ + return; +} + +static int fqdncacheHasPending(f) + fqdncache_entry *f; +{ + struct _fqdn_pending *p = NULL; + if (f->status != FQDN_PENDING) + return 0; + for (p = f->pending_head; p; p = p->next) + if (p->handler) + return 1; + return 0; +} + +void fqdncacheReleaseInvalid(name) + char *name; +{ + fqdncache_entry *f; + if ((f = fqdncache_get(name)) == NULL) + return; + if (f->status != FQDN_NEGATIVE_CACHED) + return; + fqdncache_release(f); +} diff --git a/src/ipcache.cc b/src/ipcache.cc index 725a0e3721..8829083d6e 100644 --- a/src/ipcache.cc +++ b/src/ipcache.cc @@ -1,5 +1,5 @@ /* - * $Id: ipcache.cc,v 1.35 1996/07/20 03:16:53 wessels Exp $ + * $Id: ipcache.cc,v 1.36 1996/07/22 16:40:26 wessels Exp $ * * DEBUG: section 14 IP Cache * AUTHOR: Harvest Derived @@ -111,7 +111,6 @@ #define IP_LOW_WATER 90 #define IP_HIGH_WATER 95 #define MAX_HOST_NAME 256 -#define IP_INBUF_SZ 4096 struct _ip_pending { int fd; @@ -120,36 +119,21 @@ struct _ip_pending { struct _ip_pending *next; }; -#define DNS_FLAG_ALIVE 0x01 -#define DNS_FLAG_BUSY 0x02 -#define DNS_FLAG_CLOSING 0x04 - -typedef struct _dnsserver { - int id; - int flags; - int inpipe; - int outpipe; - time_t lastcall; - time_t answer; - unsigned int offset; - unsigned int size; - char *ip_inbuf; - struct timeval dispatch_time; - ipcache_entry *ip_entry; -} dnsserver_t; +struct ipcacheQueueData { + struct ipcacheQueueData *next; + ipcache_entry *i; +}; static struct { int requests; + int replies; int hits; int misses; int pending_hits; int negative_hits; - int dnsserver_requests; - int dnsserver_replies; int errors; int avg_svc_time; int ghbn_calls; /* # calls to blocking gethostbyname() */ - int dnsserver_hist[DefaultDnsChildrenMax]; } IpcacheStats; typedef struct _line_entry { @@ -157,15 +141,8 @@ typedef struct _line_entry { struct _line_entry *next; } line_entry; -struct dnsQueueData { - struct dnsQueueData *next; - ipcache_entry *ip_entry; -}; - static int ipcache_testname _PARAMS((void)); -static dnsserver_t *dnsGetFirstAvailable _PARAMS((void)); static int ipcache_compareLastRef _PARAMS((ipcache_entry **, ipcache_entry **)); -static int ipcache_create_dnsserver _PARAMS((char *command)); static int ipcache_dnsHandleRead _PARAMS((int, dnsserver_t *)); static int ipcache_parsebuffer _PARAMS((char *buf, unsigned int offset, dnsserver_t *)); static int ipcache_purgelru _PARAMS((void)); @@ -178,24 +155,19 @@ static void ipcache_add_to_hash _PARAMS((ipcache_entry *)); static void ipcache_call_pending _PARAMS((ipcache_entry *)); static void ipcache_call_pending_badname _PARAMS((int fd, IPH handler, void *)); static void ipcache_add _PARAMS((char *, ipcache_entry *, struct hostent *, int)); -static ipcache_entry *dnsDequeue _PARAMS(()); -static void dnsEnqueue _PARAMS((ipcache_entry *)); -static void dnsDispatch _PARAMS((dnsserver_t *, ipcache_entry *)); static int ipcacheHasPending _PARAMS((ipcache_entry *)); static ipcache_entry *ipcache_get _PARAMS((char *)); static int dummy_handler _PARAMS((int, struct hostent * hp, void *)); static int ipcacheExpiredEntry _PARAMS((ipcache_entry *)); static void ipcacheAddPending _PARAMS((ipcache_entry *, int fd, IPH, void *)); +static void ipcacheEnqueue _PARAMS((ipcache_entry *)); +static void *ipcacheDequeue _PARAMS((void)); +static void ipcache_dnsDispatch _PARAMS((dnsserver_t *, ipcache_entry *)); -static dnsserver_t **dns_child_table = NULL; static struct hostent *static_result = NULL; -static int NDnsServersAlloc = 0; -static struct dnsQueueData *dnsQueueHead = NULL; -static struct dnsQueueData **dnsQueueTailP = &dnsQueueHead; static HashID ip_table = 0; -char *dns_error_message = NULL; /* possible error message */ -long ipcache_low = 180; -long ipcache_high = 200; +static struct ipcacheQueueData *ipcacheQueueHead = NULL; +static struct ipcacheQueueData **ipcacheQueueTailP = &ipcacheQueueHead; static char ipcache_status_char[] = { @@ -205,6 +177,33 @@ static char ipcache_status_char[] = 'D' }; +long ipcache_low = 180; +long ipcache_high = 200; + +static void ipcacheEnqueue(i) + ipcache_entry *i; +{ + struct ipcacheQueueData *new = xcalloc(1, sizeof(struct ipcacheQueueData)); + new->i = i; + *ipcacheQueueTailP = new; + ipcacheQueueTailP = &new->next; +} + +static void *ipcacheDequeue() +{ + struct ipcacheQueueData *old = NULL; + ipcache_entry *i = NULL; + if (ipcacheQueueHead) { + i = ipcacheQueueHead->i; + old = ipcacheQueueHead; + ipcacheQueueHead = ipcacheQueueHead->next; + if (ipcacheQueueHead == NULL) + ipcacheQueueTailP = &ipcacheQueueHead; + safe_free(old); + } + return i; +} + static int ipcache_testname() { wordlist *w = NULL; @@ -219,66 +218,6 @@ static int ipcache_testname() return 0; } -/* TCP SOCKET VERSION */ -static int ipcache_create_dnsserver(command) - char *command; -{ - int pid; - u_short port; - struct sockaddr_in S; - int cfd; - int sfd; - int len; - int fd; - - cfd = comm_open(COMM_NOCLOEXEC, - local_addr, - 0, - "socket to dnsserver"); - if (cfd == COMM_ERROR) { - debug(14, 0, "ipcache_create_dnsserver: Failed to create dnsserver\n"); - return -1; - } - len = sizeof(S); - memset(&S, '\0', len); - if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) { - debug(14, 0, "ipcache_create_dnsserver: getsockname: %s\n", xstrerror()); - comm_close(cfd); - return -1; - } - port = ntohs(S.sin_port); - debug(14, 4, "ipcache_create_dnsserver: bind to local host.\n"); - listen(cfd, 1); - if ((pid = fork()) < 0) { - debug(14, 0, "ipcache_create_dnsserver: fork: %s\n", xstrerror()); - comm_close(cfd); - return -1; - } - if (pid > 0) { /* parent */ - comm_close(cfd); /* close shared socket with child */ - /* open new socket for parent process */ - sfd = comm_open(0, local_addr, 0, NULL); /* blocking! */ - if (sfd == COMM_ERROR) - return -1; - if (comm_connect(sfd, localhost, port) == COMM_ERROR) { - comm_close(sfd); - return -1; - } - comm_set_fd_lifetime(sfd, -1); - return sfd; - } - /* child */ - - no_suid(); /* give up extra priviliges */ - dup2(cfd, 3); - for (fd = FD_SETSIZE; fd > 3; fd--) - close(fd); - execlp(command, "(dnsserver)", "-t", NULL); - debug(14, 0, "ipcache_create_dnsserver: %s: %s\n", command, xstrerror()); - _exit(1); - return 0; -} - /* removes the given ipcache entry */ static void ipcache_release(i) ipcache_entry *i; @@ -529,9 +468,6 @@ static void ipcache_add(name, i, hp, cached) ipcache_add_to_hash(i); } - - - /* walks down the pending list, calling handlers */ static void ipcache_call_pending(i) ipcache_entry *i; @@ -655,7 +591,7 @@ static int ipcache_parsebuffer(buf, offset, dnsData) debug(14, 1, "ipcache_parsebuffer: Invalid $fail?\n"); } else { line_cur = line_head->next; - i = dnsData->ip_entry; + i = dnsData->data; i->lastref = i->timestamp = squid_curtime; i->ttl = getNegativeDNSTTL(); i->status = IP_NEGATIVE_CACHED; @@ -672,7 +608,7 @@ static int ipcache_parsebuffer(buf, offset, dnsData) if ((token = strtok(NULL, w_space)) == NULL) { debug(14, 0, "ipcache_parsebuffer: Invalid OPCODE?\n"); } else { - i = dnsData->ip_entry; + i = dnsData->data; if (i->status != IP_DISPATCHED) { debug(14, 0, "ipcache_parsebuffer: DNS record already resolved.\n"); } else { @@ -828,7 +764,7 @@ static int ipcache_dnsHandleRead(fd, dnsData) comm_close(fd); return 0; } - n = ++IpcacheStats.dnsserver_replies; + n = ++IpcacheStats.replies; dnsData->offset += len; dnsData->ip_inbuf[dnsData->offset] = '\0'; @@ -852,7 +788,7 @@ static int ipcache_dnsHandleRead(fd, dnsData) } } if (dnsData->offset == 0) { - dnsData->ip_entry = NULL; + dnsData->data = NULL; dnsData->flags &= ~DNS_FLAG_BUSY; } /* reschedule */ @@ -860,8 +796,8 @@ static int ipcache_dnsHandleRead(fd, dnsData) COMM_SELECT_READ, (PF) ipcache_dnsHandleRead, dnsData); - while ((dnsData = dnsGetFirstAvailable()) && (i = dnsDequeue())) - dnsDispatch(dnsData, i); + while ((dnsData = dnsGetFirstAvailable()) && (i = ipcacheDequeue())) + ipcache_dnsDispatch(dnsData, i); return 0; } @@ -939,66 +875,19 @@ int ipcache_nbgethostbyname(name, fd, handler, handlerData) /* for HIT, PENDING, DISPATCHED we've returned. For MISS we continue */ if ((dnsData = dnsGetFirstAvailable())) - dnsDispatch(dnsData, i); + ipcache_dnsDispatch(dnsData, i); else - dnsEnqueue(i); + ipcacheEnqueue(i); return 0; } -static void dnsEnqueue(i) - ipcache_entry *i; -{ - struct dnsQueueData *new = xcalloc(1, sizeof(struct dnsQueueData)); - new->ip_entry = i; - *dnsQueueTailP = new; - dnsQueueTailP = &new->next; -} - -static ipcache_entry *dnsDequeue() -{ - struct dnsQueueData *old = NULL; - ipcache_entry *i = NULL; - if (dnsQueueHead) { - i = dnsQueueHead->ip_entry; - old = dnsQueueHead; - dnsQueueHead = dnsQueueHead->next; - if (dnsQueueHead == NULL) - dnsQueueTailP = &dnsQueueHead; - safe_free(old); - } -#ifdef SANITY_CHECK - if (i == NULL) { - for (i = ipcache_GetFirst(); i; i = ipcache_GetNext()) { - if (i->status == IP_PENDING) { /* This can't happen */ - debug(14, 0, "IP Cache inconsistency: %s still pending\n", - i->name); - } - } - i = NULL; - } -#endif - return i; -} - -static dnsserver_t *dnsGetFirstAvailable() -{ - int k; - dnsserver_t *dns = NULL; - for (k = 0; k < NDnsServersAlloc; k++) { - dns = *(dns_child_table + k); - if (!(dns->flags & DNS_FLAG_BUSY)) - return dns; - } - return NULL; -} - -static void dnsDispatch(dns, i) +static void ipcache_dnsDispatch(dns, i) dnsserver_t *dns; ipcache_entry *i; { char *buf = NULL; if (!ipcacheHasPending(i)) { - debug(14, 0, "dnsDispatch: skipping '%s' because no handler.\n", + debug(14, 0, "ipcache_dnsDispatch: skipping '%s' because no handler.\n", i->name); i->status = IP_NEGATIVE_CACHED; ipcache_release(i); @@ -1008,7 +897,7 @@ static void dnsDispatch(dns, i) buf = xcalloc(1, 256); sprintf(buf, "%1.254s\n", i->name); dns->flags |= DNS_FLAG_BUSY; - dns->ip_entry = i; + dns->data = i; comm_write(dns->outpipe, buf, strlen(buf), @@ -1016,77 +905,18 @@ static void dnsDispatch(dns, i) NULL, /* Handler */ NULL, /* Handler-data */ xfree); - debug(14, 5, "dnsDispatch: Request sent to DNS server #%d.\n", + comm_set_select_handler(dns->outpipe, + COMM_SELECT_READ, + (PF) ipcache_dnsHandleRead, + dns); + debug(14, 5, "ipcache_dnsDispatch: Request sent to DNS server #%d.\n", dns->id); dns->dispatch_time = current_time; - IpcacheStats.dnsserver_requests++; - IpcacheStats.dnsserver_hist[dns->id - 1]++; + DnsStats.requests++; + DnsStats.hist[dns->id - 1]++; } -void ipcacheOpenServers() -{ - int N = getDnsChildren(); - char *prg = getDnsProgram(); - int k; - int dnssocket; - LOCAL_ARRAY(char, fd_note_buf, FD_ASCII_NOTE_SZ); - - /* free old structures if present */ - if (dns_child_table) { - for (k = 0; k < NDnsServersAlloc; k++) { - safe_free(dns_child_table[k]->ip_inbuf); - safe_free(dns_child_table[k]); - } - safe_free(dns_child_table); - } - dns_child_table = xcalloc(N, sizeof(dnsserver_t *)); - NDnsServersAlloc = N; - debug(14, 1, "ipcacheOpenServers: Starting %d 'dns_server' processes\n", N); - for (k = 0; k < N; k++) { - dns_child_table[k] = xcalloc(1, sizeof(dnsserver_t)); - if ((dnssocket = ipcache_create_dnsserver(prg)) < 0) { - debug(14, 1, "ipcacheOpenServers: WARNING: Cannot run 'dnsserver' process.\n"); - debug(14, 1, " Fallling back to the blocking version.\n"); - dns_child_table[k]->flags &= ~DNS_FLAG_ALIVE; - } else { - debug(14, 4, "ipcacheOpenServers: FD %d connected to %s #%d.\n", - dnssocket, prg, k + 1); - dns_child_table[k]->flags |= DNS_FLAG_ALIVE; - dns_child_table[k]->id = k + 1; - dns_child_table[k]->inpipe = dnssocket; - dns_child_table[k]->outpipe = dnssocket; - dns_child_table[k]->lastcall = squid_curtime; - dns_child_table[k]->size = IP_INBUF_SZ - 1; /* spare one for \0 */ - dns_child_table[k]->offset = 0; - dns_child_table[k]->ip_inbuf = xcalloc(IP_INBUF_SZ, 1); - - /* update fd_stat */ - - sprintf(fd_note_buf, "%s #%d", prg, dns_child_table[k]->id); - fd_note(dns_child_table[k]->inpipe, fd_note_buf); - commSetNonBlocking(dns_child_table[k]->inpipe); - - /* clear unused handlers */ - comm_set_select_handler(dns_child_table[k]->inpipe, - COMM_SELECT_WRITE, - 0, - 0); - comm_set_select_handler(dns_child_table[k]->outpipe, - COMM_SELECT_READ, - 0, - 0); - - /* set handler for incoming result */ - comm_set_select_handler(dns_child_table[k]->inpipe, - COMM_SELECT_READ, - (PF) ipcache_dnsHandleRead, - (void *) dns_child_table[k]); - debug(14, 3, "ipcacheOpenServers: 'dns_server' %d started\n", k); - } - } -} - /* initialize the ipcache */ void ipcache_init() { @@ -1112,8 +942,6 @@ void ipcache_init() *(static_result->h_addr_list + 0) = xcalloc(1, 4); static_result->h_name = xcalloc(1, MAX_HOST_NAME + 1); - ipcacheOpenServers(); - ipcache_high = (long) (((float) MAX_IP * (float) IP_HIGH_WATER) / (float) 100); ipcache_low = (long) (((float) MAX_IP * @@ -1224,20 +1052,8 @@ void stat_ipcache_get(sentry) IpcacheStats.misses); storeAppendPrintf(sentry, "{Blocking calls to gethostbyname(): %d}\n", IpcacheStats.ghbn_calls); - storeAppendPrintf(sentry, "{dnsserver requests: %d}\n", - IpcacheStats.dnsserver_requests); - storeAppendPrintf(sentry, "{dnsserver replies: %d}\n", - IpcacheStats.dnsserver_replies); storeAppendPrintf(sentry, "{dnsserver avg service time: %d msec}\n", IpcacheStats.avg_svc_time); - storeAppendPrintf(sentry, "{number of dnsservers: %d}\n", - getDnsChildren()); - storeAppendPrintf(sentry, "{dnsservers use histogram:}\n"); - for (k = 0; k < getDnsChildren(); k++) { - storeAppendPrintf(sentry, "{ dnsserver #%d: %d}\n", - k + 1, - IpcacheStats.dnsserver_hist[k]); - } storeAppendPrintf(sentry, "}\n\n"); storeAppendPrintf(sentry, "{IP Cache Contents:\n\n"); @@ -1267,35 +1083,6 @@ void stat_ipcache_get(sentry) storeAppendPrintf(sentry, close_bracket); } -void ipcacheShutdownServers() -{ - dnsserver_t *dnsData = NULL; - int k; - static char *shutdown = "$shutdown\n"; - - debug(14, 3, "ipcacheShutdownServers:\n"); - - for (k = 0; k < getDnsChildren(); k++) { - dnsData = *(dns_child_table + k); - if (!(dnsData->flags & DNS_FLAG_ALIVE)) - continue; - if (dnsData->flags & DNS_FLAG_BUSY) - continue; - if (dnsData->flags & DNS_FLAG_CLOSING) - continue; - debug(14, 3, "ipcacheShutdownServers: sending '$shutdown' to dnsserver #%d\n", dnsData->id); - debug(14, 3, "ipcacheShutdownServers: --> FD %d\n", dnsData->outpipe); - comm_write(dnsData->outpipe, - xstrdup(shutdown), - strlen(shutdown), - 0, /* timeout */ - NULL, /* Handler */ - NULL, /* Handler-data */ - xfree); - dnsData->flags |= DNS_FLAG_CLOSING; - } -} - static int dummy_handler(u1, u2, u3) int u1; struct hostent *u2; diff --git a/src/main.cc b/src/main.cc index 797f86ae32..199bd10ce3 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,5 +1,5 @@ /* - * $Id: main.cc,v 1.52 1996/07/19 17:35:13 wessels Exp $ + * $Id: main.cc,v 1.53 1996/07/22 16:40:27 wessels Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -372,7 +372,7 @@ static void mainReinitialize() parseConfigFile(ConfigFile); _db_init(getCacheLogFile(), getDebugOptions()); neighbors_init(); - ipcacheOpenServers(); + dnsOpenServers(); redirectOpenServers(); serverConnectionsOpen(); (void) ftpInitialize(); @@ -425,6 +425,8 @@ static void mainInitialize() writePidFile(); /* write PID file */ } ipcache_init(); + fqdncache_init(); + dnsOpenServers(); redirectOpenServers(); neighbors_init(); (void) ftpInitialize(); diff --git a/src/neighbors.cc b/src/neighbors.cc index 4ec1be4d18..9434c73af3 100644 --- a/src/neighbors.cc +++ b/src/neighbors.cc @@ -1,5 +1,5 @@ /* - * $Id: neighbors.cc,v 1.33 1996/07/20 03:16:53 wessels Exp $ + * $Id: neighbors.cc,v 1.34 1996/07/22 16:40:27 wessels Exp $ * * DEBUG: section 15 Neighbor Routines * AUTHOR: Harvest Derived @@ -234,6 +234,7 @@ static int edgeWouldBePinged(e, request) dom_list *d = NULL; int do_ping = 1; struct _acl_list *a = NULL; + aclCheck_t checklist; if (e->domains == NULL && e->acls == NULL) return do_ping; @@ -243,14 +244,10 @@ static int edgeWouldBePinged(e, request) return d->do_ping; do_ping = !d->do_ping; } + checklist.src_addr = any_addr; /* XXX bogus! */ + checklist.request = request; for (a = e->acls; a; a = a->next) { - if (aclMatchAcl(a->acl, - any_addr, /* bogus */ - request->method, - request->protocol, - request->host, - request->port, - request->urlpath)) + if (aclMatchAcl(a->acl, &checklist)) return a->op; do_ping = !a->op; } diff --git a/src/squid.h b/src/squid.h index 553ae11994..797ce7f877 100644 --- a/src/squid.h +++ b/src/squid.h @@ -1,6 +1,6 @@ /* - * $Id: squid.h,v 1.30 1996/07/20 03:16:54 wessels Exp $ + * $Id: squid.h,v 1.31 1996/07/22 16:40:29 wessels Exp $ * * AUTHOR: Duane Wessels * @@ -185,6 +185,7 @@ typedef struct mem_hdr *mem_ptr; typedef struct _edge edge; typedef struct icp_common_s icp_common_t; typedef struct _cacheinfo cacheinfo; +typedef struct _aclCheck_t aclCheck_t; /* 32 bit integer compatability hack */ #if SIZEOF_INT == 4 @@ -225,7 +226,9 @@ typedef void (*SIH) _PARAMS((int, void *)); /* swap in */ #include "proto.h" #include "icp.h" #include "errorpage.h" /* must go after icp.h */ +#include "dns.h" #include "ipcache.h" +#include "fqdncache.h" #include "mime.h" #include "neighbors.h" #include "stack.h" @@ -236,11 +239,12 @@ typedef void (*SIH) _PARAMS((int, void *)); /* swap in */ #include "http.h" #include "ftp.h" #include "gopher.h" -#include "acl.h" #include "util.h" #include "background.h" +#include "acl.h" #include "async_io.h" #include "redirect.h" +#include "client_side.h" #if !HAVE_TEMPNAM #include "tempnam.h" diff --git a/src/stat.cc b/src/stat.cc index 92bdb5f5b7..2cf9dfd434 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -1,5 +1,5 @@ /* - * $Id: stat.cc,v 1.43 1996/07/20 03:16:55 wessels Exp $ + * $Id: stat.cc,v 1.44 1996/07/22 16:40:29 wessels Exp $ * * DEBUG: section 18 Cache Manager Statistics * AUTHOR: Harvest Derived @@ -312,8 +312,10 @@ void stat_get(obj, req, sentry) stat_objects_get(obj, sentry, 0); } else if (strcmp(req, "vm_objects") == 0) { stat_objects_get(obj, sentry, 1); - } else if (strcmp(req, "general") == 0) { + } else if (strcmp(req, "ipcache") == 0) { stat_ipcache_get(sentry); + } else if (strcmp(req, "fqdncache") == 0) { + fqdnStats(sentry); } else if (strcmp(req, "redirector") == 0) { redirectStats(sentry); } else if (strcmp(req, "utilization") == 0) { @@ -594,6 +596,7 @@ int memoryAccounted() return (int) meta_data.store_entries * sizeof(StoreEntry) + meta_data.ipcache_count * sizeof(ipcache_entry) + + meta_data.fqdncache_count * sizeof(fqdncache_entry) + meta_data.hash_links * sizeof(hash_link) + sm_stats.total_pages_allocated * sm_stats.page_size + disk_stats.total_pages_allocated * disk_stats.page_size + @@ -767,6 +770,12 @@ void info_get(obj, sentry) (int) sizeof(ipcache_entry), (int) (meta_data.ipcache_count * sizeof(ipcache_entry) >> 10)); + storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n", + "FQDNCacheEntry", + meta_data.fqdncache_count, + (int) sizeof(fqdncache_entry), + (int) (meta_data.fqdncache_count * sizeof(fqdncache_entry) >> 10)); + storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n", "Hash link", meta_data.hash_links = hash_links_allocated,