From: Amos Jeffries Date: Wed, 4 Feb 2009 09:52:20 +0000 (+1300) Subject: Bug 2526: pt 2: default ALLOW when no list specified. X-Git-Tag: SQUID_3_2_0_1~1216 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b50e327b7c2f2dc02442ba2e12fd652b627805f5;p=thirdparty%2Fsquid.git Bug 2526: pt 2: default ALLOW when no list specified. Fallout from audit of access control checks. - Some got sensible defaults added - many got slightly more optimized defaults - documented the ACLChecklist interface and some API cleanups --- diff --git a/src/ACL.h b/src/ACL.h index 918019521c..374bca5077 100644 --- a/src/ACL.h +++ b/src/ACL.h @@ -140,6 +140,13 @@ public: }; }; +/// \ingroup ACLAPI +typedef enum { + ACCESS_DENIED, + ACCESS_ALLOWED, + ACCESS_REQ_PROXY_AUTH +} allow_t; + /// \ingroup ACLAPI class acl_access { diff --git a/src/ACLChecklist.cc b/src/ACLChecklist.cc index 097a061ede..33b317e31c 100644 --- a/src/ACLChecklist.cc +++ b/src/ACLChecklist.cc @@ -419,7 +419,7 @@ ACLChecklist::~ACLChecklist() ConnStateData * -ACLChecklist::conn() +ACLChecklist::conn() const { return conn_; } @@ -480,6 +480,11 @@ ACLChecklist::asyncState() const return state_; } +/** + * Kick off a non-blocking (slow) ACL access list test + * + * NP: this should probably be made Async now. + */ void ACLChecklist::nonBlockingCheck(PF * callback_, void *callback_data_) { diff --git a/src/ACLChecklist.h b/src/ACLChecklist.h index 1b92ad9442..850d3a9d9a 100644 --- a/src/ACLChecklist.h +++ b/src/ACLChecklist.h @@ -33,12 +33,14 @@ #ifndef SQUID_ACLCHECKLIST_H #define SQUID_ACLCHECKLIST_H -#include "typedefs.h" -#include "client_side.h" -#include "structs.h" +//#include "typedefs.h" +//#include "client_side.h" +//#include "structs.h" -class ExternalACLEntry; +#include "ACL.h" +class AuthUserRequest; +class ExternalACLEntry; class ConnStateData; /// \ingroup ACLAPI @@ -86,40 +88,100 @@ public: }; +public: /* operators */ void *operator new(size_t); void operator delete(void *); ACLChecklist(); ~ACLChecklist(); - /* To cause link failures if assignment attempted */ + /** NP: To cause link failures if assignment attempted */ ACLChecklist (ACLChecklist const &); + /** NP: To cause link failures if assignment attempted */ ACLChecklist &operator=(ACLChecklist const &); +public: /* API methods */ + + /** + * Trigger off a non-blocking access check for a set of *_access options.. + * The callback specified will be called with true/false + * when the results of the ACL tests are known. + */ void nonBlockingCheck(PF * callback, void *callback_data); + + /** + * Trigger a blocking access check for a set of *_access options. + * + * ACLs which cannot be satisfied directly from available data are ignored. + * This means any proxy_auth, external_acl, DNS lookups, Ident lookups etc + * which have not already been performed and cached will not be checked. + * + * If there is no access list to check the default is to return DENIED. + * However callers should perform their own check and default based on local + * knowledge of the ACL usage rather than depend on this default. + * That will also save on work setting up ACLChecklist fields for a no-op. + * + * \retval 1/true Access Allowed + * \retval 0/false Access Denied + */ int fastCheck(); - void checkCallback(allow_t answer); - void preCheck(); + + /** + * Trigger a blocking access check for a single ACL line (a AND b AND c). + * + * ACLs which cannot be satisfied directly from available data are ignored. + * This means any proxy_auth, external_acl, DNS lookups, Ident lookups etc + * which have not already been performed and cached will not be checked. + * + * \retval 1/true Access Allowed + * \retval 0/false Access Denied + */ _SQUID_INLINE_ bool matchAclListFast(const ACLList * list); - ConnStateData * conn(); - int fd() const; // uses conn() if available - // set either conn or FD + /** + * Attempt to check the current checklist against current data. + * This is the core routine behind all ACL test routines. + * As much as possible of current tests are performed immediately + * and the result is maybe delayed to wait for async lookups. + * + * When all tests are done callback is presented with one of: + * \item ACCESS_ALLOWED Access explicitly Allowed + * \item ACCESS_DENIED Access explicitly Denied + */ + void check(); + + ConnStateData * conn() const; + + /// uses conn() if available + int fd() const; + + /// set either conn void conn(ConnStateData *); + /// set FD void fd(int aDescriptor); +/* Accessors used by internal ACL stuff */ + int authenticated(); bool asyncInProgress() const; void asyncInProgress(bool const); + bool finished() const; void markFinished(); - void check(); + allow_t const & currentAnswer() const; void currentAnswer(allow_t const); + + void changeState(AsyncState *); + AsyncState *asyncState() const; + +private: /* NP: only used internally */ + + void checkCallback(allow_t answer); void checkAccessList(); void checkForAsync(); - void changeState (AsyncState *); - AsyncState *asyncState() const; + +public: /* checklist available data */ const acl_access *accessList; @@ -132,6 +194,7 @@ public: struct peer *dst_peer; HttpRequest *request; + /* for acls that look at reply data */ HttpReply *reply; char rfc931[USER_IDENT_SZ]; @@ -148,17 +211,20 @@ public: PF *callback; void *callback_data; ExternalACLEntry *extacl_entry; + bool destinationDomainChecked() const; void markDestinationDomainChecked(); bool sourceDomainChecked() const; void markSourceDomainChecked(); -private: +private: /* internal methods */ + void preCheck(); void matchAclList(const ACLList * list, bool const fast); void matchAclListSlow(const ACLList * list); CBDATA_CLASS(ACLChecklist); - ConnStateData * conn_; /* hack for ident and NTLM */ - int fd_; // may be available when conn_ is not + + ConnStateData * conn_; /**< hack for ident and NTLM */ + int fd_; /**< may be available when conn_ is not */ bool async_; bool finished_; allow_t allow_; diff --git a/src/ACLMyPortName.cc b/src/ACLMyPortName.cc index d48b051a55..fed20b6921 100644 --- a/src/ACLMyPortName.cc +++ b/src/ACLMyPortName.cc @@ -39,6 +39,9 @@ #include "ACLStringData.h" #include "ACLChecklist.h" +/* for ConnStateData */ +#include "client_side.h" + ACL::Prototype ACLMyPortName::RegistryProtoype(&ACLMyPortName::RegistryEntry_, "myportname"); diff --git a/src/DelayId.cc b/src/DelayId.cc index 3b8f6ebadf..986c1ec7a1 100644 --- a/src/DelayId.cc +++ b/src/DelayId.cc @@ -106,6 +106,14 @@ DelayId::DelayClient(ClientHttpRequest * http) } for (pool = 0; pool < DelayPools::pools(); pool++) { + + /* pools require explicit 'allow' to assign a client into them */ + if (!DelayPools::delay_data[pool].access) { + debugs(77, DBG_IMPORTANT, "delay_pool " << pool << + " has no delay_access configured. This means that no clients will ever use it."); + continue; + } + ACLChecklist ch; #if FOLLOW_X_FORWARDED_FOR if (Config.onoff.delay_pool_uses_indirect_client) @@ -124,8 +132,8 @@ DelayId::DelayClient(ClientHttpRequest * http) /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */ - if (DelayPools::delay_data[pool].theComposite().getRaw() && - ch.fastCheck()) { + if (DelayPools::delay_data[pool].theComposite().getRaw() && ch.fastCheck()) { + DelayId result (pool + 1); CompositePoolNode::CompositeSelectionDetails details; details.src_addr = ch.src_addr; diff --git a/src/HttpHeaderTools.cc b/src/HttpHeaderTools.cc index 289ccc8b89..ba1cfe7e78 100644 --- a/src/HttpHeaderTools.cc +++ b/src/HttpHeaderTools.cc @@ -86,7 +86,7 @@ httpHeaderMaskInit(HttpHeaderMask * mask, int value) memset(mask, value, sizeof(*mask)); } -/* calculates a bit mask of a given array; does not reset mask! */ +/** calculates a bit mask of a given array; does not reset mask! */ void httpHeaderCalcMask(HttpHeaderMask * mask, http_hdr_type http_hdr_type_enums[], size_t count) { @@ -182,7 +182,7 @@ httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive) return res; } -/* returns true iff "m" is a member of the list */ +/** returns true iff "m" is a member of the list */ int strListIsMember(const String * list, const char *m, char del) { @@ -201,14 +201,14 @@ strListIsMember(const String * list, const char *m, char del) return 0; } -/* returns true iff "s" is a substring of a member of the list */ +/** returns true iff "s" is a substring of a member of the list */ int strListIsSubstr(const String * list, const char *s, char del) { assert(list && del); return list->pos(s) != 0; - /* + /** \note * Note: the original code with a loop is broken because it uses strstr() * instead of strnstr(). If 's' contains a 'del', strListIsSubstr() may * return true when it should not. If 's' does not contain a 'del', the @@ -217,7 +217,7 @@ strListIsSubstr(const String * list, const char *s, char del) */ } -/* appends an item to the list */ +/** appends an item to the list */ void strListAdd(String * str, const char *item, char del) { @@ -234,7 +234,7 @@ strListAdd(String * str, const char *item, char del) str->append(item, strlen(item)); } -/* +/** * iterates through a 0-terminated string of items separated by 'del's. * white space around 'del' is considered to be a part of 'del' * like strtok, but preserves the source, and can iterate several strings at once @@ -301,7 +301,7 @@ strListGetItem(const String * str, char del, const char **item, int *ilen, const return len > 0; } -/* handy to printf prefixes of potentially very long buffers */ +/** handy to printf prefixes of potentially very long buffers */ const char * getStringPrefix(const char *str, const char *end) { @@ -312,7 +312,7 @@ getStringPrefix(const char *str, const char *end) return buf; } -/* +/** * parses an int field, complains if soemthing went wrong, returns true on * success */ @@ -342,7 +342,8 @@ httpHeaderParseOffset(const char *start, int64_t * value) } -/* Parses a quoted-string field (RFC 2616 section 2.2), complains if +/** + * Parses a quoted-string field (RFC 2616 section 2.2), complains if * something went wrong, returns non-zero on success. * start should point at the first ". * RC TODO: This is too looose. We should honour the BNF and exclude CTL's @@ -373,9 +374,13 @@ httpHeaderParseQuotedString (const char *start, String *val) } } -/* - * httpHdrMangle checks the anonymizer (header_access) configuration. - * Returns 1 if the header is allowed. +/** + * Checks the anonymizer (header_access) configuration. + * + * \retval 0 Header is explicitly blocked for removal + * \retval 1 Header is explicitly allowed + * \retval 1 Header has been replaced, the current version can be used. + * \retval 1 Header has no access controls to test */ static int httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep) @@ -396,10 +401,15 @@ httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep) hm = &Config.request_header_access[e->id]; } + /* mangler or checklist went away. default allow */ + if(!hm || !hm->access_list) { + return 1; + } + checklist = aclChecklistCreate(hm->access_list, request, NULL); - if (1 == checklist->fastCheck()) { - /* aclCheckFast returns 1 for allow. */ + if (checklist->fastCheck()) { + /* aclCheckFast returns true for allow. */ retval = 1; } else if (NULL == hm->replacement) { /* It was denied, and we don't have any replacement */ @@ -417,7 +427,7 @@ httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep) return retval; } -/* Mangles headers for a list of headers. */ +/** Mangles headers for a list of headers. */ void httpHdrMangleList(HttpHeader * l, HttpRequest * request, int req_or_rep) { @@ -433,7 +443,7 @@ httpHdrMangleList(HttpHeader * l, HttpRequest * request, int req_or_rep) l->refreshMask(); } -/* +/** * return 1 if manglers are configured. Used to set a flag * for optimization during request forwarding. */ diff --git a/src/HttpReply.cc b/src/HttpReply.cc index f0fabc45f2..92547dfe4a 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -543,7 +543,8 @@ HttpReply::calcMaxBodySize(HttpRequest& request) ch.reply = HTTPMSGLOCK(this); // XXX: this lock makes method non-const ch.request = HTTPMSGLOCK(&request); for (acl_size_t *l = Config.ReplyBodySize; l; l = l -> next) { - if (ch.matchAclListFast(l->aclList)) { + /* if there is no ACL list or if the ACLs listed match use this size value */ + if (!l->aclList || ch.matchAclListFast(l->aclList)) { debugs(58, 4, HERE << "bodySizeMax=" << bodySizeMax); bodySizeMax = l->size; // may be -1 break; diff --git a/src/adaptation/AccessCheck.cc b/src/adaptation/AccessCheck.cc index ba1f84a962..290e0b3b29 100644 --- a/src/adaptation/AccessCheck.cc +++ b/src/adaptation/AccessCheck.cc @@ -104,6 +104,7 @@ Adaptation::AccessCheck::checkCandidates() while (!candidates.empty()) { if (AccessRule *r = FindRule(topCandidate())) { + /* BUG 2526: what to do when r->acl is empty?? */ // XXX: we do not have access to conn->rfc931 here. acl_checklist = aclChecklistCreate(r->acl, req, dash_str); acl_checklist->reply = rep ? HTTPMSGLOCK(rep) : NULL; diff --git a/src/client_side.cc b/src/client_side.cc index 2dd1a45e62..e647a08137 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -2857,19 +2857,16 @@ httpAccept(int sock, int newfd, ConnectionDetail *details, #if USE_IDENT - ACLChecklist identChecklist; - - identChecklist.src_addr = details->peer; - - identChecklist.my_addr = details->me; - - identChecklist.accessList = cbdataReference(Config.accessList.identLookup); - - /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */ - - if (identChecklist.fastCheck()) - identStart(details->me, details->peer, clientIdentDone, connState); + if (Config.accessList.identLookup) { + ACLChecklist identChecklist; + identChecklist.src_addr = details->peer; + identChecklist.my_addr = details->me; + identChecklist.accessList = cbdataReference(Config.accessList.identLookup); + /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */ + if (identChecklist.fastCheck()) + identStart(details->me, details->peer, clientIdentDone, connState); + } #endif if (s->tcp_keepalive.enabled) { @@ -3075,18 +3072,16 @@ httpsAccept(int sock, int newfd, ConnectionDetail *details, #if USE_IDENT - ACLChecklist identChecklist; + if (Config.accessList.identLookup) { + ACLChecklist identChecklist; + identChecklist.src_addr = details->peer; + identChecklist.my_addr = details->me; + identChecklist.accessList = cbdataReference(Config.accessList.identLookup); - identChecklist.src_addr = details->peer; - - identChecklist.my_addr = details->me; - - identChecklist.accessList = cbdataReference(Config.accessList.identLookup); - - /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */ - - if (identChecklist.fastCheck()) - identStart(details->me, details->peer, clientIdentDone, connState); + /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */ + if (identChecklist.fastCheck()) + identStart(details->me, details->peer, clientIdentDone, connState); + } #endif diff --git a/src/client_side_reply.cc b/src/client_side_reply.cc index f166aaa0c4..7f200aacb2 100644 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@ -1758,8 +1758,10 @@ clientReplyContext::sendBodyTooLargeError() void clientReplyContext::processReplyAccess () { + /* NP: this should probably soft-fail to a zero-sized-reply error ?? */ assert(reply); - /* Dont't block our own responses or HTTP status messages */ + + /** Don't block our own responses or HTTP status messages */ if (http->logType == LOG_TCP_DENIED || http->logType == LOG_TCP_DENIED_REPLY || alwaysAllowResponse(reply->sline.status)) { @@ -1768,6 +1770,7 @@ clientReplyContext::processReplyAccess () return; } + /** Check for reply to big error */ if (reply->expectedBodyTooLarge(*http->request)) { sendBodyTooLargeError(); return; @@ -1775,11 +1778,13 @@ clientReplyContext::processReplyAccess () headers_sz = reply->hdr_sz; + /** check for absent access controls (permit by default) */ if (!Config.accessList.reply) { processReplyAccessResult(1); return; } + /** Process http_reply_access lists */ ACLChecklist *replyChecklist; replyChecklist = clientAclChecklistCreate(Config.accessList.reply, http); replyChecklist->reply = HTTPMSGLOCK(reply); diff --git a/src/client_side_request.cc b/src/client_side_request.cc index cf8d0a6847..e6a665ff0e 100644 --- a/src/client_side_request.cc +++ b/src/client_side_request.cc @@ -509,8 +509,13 @@ ClientRequestContext::clientAccessCheck() } #endif /* FOLLOW_X_FORWARDED_FOR */ - acl_checklist = clientAclChecklistCreate(Config.accessList.http, http); - acl_checklist->nonBlockingCheck(clientAccessCheckDoneWrapper, this); + if (Config.accessList.http) { + acl_checklist = clientAclChecklistCreate(Config.accessList.http, http); + acl_checklist->nonBlockingCheck(clientAccessCheckDoneWrapper, this); + } else { + debugs(0, DBG_CRITICAL, "No http_access configuration found. This will block ALL traffic"); + clientAccessCheckDone(ACCESS_DENIED); + } } void @@ -1022,11 +1027,19 @@ ClientRequestContext::clientRedirectDone(char *result) http->doCallouts(); } +/** Test cache allow/deny configuration + * Sets flags.cachable=1 if caching is not denied. + */ void ClientRequestContext::checkNoCache() { - acl_checklist = clientAclChecklistCreate(Config.accessList.noCache, http); - acl_checklist->nonBlockingCheck(checkNoCacheDoneWrapper, this); + if (Config.accessList.noCache) { + acl_checklist = clientAclChecklistCreate(Config.accessList.noCache, http); + acl_checklist->nonBlockingCheck(checkNoCacheDoneWrapper, this); + } else { + /* unless otherwise specified, we try to cache. */ + checkNoCacheDone(1); + } } static void diff --git a/src/enums.h b/src/enums.h index 8c7598924b..ea308a5549 100644 --- a/src/enums.h +++ b/src/enums.h @@ -349,12 +349,6 @@ typedef enum { STREAM_FAILED } clientStream_status_t; -typedef enum { - ACCESS_DENIED, - ACCESS_ALLOWED, - ACCESS_REQ_PROXY_AUTH -} allow_t; - typedef enum { AUTH_ACL_CHALLENGE = -2, AUTH_ACL_HELPER = -1, diff --git a/src/forward.cc b/src/forward.cc index a03a8fa014..6cab0929fb 100644 --- a/src/forward.cc +++ b/src/forward.cc @@ -194,14 +194,15 @@ FwdState::~FwdState() void FwdState::fwdStart(int client_fd, StoreEntry *entry, HttpRequest *request) { - /* + /** \note * client_addr == no_addr indicates this is an "internal" request * from peer_digest.c, asn.c, netdb.c, etc and should always * be allowed. yuck, I know. */ - if ( !request->client_addr.IsNoAddr() && request->protocol != PROTO_INTERNAL && request->protocol != PROTO_CACHEOBJ) { - /* + if ( Config.accessList.miss && !request->client_addr.IsNoAddr() && + request->protocol != PROTO_INTERNAL && request->protocol != PROTO_CACHEOBJ) { + /** * Check if this host is allowed to fetch MISSES from us (miss_access) */ ACLChecklist ch; @@ -1312,7 +1313,7 @@ aclMapAddr(acl_address * head, ACLChecklist * ch) IpAddress addr; for (l = head; l; l = l->next) { - if (ch->matchAclListFast(l->aclList)) + if (!l->aclList || ch->matchAclListFast(l->aclList)) return l->addr; } @@ -1330,7 +1331,7 @@ aclMapTOS(acl_tos * head, ACLChecklist * ch) acl_tos *l; for (l = head; l; l = l->next) { - if (ch->matchAclListFast(l->aclList)) + if (!l->aclList || ch->matchAclListFast(l->aclList)) return l->tos; } @@ -1345,6 +1346,10 @@ getOutgoingAddr(HttpRequest * request, struct peer *dst_peer) if (request && request->flags.spoof_client_ip) return request->client_addr; + if (!Config.accessList.outgoing_address) { + return IpAddress(); // anything will do. + } + ch.dst_peer = dst_peer; if (request) { diff --git a/src/htcp.cc b/src/htcp.cc index 77e5645d56..fe3bbf7b16 100644 --- a/src/htcp.cc +++ b/src/htcp.cc @@ -844,9 +844,12 @@ htcpUnpackDetail(char *buf, int sz) } static int - htcpAccessCheck(acl_access * acl, htcpSpecifier * s, IpAddress &from) { + /* default deny if no access list present */ + if (!acl) + return 0; + ACLChecklist checklist; checklist.src_addr = from; checklist.my_addr.SetNoAddr(); diff --git a/src/icp_v2.cc b/src/icp_v2.cc index 6b3f1a519c..ec7d8c7f94 100644 --- a/src/icp_v2.cc +++ b/src/icp_v2.cc @@ -405,6 +405,10 @@ icpDenyAccess(IpAddress &from, char *url, int reqnum, int fd) int icpAccessAllowed(IpAddress &from, HttpRequest * icp_request) { + /* absent an explicit allow, we deny all */ + if (!Config.accessList.icp) + return 0; + ACLChecklist checklist; checklist.src_addr = from; checklist.my_addr.SetNoAddr(); diff --git a/src/peer_select.cc b/src/peer_select.cc index a5eb32c261..e9f4a5c3b2 100644 --- a/src/peer_select.cc +++ b/src/peer_select.cc @@ -290,18 +290,21 @@ peerSelectFoo(ps_state * ps) HttpRequest *request = ps->request; debugs(44, 3, "peerSelectFoo: '" << RequestMethodStr(request->method) << " " << request->GetHost() << "'"); + /** If we don't known whether DIRECT is permitted ... */ if (ps->direct == DIRECT_UNKNOWN) { if (ps->always_direct == 0 && Config.accessList.AlwaysDirect) { + /** check always_direct; */ ps->acl_checklist = aclChecklistCreate( Config.accessList.AlwaysDirect, request, NULL); /* ident */ - ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone, - ps); + ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone, ps); return; } else if (ps->always_direct > 0) { + /** if always_direct says YES, do that. */ ps->direct = DIRECT_YES; } else if (ps->never_direct == 0 && Config.accessList.NeverDirect) { + /** check never_direct; */ ps->acl_checklist = aclChecklistCreate( Config.accessList.NeverDirect, request, @@ -310,10 +313,13 @@ peerSelectFoo(ps_state * ps) ps); return; } else if (ps->never_direct > 0) { + /** if always_direct says NO, do that. */ ps->direct = DIRECT_NO; } else if (request->flags.accelerated) { + /** if we are accelerating, direct is not an option. */ ps->direct = DIRECT_NO; } else if (request->flags.loopdetect) { + /** if we are in a forwarding-loop, direct is not an option. */ ps->direct = DIRECT_YES; } else if (peerCheckNetdbDirect(ps)) { ps->direct = DIRECT_YES; diff --git a/src/snmp_core.cc b/src/snmp_core.cc index 71cd059529..5c4b9d9cae 100644 --- a/src/snmp_core.cc +++ b/src/snmp_core.cc @@ -532,7 +532,9 @@ snmpDecodePacket(snmp_request_t * rq) rq->session.Version = SNMP_VERSION_1; Community = snmp_parse(&rq->session, PDU, buf, len); - if (Community) { + /* Check if we have explicit permission to access SNMP data. + * default (set above) is to deny all */ + if (Community && Config.accessList.snmp) { ACLChecklist checklist; checklist.accessList = cbdataReference(Config.accessList.snmp); checklist.src_addr = rq->from; diff --git a/src/tunnel.cc b/src/tunnel.cc index aad28a28af..7048133277 100644 --- a/src/tunnel.cc +++ b/src/tunnel.cc @@ -613,9 +613,10 @@ tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr) * be allowed. yuck, I know. */ - if (!request->client_addr.IsNoAddr()) { + if (!request->client_addr.IsNoAddr() && Config.accessList.miss) { /* * Check if this host is allowed to fetch MISSES from us (miss_access) + * default is to allow. */ ACLChecklist ch; ch.src_addr = request->client_addr;