]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Move ASN handling for ACL into ACL area.
authorAmos Jeffries <squid3@treenet.co.nz>
Mon, 18 May 2009 11:15:37 +0000 (23:15 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Mon, 18 May 2009 11:15:37 +0000 (23:15 +1200)
This removes one possble compile clash, and one empty file.

src/Makefile.am
src/acl/Asn.cc
src/asn.cc [deleted file]

index 6f3b4376fdff430811b730992987a7e03a9b4063..8c02760907931bb5e2e14536043d5df4828dc78f 100644 (file)
@@ -285,7 +285,6 @@ squid_SOURCES = \
        $(ACL_REGISTRATION_SOURCES) \
        access_log.cc \
        AccessLogEntry.h \
-       asn.cc \
        AsyncEngine.cc \
        AsyncEngine.h \
        cache_cf.cc \
index 63ba9cd77de687deb1664df8b5e0c5abda4d8ef1..eb921dbc330977b9140936f3f6f8df98eb5224ff 100644 (file)
@@ -1,8 +1,9 @@
+
 /*
  * $Id$
  *
- * DEBUG: section 28    Access Control
- * AUTHOR: Robert Collins
+ * DEBUG: section 53    AS Number handling
+ * AUTHOR: Duane Wessels, Kostas Anagnostakis
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
- * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
+#include "CacheManager.h"
+#include "radix.h"
+#include "HttpRequest.h"
+#include "StoreClient.h"
+#include "Store.h"
+#include "acl/Acl.h"
 #include "acl/Asn.h"
 #include "acl/Checklist.h"
+#include "acl/SourceAsn.h"
+#include "acl/DestinationAsn.h"
+#include "acl/DestinationIp.h"
+#include "HttpReply.h"
+#include "forward.h"
+#include "wordlist.h"
+
+#define WHOIS_PORT 43
+#define        AS_REQBUF_SZ    4096
+
+/* BEGIN of definitions for radix tree entries */
+
+
+/* 32/128 bits address in memory with length */
+class m_ADDR
+{
+public:
+    uint8_t len;
+    IpAddress addr;
+
+    m_ADDR() : len(sizeof(IpAddress)) {};
+};
+
+/* END of definitions for radix tree entries */
+
+/* Head for ip to asn radix tree */
+
+struct squid_radix_node_head *AS_tree_head;
+
+/* explicit instantiation required for some systems */
+
+/// \cond AUTODOCS-IGNORE
+template cbdata_type CbDataList<int>::CBDATA_CbDataList;
+/// \endcond
+
+/**
+ * Structure for as number information. it could be simply
+ * a list but it's coded as a structure for future
+ * enhancements (e.g. expires)
+ */
+struct as_info {
+    CbDataList<int> *as_number;
+    time_t expires;            /* NOTUSED */
+};
+
+struct ASState {
+    StoreEntry *entry;
+    store_client *sc;
+    HttpRequest *request;
+    int as_number;
+    int64_t offset;
+    int reqofs;
+    char reqbuf[AS_REQBUF_SZ];
+    bool dataRead;
+};
+
+/** entry into the radix tree */
+struct rtentry_t {
+    struct squid_radix_node e_nodes[2];
+    as_info *e_info;
+    m_ADDR e_addr;
+    m_ADDR e_mask;
+};
+
+static int asnAddNet(char *, int);
+
+static void asnCacheStart(int as);
+
+static STCB asHandleReply;
+
+static int destroyRadixNode(struct squid_radix_node *rn, void *w);
+
+static int printRadixNode(struct squid_radix_node *rn, void *sentry);
+
+void asnAclInitialize(ACL * acls);
+
+static void asStateFree(void *data);
+
+static void destroyRadixNodeInfo(as_info *);
+
+static OBJH asnStats;
+
+/* PUBLIC */
+
+int
+asnMatchIp(CbDataList<int> *data, IpAddress &addr)
+{
+    struct squid_radix_node *rn;
+    as_info *e;
+    m_ADDR m_addr;
+    CbDataList<int> *a = NULL;
+    CbDataList<int> *b = NULL;
+
+    debugs(53, 3, "asnMatchIp: Called for " << addr );
+
+    if (AS_tree_head == NULL)
+        return 0;
+
+    if (addr.IsNoAddr())
+        return 0;
+
+    if (addr.IsAnyAddr())
+        return 0;
+
+    m_addr.addr = addr;
+
+    rn = squid_rn_match(&m_addr, AS_tree_head);
+
+    if (rn == NULL) {
+        debugs(53, 3, "asnMatchIp: Address not in as db.");
+        return 0;
+    }
+
+    debugs(53, 3, "asnMatchIp: Found in db!");
+    e = ((rtentry_t *) rn)->e_info;
+    assert(e);
+
+    for (a = data; a; a = a->next)
+        for (b = e->as_number; b; b = b->next)
+            if (a->element == b->element) {
+                debugs(53, 5, "asnMatchIp: Found a match!");
+                return 1;
+            }
+
+    debugs(53, 5, "asnMatchIp: AS not in as db.");
+    return 0;
+}
+
+void
+ACLASN::prepareForUse()
+{
+    for (CbDataList<int> *i = data; i; i = i->
+                                           next)
+        asnCacheStart(i->element);
+}
+
+static void
+asnRegisterWithCacheManager(void)
+{
+    CacheManager::GetInstance()->registerAction("asndb", "AS Number Database", asnStats, 0, 1);
+}
+
+/* initialize the radix tree structure */
+
+SQUIDCEXTERN int squid_max_keylen;     /* yuck.. this is in lib/radix.c */
+
+CBDATA_TYPE(ASState);
+void
+asnInit(void)
+{
+    static int inited = 0;
+    squid_max_keylen = 40;
+    CBDATA_INIT_TYPE(ASState);
+
+    if (0 == inited++)
+        squid_rn_init();
+
+    squid_rn_inithead(&AS_tree_head, 8);
+
+    asnRegisterWithCacheManager();
+}
+
+void
+asnFreeMemory(void)
+{
+    squid_rn_walktree(AS_tree_head, destroyRadixNode, AS_tree_head);
+
+    destroyRadixNode((struct squid_radix_node *) 0, (void *) AS_tree_head);
+}
+
+static void
+asnStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Address    \tAS Numbers\n");
+    squid_rn_walktree(AS_tree_head, printRadixNode, sentry);
+}
+
+/* PRIVATE */
+
+
+static void
+asnCacheStart(int as)
+{
+    LOCAL_ARRAY(char, asres, 4096);
+    StoreEntry *e;
+    HttpRequest *req;
+    ASState *asState;
+    asState = cbdataAlloc(ASState);
+    asState->dataRead = 0;
+    debugs(53, 3, "asnCacheStart: AS " << as);
+    snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
+    asState->as_number = as;
+    req = HttpRequest::CreateFromUrl(asres);
+    assert(NULL != req);
+    asState->request = HTTPMSGLOCK(req);
+
+    if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
+        e = storeCreateEntry(asres, asres, request_flags(), METHOD_GET);
+        asState->sc = storeClientListAdd(e, asState);
+        FwdState::fwdStart(-1, e, asState->request);
+    } else {
+
+        e->lock();
+        asState->sc = storeClientListAdd(e, asState);
+    }
+
+    asState->entry = e;
+    asState->offset = 0;
+    asState->reqofs = 0;
+    StoreIOBuffer readBuffer (AS_REQBUF_SZ, asState->offset, asState->reqbuf);
+    storeClientCopy(asState->sc,
+                    e,
+                    readBuffer,
+                    asHandleReply,
+                    asState);
+}
+
+static void
+asHandleReply(void *data, StoreIOBuffer result)
+{
+    ASState *asState = (ASState *)data;
+    StoreEntry *e = asState->entry;
+    char *s;
+    char *t;
+    char *buf = asState->reqbuf;
+    int leftoversz = -1;
+
+    debugs(53, 3, "asHandleReply: Called with size=" << (unsigned int)result.length);
+    debugs(53, 3, "asHandleReply: buffer='" << buf << "'");
+
+    /* First figure out whether we should abort the request */
+
+    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
+        asStateFree(asState);
+        return;
+    }
+
+    if (result.length == 0 && asState->dataRead) {
+        debugs(53, 3, "asHandleReply: Done: " << e->url()  );
+        asStateFree(asState);
+        return;
+    } else if (result.flags.error) {
+        debugs(53, 1, "asHandleReply: Called with Error set and size=" << (unsigned int) result.length);
+        asStateFree(asState);
+        return;
+    } else if (HTTP_OK != e->getReply()->sline.status) {
+        debugs(53, 1, "WARNING: AS " << asState->as_number << " whois request failed");
+        asStateFree(asState);
+        return;
+    }
+
+    /*
+     * Next, attempt to parse our request
+     * Remembering that the actual buffer size is retsize + reqofs!
+     */
+    s = buf;
+
+    while ((size_t)(s - buf) < result.length + asState->reqofs && *s != '\0') {
+        while (*s && xisspace(*s))
+            s++;
+
+        for (t = s; *t; t++) {
+            if (xisspace(*t))
+                break;
+        }
+
+        if (*t == '\0') {
+            /* oof, word should continue on next block */
+            break;
+        }
+
+        *t = '\0';
+        debugs(53, 3, "asHandleReply: AS# " << s << " (" << asState->as_number << ")");
+        asnAddNet(s, asState->as_number);
+        s = t + 1;
+        asState->dataRead = 1;
+    }
+
+    /*
+     * Next, grab the end of the 'valid data' in the buffer, and figure
+     * out how much data is left in our buffer, which we need to keep
+     * around for the next request
+     */
+    leftoversz = (asState->reqofs + result.length) - (s - buf);
+
+    assert(leftoversz >= 0);
+
+    /*
+     * Next, copy the left over data, from s to s + leftoversz to the
+     * beginning of the buffer
+     */
+    xmemmove(buf, s, leftoversz);
+
+    /*
+     * Next, update our offset and reqofs, and kick off a copy if required
+     */
+    asState->offset += result.length;
+
+    asState->reqofs = leftoversz;
+
+    debugs(53, 3, "asState->offset = " << asState->offset);
+
+    if (e->store_status == STORE_PENDING) {
+        debugs(53, 3, "asHandleReply: store_status == STORE_PENDING: " << e->url()  );
+        StoreIOBuffer tempBuffer (AS_REQBUF_SZ - asState->reqofs,
+                                  asState->offset,
+                                  asState->reqbuf + asState->reqofs);
+        storeClientCopy(asState->sc,
+                        e,
+                        tempBuffer,
+                        asHandleReply,
+                        asState);
+    } else {
+        StoreIOBuffer tempBuffer;
+        debugs(53, 3, "asHandleReply: store complete, but data received " << e->url()  );
+        tempBuffer.offset = asState->offset;
+        tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
+        tempBuffer.data = asState->reqbuf + asState->reqofs;
+        storeClientCopy(asState->sc,
+                        e,
+                        tempBuffer,
+                        asHandleReply,
+                        asState);
+    }
+}
+
+static void
+asStateFree(void *data)
+{
+    ASState *asState = (ASState *)data;
+    debugs(53, 3, "asnStateFree: " << asState->entry->url()  );
+    storeUnregister(asState->sc, asState->entry, asState);
+    asState->entry->unlock();
+    HTTPMSGUNLOCK(asState->request);
+    cbdataFree(asState);
+}
+
+
+/**
+ * add a network (addr, mask) to the radix tree, with matching AS number
+ */
+static int
+asnAddNet(char *as_string, int as_number)
+{
+    rtentry_t *e;
+
+    struct squid_radix_node *rn;
+    CbDataList<int> **Tail = NULL;
+    CbDataList<int> *q = NULL;
+    as_info *asinfo = NULL;
+
+    IpAddress mask;
+    IpAddress addr;
+    char *t;
+    int bitl;
+
+    t = strchr(as_string, '/');
+
+    if (t == NULL) {
+        debugs(53, 3, "asnAddNet: failed, invalid response from whois server.");
+        return 0;
+    }
+
+    *t = '\0';
+    addr = as_string;
+    bitl = atoi(t + 1);
+
+    if (bitl < 0)
+        bitl = 0;
+
+    // INET6 TODO : find a better way of identifying the base IPA family for mask than this.
+    t = strchr(as_string, '.');
+
+    // generate Netbits Format Mask
+    mask.SetNoAddr();
+    mask.ApplyMask(bitl, (t!=NULL?AF_INET:AF_INET6) );
+
+    debugs(53, 3, "asnAddNet: called for " << addr << "/" << mask );
+
+    e = (rtentry_t *)xmalloc(sizeof(rtentry_t));
+
+    memset(e, '\0', sizeof(rtentry_t));
+
+    e->e_addr.addr = addr;
+
+    e->e_mask.addr = mask;
+
+    rn = squid_rn_lookup(&e->e_addr, &e->e_mask, AS_tree_head);
+
+    if (rn != NULL) {
+        asinfo = ((rtentry_t *) rn)->e_info;
+
+        if (asinfo->as_number->find(as_number)) {
+            debugs(53, 3, "asnAddNet: Ignoring repeated network '" << addr << "/" << bitl << "' for AS " << as_number);
+        } else {
+            debugs(53, 3, "asnAddNet: Warning: Found a network with multiple AS numbers!");
+
+            for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
+            q = new CbDataList<int> (as_number);
+
+            *(Tail) = q;
+
+            e->e_info = asinfo;
+        }
+    } else {
+        q = new CbDataList<int> (as_number);
+        asinfo = (as_info *)xmalloc(sizeof(as_info));
+        asinfo->as_number = q;
+        rn = squid_rn_addroute(&e->e_addr, &e->e_mask, AS_tree_head, e->e_nodes);
+        rn = squid_rn_match(&e->e_addr, AS_tree_head);
+        assert(rn != NULL);
+        e->e_info = asinfo;
+    }
+
+    if (rn == 0) {             /* assert might expand to nothing */
+        xfree(asinfo);
+        delete q;
+        xfree(e);
+        debugs(53, 3, "asnAddNet: Could not add entry.");
+        return 0;
+    }
+
+    e->e_info = asinfo;
+    return 1;
+}
+
+static int
+destroyRadixNode(struct squid_radix_node *rn, void *w)
+{
+
+    struct squid_radix_node_head *rnh = (struct squid_radix_node_head *) w;
+
+    if (rn && !(rn->rn_flags & RNF_ROOT)) {
+        rtentry_t *e = (rtentry_t *) rn;
+        rn = squid_rn_delete(rn->rn_key, rn->rn_mask, rnh);
+
+        if (rn == 0)
+            debugs(53, 3, "destroyRadixNode: internal screwup");
+
+        destroyRadixNodeInfo(e->e_info);
+
+        xfree(rn);
+    }
+
+    return 1;
+}
+
+static void
+destroyRadixNodeInfo(as_info * e_info)
+{
+    CbDataList<int> *prev = NULL;
+    CbDataList<int> *data = e_info->as_number;
+
+    while (data) {
+        prev = data;
+        data = data->next;
+        delete prev;
+    }
+
+    delete data;
+}
+
+static int
+printRadixNode(struct squid_radix_node *rn, void *_sentry)
+{
+    StoreEntry *sentry = (StoreEntry *)_sentry;
+    rtentry_t *e = (rtentry_t *) rn;
+    CbDataList<int> *q;
+    as_info *asinfo;
+    char buf[MAX_IPSTRLEN];
+    IpAddress addr;
+    IpAddress mask;
+
+    assert(e);
+    assert(e->e_info);
+    addr = e->e_addr.addr;
+    mask = e->e_mask.addr;
+    storeAppendPrintf(sentry, "%s/%d\t",
+                      addr.NtoA(buf, MAX_IPSTRLEN),
+                      mask.GetCIDR() );
+    asinfo = e->e_info;
+    assert(asinfo->as_number);
+
+    for (q = asinfo->as_number; q; q = q->next)
+        storeAppendPrintf(sentry, " %d", q->element);
+
+    storeAppendPrintf(sentry, "\n");
+
+    return 0;
+}
+
+ACLASN::~ACLASN()
+{
+    if (data)
+        delete data;
+}
+
+bool
+
+ACLASN::match(IpAddress toMatch)
+{
+    return asnMatchIp(data, toMatch);
+}
+
+wordlist *
+ACLASN::dump()
+{
+    wordlist *W = NULL;
+    char buf[32];
+    CbDataList<int> *ldata = data;
+
+    while (ldata != NULL) {
+        snprintf(buf, sizeof(buf), "%d", ldata->element);
+        wordlistAdd(&W, buf);
+        ldata = ldata->next;
+    }
+
+    return W;
+}
+
+bool
+ACLASN::empty () const
+{
+    return data == NULL;
+}
+
+void
+ACLASN::parse()
+{
+    CbDataList<int> **curlist = &data;
+    CbDataList<int> **Tail;
+    CbDataList<int> *q = NULL;
+    char *t = NULL;
+
+    for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
+    while ((t = strtokFile())) {
+        q = new CbDataList<int> (atoi(t));
+        *(Tail) = q;
+        Tail = &q->next;
+    }
+}
+
+ACLData<IpAddress> *
+ACLASN::clone() const
+{
+    if (data)
+        fatal ("cloning of ACLASN not implemented");
+
+    return new ACLASN(*this);
+}
+
+/* explicit template instantiation required for some systems */
+
+template class ACLStrategised<IpAddress>;
+
+ACL::Prototype ACLASN::SourceRegistryProtoype(&ACLASN::SourceRegistryEntry_, "src_as");
+
+ACLStrategised<IpAddress> ACLASN::SourceRegistryEntry_(new ACLASN, ACLSourceASNStrategy::Instance(), "src_as");
+
+ACL::Prototype ACLASN::DestinationRegistryProtoype(&ACLASN::DestinationRegistryEntry_, "dst_as");
+
+ACLStrategised<IpAddress> ACLASN::DestinationRegistryEntry_(new ACLASN, ACLDestinationASNStrategy::Instance(), "dst_as");
+
+int
+ACLSourceASNStrategy::match (ACLData<IpAddress> * &data, ACLFilledChecklist *checklist)
+{
+    return data->match(checklist->src_addr);
+}
+
+ACLSourceASNStrategy *
+ACLSourceASNStrategy::Instance()
+{
+    return &Instance_;
+}
+
+ACLSourceASNStrategy ACLSourceASNStrategy::Instance_;
+
+
+int
+ACLDestinationASNStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
+{
+    const ipcache_addrs *ia = ipcache_gethostbyname(checklist->request->GetHost(), IP_LOOKUP_IF_MISS);
+
+    if (ia) {
+        for (int k = 0; k < (int) ia->count; k++) {
+            if (data->match(ia->in_addrs[k]))
+                return 1;
+        }
+
+        return 0;
+
+    } else if (!checklist->request->flags.destinationIPLookedUp()) {
+        /* No entry in cache, lookup not attempted */
+        /* XXX FIXME: allow accessing the acl name here */
+        debugs(28, 3, "asnMatchAcl: Can't yet compare '" << "unknown" /*name*/ << "' ACL for '" << checklist->request->GetHost() << "'");
+        checklist->changeState (DestinationIPLookup::Instance());
+    } else {
+        IpAddress noaddr;
+        noaddr.SetNoAddr();
+        return data->match(noaddr);
+    }
+
+    return 0;
+}
+
+ACLDestinationASNStrategy *
+ACLDestinationASNStrategy::Instance()
+{
+    return &Instance_;
+}
 
+ACLDestinationASNStrategy ACLDestinationASNStrategy::Instance_;
diff --git a/src/asn.cc b/src/asn.cc
deleted file mode 100644 (file)
index 747dffe..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-
-/*
- * $Id$
- *
- * DEBUG: section 53    AS Number handling
- * AUTHOR: Duane Wessels, Kostas Anagnostakis
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
-
-#include "squid.h"
-#include "CacheManager.h"
-#include "radix.h"
-#include "HttpRequest.h"
-#include "StoreClient.h"
-#include "Store.h"
-#include "acl/Acl.h"
-#include "acl/Asn.h"
-#include "acl/SourceAsn.h"
-#include "acl/DestinationAsn.h"
-#include "acl/DestinationIp.h"
-#include "HttpReply.h"
-#include "forward.h"
-#include "wordlist.h"
-
-#define WHOIS_PORT 43
-#define        AS_REQBUF_SZ    4096
-
-/* BEGIN of definitions for radix tree entries */
-
-
-/* 32/128 bits address in memory with length */
-class m_ADDR
-{
-public:
-    uint8_t len;
-    IpAddress addr;
-
-    m_ADDR() : len(sizeof(IpAddress)) {};
-};
-
-/* END of definitions for radix tree entries */
-
-/* Head for ip to asn radix tree */
-
-struct squid_radix_node_head *AS_tree_head;
-
-/* explicit instantiation required for some systems */
-
-/// \cond AUTODOCS-IGNORE
-template cbdata_type CbDataList<int>::CBDATA_CbDataList;
-/// \endcond
-
-/**
- * Structure for as number information. it could be simply
- * a list but it's coded as a structure for future
- * enhancements (e.g. expires)
- */
-struct as_info {
-    CbDataList<int> *as_number;
-    time_t expires;            /* NOTUSED */
-};
-
-struct ASState {
-    StoreEntry *entry;
-    store_client *sc;
-    HttpRequest *request;
-    int as_number;
-    int64_t offset;
-    int reqofs;
-    char reqbuf[AS_REQBUF_SZ];
-    bool dataRead;
-};
-
-/** entry into the radix tree */
-struct rtentry_t {
-    struct squid_radix_node e_nodes[2];
-    as_info *e_info;
-    m_ADDR e_addr;
-    m_ADDR e_mask;
-};
-
-static int asnAddNet(char *, int);
-
-static void asnCacheStart(int as);
-
-static STCB asHandleReply;
-
-static int destroyRadixNode(struct squid_radix_node *rn, void *w);
-
-static int printRadixNode(struct squid_radix_node *rn, void *sentry);
-
-void asnAclInitialize(ACL * acls);
-
-static void asStateFree(void *data);
-
-static void destroyRadixNodeInfo(as_info *);
-
-static OBJH asnStats;
-
-/* PUBLIC */
-
-int
-asnMatchIp(CbDataList<int> *data, IpAddress &addr)
-{
-    struct squid_radix_node *rn;
-    as_info *e;
-    m_ADDR m_addr;
-    CbDataList<int> *a = NULL;
-    CbDataList<int> *b = NULL;
-
-    debugs(53, 3, "asnMatchIp: Called for " << addr );
-
-    if (AS_tree_head == NULL)
-        return 0;
-
-    if (addr.IsNoAddr())
-        return 0;
-
-    if (addr.IsAnyAddr())
-        return 0;
-
-    m_addr.addr = addr;
-
-    rn = squid_rn_match(&m_addr, AS_tree_head);
-
-    if (rn == NULL) {
-        debugs(53, 3, "asnMatchIp: Address not in as db.");
-        return 0;
-    }
-
-    debugs(53, 3, "asnMatchIp: Found in db!");
-    e = ((rtentry_t *) rn)->e_info;
-    assert(e);
-
-    for (a = data; a; a = a->next)
-        for (b = e->as_number; b; b = b->next)
-            if (a->element == b->element) {
-                debugs(53, 5, "asnMatchIp: Found a match!");
-                return 1;
-            }
-
-    debugs(53, 5, "asnMatchIp: AS not in as db.");
-    return 0;
-}
-
-void
-ACLASN::prepareForUse()
-{
-    for (CbDataList<int> *i = data; i; i = i->
-                                           next)
-        asnCacheStart(i->element);
-}
-
-static void
-asnRegisterWithCacheManager(void)
-{
-    CacheManager::GetInstance()->registerAction("asndb", "AS Number Database", asnStats, 0, 1);
-}
-
-/* initialize the radix tree structure */
-
-SQUIDCEXTERN int squid_max_keylen;     /* yuck.. this is in lib/radix.c */
-
-CBDATA_TYPE(ASState);
-void
-asnInit(void)
-{
-    static int inited = 0;
-    squid_max_keylen = 40;
-    CBDATA_INIT_TYPE(ASState);
-
-    if (0 == inited++)
-        squid_rn_init();
-
-    squid_rn_inithead(&AS_tree_head, 8);
-
-    asnRegisterWithCacheManager();
-}
-
-void
-asnFreeMemory(void)
-{
-    squid_rn_walktree(AS_tree_head, destroyRadixNode, AS_tree_head);
-
-    destroyRadixNode((struct squid_radix_node *) 0, (void *) AS_tree_head);
-}
-
-static void
-asnStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "Address    \tAS Numbers\n");
-    squid_rn_walktree(AS_tree_head, printRadixNode, sentry);
-}
-
-/* PRIVATE */
-
-
-static void
-asnCacheStart(int as)
-{
-    LOCAL_ARRAY(char, asres, 4096);
-    StoreEntry *e;
-    HttpRequest *req;
-    ASState *asState;
-    asState = cbdataAlloc(ASState);
-    asState->dataRead = 0;
-    debugs(53, 3, "asnCacheStart: AS " << as);
-    snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
-    asState->as_number = as;
-    req = HttpRequest::CreateFromUrl(asres);
-    assert(NULL != req);
-    asState->request = HTTPMSGLOCK(req);
-
-    if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
-        e = storeCreateEntry(asres, asres, request_flags(), METHOD_GET);
-        asState->sc = storeClientListAdd(e, asState);
-        FwdState::fwdStart(-1, e, asState->request);
-    } else {
-
-        e->lock();
-        asState->sc = storeClientListAdd(e, asState);
-    }
-
-    asState->entry = e;
-    asState->offset = 0;
-    asState->reqofs = 0;
-    StoreIOBuffer readBuffer (AS_REQBUF_SZ, asState->offset, asState->reqbuf);
-    storeClientCopy(asState->sc,
-                    e,
-                    readBuffer,
-                    asHandleReply,
-                    asState);
-}
-
-static void
-asHandleReply(void *data, StoreIOBuffer result)
-{
-    ASState *asState = (ASState *)data;
-    StoreEntry *e = asState->entry;
-    char *s;
-    char *t;
-    char *buf = asState->reqbuf;
-    int leftoversz = -1;
-
-    debugs(53, 3, "asHandleReply: Called with size=" << (unsigned int)result.length);
-    debugs(53, 3, "asHandleReply: buffer='" << buf << "'");
-
-    /* First figure out whether we should abort the request */
-
-    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
-        asStateFree(asState);
-        return;
-    }
-
-    if (result.length == 0 && asState->dataRead) {
-        debugs(53, 3, "asHandleReply: Done: " << e->url()  );
-        asStateFree(asState);
-        return;
-    } else if (result.flags.error) {
-        debugs(53, 1, "asHandleReply: Called with Error set and size=" << (unsigned int) result.length);
-        asStateFree(asState);
-        return;
-    } else if (HTTP_OK != e->getReply()->sline.status) {
-        debugs(53, 1, "WARNING: AS " << asState->as_number << " whois request failed");
-        asStateFree(asState);
-        return;
-    }
-
-    /*
-     * Next, attempt to parse our request
-     * Remembering that the actual buffer size is retsize + reqofs!
-     */
-    s = buf;
-
-    while ((size_t)(s - buf) < result.length + asState->reqofs && *s != '\0') {
-        while (*s && xisspace(*s))
-            s++;
-
-        for (t = s; *t; t++) {
-            if (xisspace(*t))
-                break;
-        }
-
-        if (*t == '\0') {
-            /* oof, word should continue on next block */
-            break;
-        }
-
-        *t = '\0';
-        debugs(53, 3, "asHandleReply: AS# " << s << " (" << asState->as_number << ")");
-        asnAddNet(s, asState->as_number);
-        s = t + 1;
-        asState->dataRead = 1;
-    }
-
-    /*
-     * Next, grab the end of the 'valid data' in the buffer, and figure
-     * out how much data is left in our buffer, which we need to keep
-     * around for the next request
-     */
-    leftoversz = (asState->reqofs + result.length) - (s - buf);
-
-    assert(leftoversz >= 0);
-
-    /*
-     * Next, copy the left over data, from s to s + leftoversz to the
-     * beginning of the buffer
-     */
-    xmemmove(buf, s, leftoversz);
-
-    /*
-     * Next, update our offset and reqofs, and kick off a copy if required
-     */
-    asState->offset += result.length;
-
-    asState->reqofs = leftoversz;
-
-    debugs(53, 3, "asState->offset = " << asState->offset);
-
-    if (e->store_status == STORE_PENDING) {
-        debugs(53, 3, "asHandleReply: store_status == STORE_PENDING: " << e->url()  );
-        StoreIOBuffer tempBuffer (AS_REQBUF_SZ - asState->reqofs,
-                                  asState->offset,
-                                  asState->reqbuf + asState->reqofs);
-        storeClientCopy(asState->sc,
-                        e,
-                        tempBuffer,
-                        asHandleReply,
-                        asState);
-    } else {
-        StoreIOBuffer tempBuffer;
-        debugs(53, 3, "asHandleReply: store complete, but data received " << e->url()  );
-        tempBuffer.offset = asState->offset;
-        tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
-        tempBuffer.data = asState->reqbuf + asState->reqofs;
-        storeClientCopy(asState->sc,
-                        e,
-                        tempBuffer,
-                        asHandleReply,
-                        asState);
-    }
-}
-
-static void
-asStateFree(void *data)
-{
-    ASState *asState = (ASState *)data;
-    debugs(53, 3, "asnStateFree: " << asState->entry->url()  );
-    storeUnregister(asState->sc, asState->entry, asState);
-    asState->entry->unlock();
-    HTTPMSGUNLOCK(asState->request);
-    cbdataFree(asState);
-}
-
-
-/**
- * add a network (addr, mask) to the radix tree, with matching AS number
- */
-static int
-asnAddNet(char *as_string, int as_number)
-{
-    rtentry_t *e;
-
-    struct squid_radix_node *rn;
-    CbDataList<int> **Tail = NULL;
-    CbDataList<int> *q = NULL;
-    as_info *asinfo = NULL;
-
-    IpAddress mask;
-    IpAddress addr;
-    char *t;
-    int bitl;
-
-    t = strchr(as_string, '/');
-
-    if (t == NULL) {
-        debugs(53, 3, "asnAddNet: failed, invalid response from whois server.");
-        return 0;
-    }
-
-    *t = '\0';
-    addr = as_string;
-    bitl = atoi(t + 1);
-
-    if (bitl < 0)
-        bitl = 0;
-
-    // INET6 TODO : find a better way of identifying the base IPA family for mask than this.
-    t = strchr(as_string, '.');
-
-    // generate Netbits Format Mask
-    mask.SetNoAddr();
-    mask.ApplyMask(bitl, (t!=NULL?AF_INET:AF_INET6) );
-
-    debugs(53, 3, "asnAddNet: called for " << addr << "/" << mask );
-
-    e = (rtentry_t *)xmalloc(sizeof(rtentry_t));
-
-    memset(e, '\0', sizeof(rtentry_t));
-
-    e->e_addr.addr = addr;
-
-    e->e_mask.addr = mask;
-
-    rn = squid_rn_lookup(&e->e_addr, &e->e_mask, AS_tree_head);
-
-    if (rn != NULL) {
-        asinfo = ((rtentry_t *) rn)->e_info;
-
-        if (asinfo->as_number->find(as_number)) {
-            debugs(53, 3, "asnAddNet: Ignoring repeated network '" << addr << "/" << bitl << "' for AS " << as_number);
-        } else {
-            debugs(53, 3, "asnAddNet: Warning: Found a network with multiple AS numbers!");
-
-            for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
-            q = new CbDataList<int> (as_number);
-
-            *(Tail) = q;
-
-            e->e_info = asinfo;
-        }
-    } else {
-        q = new CbDataList<int> (as_number);
-        asinfo = (as_info *)xmalloc(sizeof(as_info));
-        asinfo->as_number = q;
-        rn = squid_rn_addroute(&e->e_addr, &e->e_mask, AS_tree_head, e->e_nodes);
-        rn = squid_rn_match(&e->e_addr, AS_tree_head);
-        assert(rn != NULL);
-        e->e_info = asinfo;
-    }
-
-    if (rn == 0) {             /* assert might expand to nothing */
-        xfree(asinfo);
-        delete q;
-        xfree(e);
-        debugs(53, 3, "asnAddNet: Could not add entry.");
-        return 0;
-    }
-
-    e->e_info = asinfo;
-    return 1;
-}
-
-static int
-destroyRadixNode(struct squid_radix_node *rn, void *w)
-{
-
-    struct squid_radix_node_head *rnh = (struct squid_radix_node_head *) w;
-
-    if (rn && !(rn->rn_flags & RNF_ROOT)) {
-        rtentry_t *e = (rtentry_t *) rn;
-        rn = squid_rn_delete(rn->rn_key, rn->rn_mask, rnh);
-
-        if (rn == 0)
-            debugs(53, 3, "destroyRadixNode: internal screwup");
-
-        destroyRadixNodeInfo(e->e_info);
-
-        xfree(rn);
-    }
-
-    return 1;
-}
-
-static void
-destroyRadixNodeInfo(as_info * e_info)
-{
-    CbDataList<int> *prev = NULL;
-    CbDataList<int> *data = e_info->as_number;
-
-    while (data) {
-        prev = data;
-        data = data->next;
-        delete prev;
-    }
-
-    delete data;
-}
-
-static int
-printRadixNode(struct squid_radix_node *rn, void *_sentry)
-{
-    StoreEntry *sentry = (StoreEntry *)_sentry;
-    rtentry_t *e = (rtentry_t *) rn;
-    CbDataList<int> *q;
-    as_info *asinfo;
-    char buf[MAX_IPSTRLEN];
-    IpAddress addr;
-    IpAddress mask;
-
-    assert(e);
-    assert(e->e_info);
-    addr = e->e_addr.addr;
-    mask = e->e_mask.addr;
-    storeAppendPrintf(sentry, "%s/%d\t",
-                      addr.NtoA(buf, MAX_IPSTRLEN),
-                      mask.GetCIDR() );
-    asinfo = e->e_info;
-    assert(asinfo->as_number);
-
-    for (q = asinfo->as_number; q; q = q->next)
-        storeAppendPrintf(sentry, " %d", q->element);
-
-    storeAppendPrintf(sentry, "\n");
-
-    return 0;
-}
-
-ACLASN::~ACLASN()
-{
-    if (data)
-        delete data;
-}
-
-bool
-
-ACLASN::match(IpAddress toMatch)
-{
-    return asnMatchIp(data, toMatch);
-}
-
-wordlist *
-ACLASN::dump()
-{
-    wordlist *W = NULL;
-    char buf[32];
-    CbDataList<int> *ldata = data;
-
-    while (ldata != NULL) {
-        snprintf(buf, sizeof(buf), "%d", ldata->element);
-        wordlistAdd(&W, buf);
-        ldata = ldata->next;
-    }
-
-    return W;
-}
-
-bool
-ACLASN::empty () const
-{
-    return data == NULL;
-}
-
-void
-ACLASN::parse()
-{
-    CbDataList<int> **curlist = &data;
-    CbDataList<int> **Tail;
-    CbDataList<int> *q = NULL;
-    char *t = NULL;
-
-    for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
-    while ((t = strtokFile())) {
-        q = new CbDataList<int> (atoi(t));
-        *(Tail) = q;
-        Tail = &q->next;
-    }
-}
-
-ACLData<IpAddress> *
-ACLASN::clone() const
-{
-    if (data)
-        fatal ("cloning of ACLASN not implemented");
-
-    return new ACLASN(*this);
-}
-
-/* explicit template instantiation required for some systems */
-
-template class ACLStrategised<IpAddress>;
-
-ACL::Prototype ACLASN::SourceRegistryProtoype(&ACLASN::SourceRegistryEntry_, "src_as");
-
-ACLStrategised<IpAddress> ACLASN::SourceRegistryEntry_(new ACLASN, ACLSourceASNStrategy::Instance(), "src_as");
-
-ACL::Prototype ACLASN::DestinationRegistryProtoype(&ACLASN::DestinationRegistryEntry_, "dst_as");
-
-ACLStrategised<IpAddress> ACLASN::DestinationRegistryEntry_(new ACLASN, ACLDestinationASNStrategy::Instance(), "dst_as");
-
-int
-ACLSourceASNStrategy::match (ACLData<IpAddress> * &data, ACLFilledChecklist *checklist)
-{
-    return data->match(checklist->src_addr);
-}
-
-ACLSourceASNStrategy *
-ACLSourceASNStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLSourceASNStrategy ACLSourceASNStrategy::Instance_;
-
-
-int
-ACLDestinationASNStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
-{
-    const ipcache_addrs *ia = ipcache_gethostbyname(checklist->request->GetHost(), IP_LOOKUP_IF_MISS);
-
-    if (ia) {
-        for (int k = 0; k < (int) ia->count; k++) {
-            if (data->match(ia->in_addrs[k]))
-                return 1;
-        }
-
-        return 0;
-
-    } else if (!checklist->request->flags.destinationIPLookedUp()) {
-        /* No entry in cache, lookup not attempted */
-        /* XXX FIXME: allow accessing the acl name here */
-        debugs(28, 3, "asnMatchAcl: Can't yet compare '" << "unknown" /*name*/ << "' ACL for '" << checklist->request->GetHost() << "'");
-        checklist->changeState (DestinationIPLookup::Instance());
-    } else {
-        IpAddress noaddr;
-        noaddr.SetNoAddr();
-        return data->match(noaddr);
-    }
-
-    return 0;
-}
-
-ACLDestinationASNStrategy *
-ACLDestinationASNStrategy::Instance()
-{
-    return &Instance_;
-}
-
-ACLDestinationASNStrategy ACLDestinationASNStrategy::Instance_;