From 445d18a460422224933c2d3b964dce27270bb402 Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Mon, 18 May 2009 23:15:37 +1200 Subject: [PATCH] Move ASN handling for ACL into ACL area. This removes one possble compile clash, and one empty file. --- src/Makefile.am | 1 - src/acl/Asn.cc | 623 ++++++++++++++++++++++++++++++++++++++++++++- src/asn.cc | 655 ------------------------------------------------ 3 files changed, 620 insertions(+), 659 deletions(-) delete mode 100644 src/asn.cc diff --git a/src/Makefile.am b/src/Makefile.am index 6f3b4376fd..8c02760907 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -285,7 +285,6 @@ squid_SOURCES = \ $(ACL_REGISTRATION_SOURCES) \ access_log.cc \ AccessLogEntry.h \ - asn.cc \ AsyncEngine.cc \ AsyncEngine.h \ cache_cf.cc \ diff --git a/src/acl/Asn.cc b/src/acl/Asn.cc index 63ba9cd77d..eb921dbc33 100644 --- a/src/acl/Asn.cc +++ b/src/acl/Asn.cc @@ -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/ * ---------------------------------------------------------- @@ -30,10 +31,626 @@ * 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 */ #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::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 *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 *data, IpAddress &addr) +{ + struct squid_radix_node *rn; + as_info *e; + m_ADDR m_addr; + CbDataList *a = NULL; + CbDataList *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 *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 **Tail = NULL; + CbDataList *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 (as_number); + + *(Tail) = q; + + e->e_info = asinfo; + } + } else { + q = new CbDataList (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 *prev = NULL; + CbDataList *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 *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 *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 **curlist = &data; + CbDataList **Tail; + CbDataList *q = NULL; + char *t = NULL; + + for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); + while ((t = strtokFile())) { + q = new CbDataList (atoi(t)); + *(Tail) = q; + Tail = &q->next; + } +} + +ACLData * +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; + +ACL::Prototype ACLASN::SourceRegistryProtoype(&ACLASN::SourceRegistryEntry_, "src_as"); + +ACLStrategised ACLASN::SourceRegistryEntry_(new ACLASN, ACLSourceASNStrategy::Instance(), "src_as"); + +ACL::Prototype ACLASN::DestinationRegistryProtoype(&ACLASN::DestinationRegistryEntry_, "dst_as"); + +ACLStrategised ACLASN::DestinationRegistryEntry_(new ACLASN, ACLDestinationASNStrategy::Instance(), "dst_as"); + +int +ACLSourceASNStrategy::match (ACLData * &data, ACLFilledChecklist *checklist) +{ + return data->match(checklist->src_addr); +} + +ACLSourceASNStrategy * +ACLSourceASNStrategy::Instance() +{ + return &Instance_; +} + +ACLSourceASNStrategy ACLSourceASNStrategy::Instance_; + + +int +ACLDestinationASNStrategy::match (ACLData * &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 index 747dffe738..0000000000 --- a/src/asn.cc +++ /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::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 *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 *data, IpAddress &addr) -{ - struct squid_radix_node *rn; - as_info *e; - m_ADDR m_addr; - CbDataList *a = NULL; - CbDataList *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 *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 **Tail = NULL; - CbDataList *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 (as_number); - - *(Tail) = q; - - e->e_info = asinfo; - } - } else { - q = new CbDataList (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 *prev = NULL; - CbDataList *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 *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 *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 **curlist = &data; - CbDataList **Tail; - CbDataList *q = NULL; - char *t = NULL; - - for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); - while ((t = strtokFile())) { - q = new CbDataList (atoi(t)); - *(Tail) = q; - Tail = &q->next; - } -} - -ACLData * -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; - -ACL::Prototype ACLASN::SourceRegistryProtoype(&ACLASN::SourceRegistryEntry_, "src_as"); - -ACLStrategised ACLASN::SourceRegistryEntry_(new ACLASN, ACLSourceASNStrategy::Instance(), "src_as"); - -ACL::Prototype ACLASN::DestinationRegistryProtoype(&ACLASN::DestinationRegistryEntry_, "dst_as"); - -ACLStrategised ACLASN::DestinationRegistryEntry_(new ACLASN, ACLDestinationASNStrategy::Instance(), "dst_as"); - -int -ACLSourceASNStrategy::match (ACLData * &data, ACLFilledChecklist *checklist) -{ - return data->match(checklist->src_addr); -} - -ACLSourceASNStrategy * -ACLSourceASNStrategy::Instance() -{ - return &Instance_; -} - -ACLSourceASNStrategy ACLSourceASNStrategy::Instance_; - - -int -ACLDestinationASNStrategy::match (ACLData * &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_; -- 2.47.3