]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
-Split ipcache.c into ipcache.c and dns.c
authorwessels <>
Mon, 22 Jul 1996 22:40:19 +0000 (22:40 +0000)
committerwessels <>
Mon, 22 Jul 1996 22:40:19 +0000 (22:40 +0000)
-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'

12 files changed:
src/Makefile.in
src/acl.cc
src/client_side.cc [new file with mode: 0644]
src/comm.cc
src/dns.cc [new file with mode: 0644]
src/dnsserver.cc
src/fqdncache.cc [new file with mode: 0644]
src/ipcache.cc
src/main.cc
src/neighbors.cc
src/squid.h
src/stat.cc

index 5de1a1e96d4c2bbb11d19fc2022e0e6527a783d9..49119f3f6f844252cb5cec8ab4483978ecd7d876 100644 (file)
@@ -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 \
index 1d19f8e3d2cc423d68ab9a9269acab4658192a0e..3e26d77a1e057c5695c6ad4dcd010ad41d19a94a 100644 (file)
@@ -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 (file)
index 0000000..03eaed3
--- /dev/null
@@ -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);
+}
index b5ce562abb9f6c285d01390aa94d11436018d30f..9db02cd100e57a3447ee8bfd949824c41e102462 100644 (file)
@@ -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 (file)
index 0000000..9f7d2ca
--- /dev/null
@@ -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;
+    }
+}
index 39ce74a7d3f16324782d7905212deef57451bb09..28a6b5a0e2eb0c4867a85f4a88b545d1fd438180 100644 (file)
@@ -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 (file)
index 0000000..ad350c0
--- /dev/null
@@ -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);
+}
index 725a0e3721599accc103ffb5f24cc5459653acc4..8829083d6ee3d530df756ed708a4932657f81b32 100644 (file)
@@ -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
 #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;
index 797f86ae3237afccc4e5fed25f1e05cc8eb2a45b..199bd10ce34c97061d292df3285e4dbcab3365a6 100644 (file)
@@ -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();
index 4ec1be4d189f72b5fd2d7b01a594d4fe8f5e56a0..9434c73af3ff72010e4db266e7cf61a01b766866 100644 (file)
@@ -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;
     }
index 553ae119941eab8795a53a8c876470d9d5b34f62..797ce7f8775878b08fdcba08a1e891143f1e7ea0 100644 (file)
@@ -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"
index 92bdb5f5b70998c78169b0f7f44f0ed54f25874d..2cf9dfd4343922dd5e2d10414a5a64147cc159c0 100644 (file)
@@ -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,