# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: chtsanti@users.sourceforge.net-20080929213814-\ # aea7o7utorr4tgdp # target_branch: file:///home/projects/squid/squid3-bzr/squid-\ # repo/trunk/ # testament_sha1: 14ed8381d8705645f5fd4ef3a3f1a41e8daafed1 # timestamp: 2008-09-30 00:48:07 +0300 # base_revision_id: squid3@treenet.co.nz-20080920100327-\ # h7e6i88s7t5lieme # # Begin patch === modified file 'src/HttpHeader.cc' --- src/HttpHeader.cc 2008-07-13 08:37:43 +0000 +++ src/HttpHeader.cc 2008-07-17 18:33:07 +0000 @@ -112,6 +112,7 @@ {"Proxy-Authentication-Info", HDR_PROXY_AUTHENTICATION_INFO, ftStr}, {"Proxy-Authorization", HDR_PROXY_AUTHORIZATION, ftStr}, {"Proxy-Connection", HDR_PROXY_CONNECTION, ftStr}, + {"Proxy-support", HDR_PROXY_SUPPORT, ftStr}, {"Public", HDR_PUBLIC, ftStr}, {"Range", HDR_RANGE, ftPRange}, {"Referer", HDR_REFERER, ftStr}, @@ -172,6 +173,7 @@ HDR_IF_MATCH, HDR_IF_NONE_MATCH, HDR_LINK, HDR_PRAGMA, HDR_PROXY_CONNECTION, + HDR_PROXY_SUPPORT, HDR_TRANSFER_ENCODING, HDR_UPGRADE, HDR_VARY, === modified file 'src/HttpHeader.h' --- src/HttpHeader.h 2008-07-13 08:37:43 +0000 +++ src/HttpHeader.h 2008-07-17 18:33:07 +0000 @@ -83,6 +83,7 @@ HDR_PROXY_AUTHENTICATION_INFO, HDR_PROXY_AUTHORIZATION, HDR_PROXY_CONNECTION, + HDR_PROXY_SUPPORT, HDR_PUBLIC, HDR_RANGE, HDR_REQUEST_RANGE, /**< some clients use this, sigh */ === modified file 'src/HttpMsg.h' --- src/HttpMsg.h 2008-01-20 15:54:28 +0000 +++ src/HttpMsg.h 2008-09-25 21:25:22 +0000 @@ -89,6 +89,8 @@ virtual bool expectingBody(const HttpRequestMethod&, int64_t&) const = 0; void firstLineBuf(MemBuf&); + + virtual bool inheritProperties(const HttpMsg *aMsg) = 0; protected: virtual bool sanityCheckStartLine(MemBuf *buf, http_status *error) = 0; === modified file 'src/HttpReply.cc' --- src/HttpReply.cc 2008-07-02 03:49:07 +0000 +++ src/HttpReply.cc 2008-09-25 21:25:22 +0000 @@ -563,5 +563,16 @@ rep->pstate = pstate; rep->protocol = protocol; rep->sline = sline; + rep->keep_alive = keep_alive; return rep; } + + +bool HttpReply::inheritProperties(const HttpMsg *aMsg) +{ + const HttpReply *aRep = dynamic_cast(aMsg); + if(!aRep) + return false; + keep_alive = aRep->keep_alive; + return true; +} === modified file 'src/HttpReply.h' --- src/HttpReply.h 2008-05-11 11:37:14 +0000 +++ src/HttpReply.h 2008-09-25 21:25:22 +0000 @@ -99,6 +99,8 @@ virtual bool expectingBody(const HttpRequestMethod&, int64_t&) const; + virtual bool inheritProperties(const HttpMsg *aMsg); + void updateOnNotModified(HttpReply const *other); /** set commonly used info with one call */ === modified file 'src/HttpRequest.cc' --- src/HttpRequest.cc 2008-06-07 05:20:05 +0000 +++ src/HttpRequest.cc 2008-09-25 21:25:22 +0000 @@ -74,6 +74,7 @@ login[0] = '\0'; host[0] = '\0'; auth_user_request = NULL; + pinned_connection = NULL; port = 0; canonical = NULL; memset(&flags, '\0', sizeof(flags)); @@ -127,6 +128,9 @@ range = NULL; } + if(pinned_connection) + cbdataReferenceDone(pinned_connection); + tag.clean(); extacl_user.clean(); @@ -457,3 +461,27 @@ return true; } + +bool HttpRequest::inheritProperties(const HttpMsg *aMsg) +{ + const HttpRequest* aReq = dynamic_cast(aMsg); + if(!aReq) + return false; + + client_addr = aReq->client_addr; + my_addr = aReq->my_addr; + + // This may be too conservative for the 204 No Content case + // may eventually need cloneNullAdaptationImmune() for that. + flags = aReq->flags.cloneAdaptationImmune(); + + if (aReq->auth_user_request) { + auth_user_request = aReq->auth_user_request; + AUTHUSERREQUESTLOCK(auth_user_request, "inheritProperties"); + } + + if(aReq->pinned_connection) { + pinned_connection = cbdataReference(aReq->pinned_connection); + } + return true; +} === modified file 'src/HttpRequest.h' --- src/HttpRequest.h 2008-06-07 05:20:05 +0000 +++ src/HttpRequest.h 2008-09-29 17:09:41 +0000 @@ -98,6 +98,12 @@ private: char host[SQUIDHOSTNAMELEN]; + + /*** + * The client side connection data of pinned connections for the client side + * request related objects + */ + ConnStateData *pinned_connection; public: IPAddress host_addr; @@ -174,6 +180,18 @@ static HttpRequest * CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method); static HttpRequest * CreateFromUrl(char * url); + + void setPinnedConnection(ConnStateData *conn) { + pinned_connection = cbdataReference(conn); + } + + ConnStateData *pinnedConnection() { + return pinned_connection; + } + + void releasePinnedConnection() { + cbdataReferenceDone(pinned_connection); + } private: const char *packableURI(bool full_uri) const; @@ -184,7 +202,8 @@ virtual bool sanityCheckStartLine(MemBuf *buf, http_status *error); virtual void hdrCacheInit(); - + + virtual bool inheritProperties(const HttpMsg *aMsg); }; MEMPROXY_CLASS_INLINE(HttpRequest) /**DOCS_NOSEMI*/ === modified file 'src/ICAP/ICAPModXact.cc' --- src/ICAP/ICAPModXact.cc 2008-09-19 17:26:31 +0000 +++ src/ICAP/ICAPModXact.cc 2008-09-25 21:25:22 +0000 @@ -782,14 +782,16 @@ // allocate the adapted message and copy metainfo Must(!adapted.header); HttpMsg *newHead = NULL; - if (const HttpRequest *oldR = dynamic_cast(oldHead)) { + if (dynamic_cast(oldHead)) { HttpRequest *newR = new HttpRequest; - inheritVirginProperties(*newR, *oldR); newHead = newR; - } else - if (dynamic_cast(oldHead)) - newHead = new HttpReply; + } + else if (dynamic_cast(oldHead)) { + HttpReply *newRep = new HttpReply; + newHead = newRep; + } Must(newHead); + newHead->inheritProperties(oldHead); adapted.setHeader(newHead); @@ -845,15 +847,18 @@ if (!parseHead(adapted.header)) return; // need more header data - if (HttpRequest *newHead = dynamic_cast(adapted.header)) { + if (dynamic_cast(adapted.header)) { const HttpRequest *oldR = dynamic_cast(virgin.header); Must(oldR); // TODO: the adapted request did not really originate from the // client; give proxy admin an option to prevent copying of // sensitive client information here. See the following thread: // http://www.squid-cache.org/mail-archive/squid-dev/200703/0040.html - inheritVirginProperties(*newHead, *oldR); } + + // Maybe adapted.header==NULL if HttpReply and have Http 0.9 .... + if(adapted.header) + adapted.header->inheritProperties(virgin.header); } decideOnParsingBody(); @@ -881,22 +886,6 @@ return true; } -// TODO: Move this method to HttpRequest? -void ICAPModXact::inheritVirginProperties(HttpRequest &newR, const HttpRequest &oldR) { - - newR.client_addr = oldR.client_addr; - newR.my_addr = oldR.my_addr; - - // This may be too conservative for the 204 No Content case - // may eventually need cloneNullAdaptationImmune() for that. - newR.flags = oldR.flags.cloneAdaptationImmune(); - - if (oldR.auth_user_request) { - newR.auth_user_request = oldR.auth_user_request; - AUTHUSERREQUESTLOCK(newR.auth_user_request, "newR in ICAPModXact"); - } -} - void ICAPModXact::decideOnParsingBody() { if (gotEncapsulated("res-body") || gotEncapsulated("req-body")) { debugs(93, 5, HERE << "expecting a body"); @@ -1152,7 +1141,6 @@ HttpRequest* new_request = new HttpRequest; urlParse(old_request->method, old_request->canonical,new_request); new_request->http_ver = old_request->http_ver; - inheritVirginProperties(*new_request, *old_request); headClone = new_request; } else if (const HttpReply *old_reply = dynamic_cast(head)) { @@ -1162,6 +1150,7 @@ } Must(headClone); + headClone->inheritProperties(head); HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry* p_head_entry = NULL; === modified file 'src/ICAP/ICAPModXact.h' --- src/ICAP/ICAPModXact.h 2008-03-31 01:06:13 +0000 +++ src/ICAP/ICAPModXact.h 2008-09-25 21:25:22 +0000 @@ -208,7 +208,6 @@ void parseIcapHead(); void parseHttpHead(); bool parseHead(HttpMsg *head); - void inheritVirginProperties(HttpRequest &newR, const HttpRequest &oldR); void decideOnParsingBody(); void parseBody(); === modified file 'src/ProtoPort.h' --- src/ProtoPort.h 2008-04-09 10:17:28 +0000 +++ src/ProtoPort.h 2008-09-25 21:25:22 +0000 @@ -26,6 +26,7 @@ unsigned int sslBump:1; /**< intercepts CONNECT requests */ int vport; /* virtual port support, -1 for dynamic, >0 static*/ + bool connection_auth_disabled; /* Don't support connection oriented auth */ int disable_pmtu_discovery; struct { === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2008-08-10 05:05:45 +0000 +++ src/cache_cf.cc 2008-09-29 21:32:15 +0000 @@ -1692,6 +1692,7 @@ self_destruct(); p->icp.port = GetUdpService(); + p->connection_auth = 2; /* auto */ while ((token = strtok(NULL, w_space))) { if (!strcasecmp(token, "proxy-only")) { @@ -1829,6 +1830,14 @@ p->front_end_https = 1; } else if (strcmp(token, "front-end-https=auto") == 0) { p->front_end_https = 2; + }else if (strcmp(token, "connection-auth=off") == 0) { + p->connection_auth = 0; + } else if (strcmp(token, "connection-auth") == 0) { + p->connection_auth = 1; + } else if (strcmp(token, "connection-auth=on") == 0) { + p->connection_auth = 1; + } else if (strcmp(token, "connection-auth=auto") == 0) { + p->connection_auth = 2; } else { debugs(3, 0, "parse_peer: token='" << token << "'"); self_destruct(); @@ -2853,6 +2862,7 @@ s->disable_pmtu_discovery = DISABLE_PMTU_OFF; s->name = xstrdup(token); + s->connection_auth_disabled = false; #if USE_IPV6 if (*token == '[') { @@ -2936,6 +2946,14 @@ s->accel = 1; } else if (strcmp(token, "accel") == 0) { s->accel = 1; + } else if (strcmp(token, "no-connection-auth") == 0) { + s->connection_auth_disabled = true; + } else if (strcmp(token, "connection-auth=off") == 0) { + s->connection_auth_disabled = true; + } else if (strcmp(token, "connection-auth") == 0) { + s->connection_auth_disabled = false; + } else if (strcmp(token, "connection-auth=on") == 0) { + s->connection_auth_disabled = false; } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) { if (!strcasecmp(token + 23, "off")) s->disable_pmtu_discovery = DISABLE_PMTU_OFF; @@ -3108,6 +3126,11 @@ if (s->vport) storeAppendPrintf(e, " vport"); + if (s->connection_auth_disabled) + storeAppendPrintf(e, " connection-auth=off"); + else + storeAppendPrintf(e, " connection-auth=on"); + if (s->disable_pmtu_discovery != DISABLE_PMTU_OFF) { const char *pmtu; === modified file 'src/cf.data.pre' --- src/cf.data.pre 2008-09-20 09:43:40 +0000 +++ src/cf.data.pre 2008-09-29 21:32:15 +0000 @@ -1023,6 +1023,11 @@ protocol= Protocol to reconstruct accelerated requests with. Defaults to http. + connection-auth[=on|off] + use connection-auth=off to tell Squid to prevent + forwarding Microsoft connection oriented authentication + (NTLM, Negotiate and Kerberos) + disable-pmtu-discovery= Control Path-MTU discovery usage: off lets OS decide on what to do (default). @@ -1588,6 +1593,7 @@ sslcipher=... ssloptions=... front-end-https[=on|auto] + connection-auth[=on|off|auto] use 'proxy-only' to specify objects fetched from this cache should not be saved locally. @@ -1796,6 +1802,12 @@ on this header. If set to auto the header will only be added if the request is forwarded as a https:// URL. + + use connection-auth=off to tell Squid that this peer does + not support Microsoft connection oriented authentication, + and any such challenges received from there should be + ignored. Default is auto to automatically determine the + status of the peer. DOC_END NAME: cache_peer_domain cache_host_domain === modified file 'src/client_side.cc' --- src/client_side.cc 2008-09-11 04:54:34 +0000 +++ src/client_side.cc 2008-09-29 20:53:18 +0000 @@ -621,6 +621,9 @@ auth_user_request->onConnectionClose(this); } + if (pinning.fd >= 0) + comm_close(pinning.fd); + BodyProducer::swanSong(); flags.swanSang = true; } @@ -1368,6 +1371,12 @@ debugs(33, 3, "ClientSocketContext::keepaliveNextRequest: FD " << conn->fd); connIsFinished(); + if (conn->pinning.pinned && conn->pinning.fd == -1) { + debugs(33, 2, "clientKeepaliveNextRequest: FD " << conn->fd << " Connection was pinned but server side gone. Terminating client connection"); + comm_close(conn->fd); + return; + } + /** \par * Attempt to parse a request from the request buffer. * If we've been fed a pipelined request it may already @@ -3336,6 +3345,9 @@ ConnStateData::ConnStateData() :AsyncJob("ConnStateData"), transparent_ (false), reading_ (false), closing_ (false) { + pinning.fd = -1; + pinning.pinned = false; + pinning.auth = false; } bool @@ -3415,3 +3427,96 @@ if (allocatedSize) memFreeBuf(allocatedSize, buf); } + +/* This is a comm call normally scheduled by comm_close() */ +void +ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io) +{ + pinning.fd = -1; + if (pinning.peer) { + cbdataReferenceDone(pinning.peer); + } + safe_free(pinning.host); + /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host + * connection has gone away */ +} + +void ConnStateData::pinConnection(int pinning_fd, HttpRequest *request, struct peer *peer, bool auth){ + fde *f; + char desc[FD_DESC_SZ]; + + if (pinning.fd == pinning_fd) + return; + else if (pinning.fd != -1) + comm_close(pinning.fd); + + if(pinning.host) + safe_free(pinning.host); + + pinning.fd = pinning_fd; + pinning.host = xstrdup(request->GetHost()); + pinning.port = request->port; + pinning.pinned = true; + if (pinning.peer) + cbdataReferenceDone(pinning.peer); + if (peer) + pinning.peer = cbdataReference(peer); + pinning.auth = auth; + f = &fd_table[fd]; + snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s:%d (%d)", + (auth || !peer) ? request->GetHost() : peer->name, f->ipaddr, (int) f->remote_port, fd); + fd_note(pinning_fd, desc); + + typedef CommCbMemFunT Dialer; + pinning.closeHandler = asyncCall(33, 5, "ConnStateData::clientPinnedConnectionClosed", + Dialer(this, &ConnStateData::clientPinnedConnectionClosed)); + comm_add_close_handler(pinning_fd, pinning.closeHandler); + +} + +int ConnStateData::validatePinnedConnection(HttpRequest *request, const struct peer *peer) +{ + bool valid = true; + if (pinning.fd < 0) + return -1; + + if (pinning.auth && request && strcasecmp(pinning.host, request->GetHost()) != 0) { + valid = false; + } + if (request && pinning.port != request->port){ + valid = false; + } + if (pinning.peer && !cbdataReferenceValid(pinning.peer)){ + valid = false; + } + if (peer != pinning.peer){ + valid = false; + } + + if(!valid) { + int pinning_fd=pinning.fd; + /* The pinning info is not safe, remove any pinning info*/ + unpinConnection(); + + /* also close the server side socket, we should not use it for invalid/unauthenticated + requests... + */ + comm_close(pinning_fd); + return -1; + } + + return pinning.fd; +} + +void ConnStateData::unpinConnection() +{ + if(pinning.peer) + cbdataReferenceDone(pinning.peer); + + if(pinning.closeHandler != NULL) { + comm_remove_close_handler(pinning.fd, pinning.closeHandler); + pinning.closeHandler = NULL; + } + pinning.fd = -1; + safe_free(pinning.host); +} === modified file 'src/client_side.h' --- src/client_side.h 2008-09-11 04:54:34 +0000 +++ src/client_side.h 2008-09-29 21:38:14 +0000 @@ -189,6 +189,16 @@ bool readMoreRequests; bool swanSang; // XXX: temporary flag to check proper cleanup } flags; + struct { + int fd; /* pinned server side connection */ + char *host; /* host name of pinned connection */ + int port; /* port of pinned connection */ + bool pinned; /* this connection was pinned */ + bool auth; /* pinned for www authentication */ + struct peer *peer; /* peer the connection goes via */ + AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/ + } pinning; + http_port_list *port; bool transparent() const; @@ -206,6 +216,31 @@ void handleReadData(char *buf, size_t size); void handleRequestBodyData(); + /** + * Correlate the current ConnStateData object with the pinning_fd socket descriptor. + */ + void pinConnection(int fd, HttpRequest *request, struct peer *peer, bool auth); + /** + * Decorrelate the ConnStateData object from its pinned peer + */ + void unpinConnection(); + /** + * Checks if there is pinning info if it is valid. It can close the server side connection + * if pinned info is not valid. + \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest + \param peer if it is not NULL also check if the peer is the pinning peer + \return The fd of the server side connection or -1 if fails. + */ + int validatePinnedConnection(HttpRequest *request, const struct peer *peer=NULL); + /** + * returts the pinned peer if exists, NULL otherwise + */ + struct peer *pinnedPeer() const {return pinning.peer;} + bool pinnedAuth() const {return pinning.auth;} + + // pining related comm callbacks + void clientPinnedConnectionClosed(const CommCloseCbParams &io); + // comm callbacks void clientReadRequest(const CommIoCbParams &io); void connStateClosed(const CommCloseCbParams &io); === modified file 'src/client_side_reply.cc' --- src/client_side_reply.cc 2008-09-20 05:00:47 +0000 +++ src/client_side_reply.cc 2008-09-25 21:25:22 +0000 @@ -1249,24 +1249,45 @@ /* Filter unproxyable authentication types */ if (http->logType != LOG_TCP_DENIED && - (hdr->has(HDR_WWW_AUTHENTICATE) || hdr->has(HDR_PROXY_AUTHENTICATE))) { + hdr->has(HDR_WWW_AUTHENTICATE)) { HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; - int headers_deleted = 0; + int connection_auth_blocked = 0; while ((e = hdr->getEntry(&pos))) { - if (e->id == HDR_WWW_AUTHENTICATE || e->id == HDR_PROXY_AUTHENTICATE) { + if (e->id == HDR_WWW_AUTHENTICATE) { const char *value = e->value.buf(); if ((strncasecmp(value, "NTLM", 4) == 0 && (value[4] == '\0' || value[4] == ' ')) || (strncasecmp(value, "Negotiate", 9) == 0 && - (value[9] == '\0' || value[9] == ' '))) - hdr->delAt(pos, headers_deleted); + (value[9] == '\0' || value[9] == ' ')) + || + (strncasecmp(value, "Kerberos", 8) == 0 && + (value[8] == '\0' || value[8] == ' '))) + { + if (request->flags.connection_auth_disabled) { + hdr->delAt(pos, connection_auth_blocked); + continue; + } + request->flags.must_keepalive = 1; + if (!request->flags.accelerated && !request->flags.intercepted) { + httpHeaderPutStrf(hdr, HDR_PROXY_SUPPORT, "Session-Based-Authentication"); + /* + We send "[Proxy-]Connection: Proxy-Support" header to mark + Proxy-Support as a hop-by-hop header for intermediaries that do not + understand the semantics of this header. The RFC should have included + this recommendation. + */ + httpHeaderPutStrf(hdr, HDR_CONNECTION, "Proxy-support"); + } + break; + } } } - if (headers_deleted) + + if (connection_auth_blocked) hdr->refreshMask(); } @@ -1324,6 +1345,12 @@ debugs(88, 3, "clientBuildReplyHeader: Shutting down, don't keep-alive."); request->flags.proxy_keepalive = 0; } + + if (request->flags.connection_auth && !reply->keep_alive) { + debugs(33, 2, "clientBuildReplyHeader: Connection oriented auth but server side non-persistent"); + request->flags.proxy_keepalive = 0; + } + /* Append VIA */ if (Config.onoff.via) { === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2008-09-11 11:14:39 +0000 +++ src/client_side_request.cc 2008-09-29 21:32:15 +0000 @@ -828,6 +828,56 @@ if (req_hdr->has(HDR_AUTHORIZATION)) request->flags.auth = 1; + ConnStateData *http_conn = http->getConn(); + assert(http_conn); + request->flags.connection_auth_disabled = http_conn->port->connection_auth_disabled; + if (!request->flags.connection_auth_disabled) { + if (http_conn->pinning.fd != -1) { + if (http_conn->pinning.auth) { + request->flags.connection_auth = 1; + request->flags.auth = 1; + } else { + request->flags.connection_proxy_auth = 1; + } + request->setPinnedConnection(http_conn); + } + } + + /* check if connection auth is used, and flag as candidate for pinning + * in such case. + * Note: we may need to set flags.connection_auth even if the connection + * is already pinned if it was pinned earlier due to proxy auth + */ + if (!request->flags.connection_auth) { + if (req_hdr->has(HDR_AUTHORIZATION) || req_hdr->has(HDR_PROXY_AUTHORIZATION)) { + HttpHeaderPos pos = HttpHeaderInitPos; + HttpHeaderEntry *e; + int may_pin = 0; + while ((e = req_hdr->getEntry(&pos))) { + if (e->id == HDR_AUTHORIZATION || e->id == HDR_PROXY_AUTHORIZATION) { + const char *value = e->value.buf(); + if (strncasecmp(value, "NTLM ", 5) == 0 + || + strncasecmp(value, "Negotiate ", 10) == 0 + || + strncasecmp(value, "Kerberos ", 9) == 0) { + if (e->id == HDR_AUTHORIZATION) { + request->flags.connection_auth = 1; + may_pin = 1; + } else { + request->flags.connection_proxy_auth = 1; + may_pin = 1; + } + } + } + } + if (may_pin && !request->pinnedConnection()) { + request->setPinnedConnection(http->getConn()); + } + } + } + + if (request->login[0] != '\0') request->flags.auth = 1; === modified file 'src/enums.h' --- src/enums.h 2008-07-11 20:43:43 +0000 +++ src/enums.h 2008-07-17 18:33:07 +0000 @@ -177,7 +177,8 @@ ANY_OLD_PARENT, USERHASH_PARENT, SOURCEHASH_PARENT, - HIER_MAX + HIER_MAX, + PINNED } hier_code; /// \ingroup ServerProtocolICPAPI === modified file 'src/forward.cc' --- src/forward.cc 2008-09-18 09:46:56 +0000 +++ src/forward.cc 2008-09-29 20:53:18 +0000 @@ -804,6 +804,35 @@ if (ftimeout < ctimeout) ctimeout = ftimeout; + + request->flags.pinned = 0; + if (fs->code == PINNED) { + ConnStateData *pinned_connection = request->pinnedConnection(); + assert(pinned_connection); + fd = pinned_connection->validatePinnedConnection(request, fs->_peer); + if (fd >= 0) { + pinned_connection->unpinConnection(); +#if 0 + if (!fs->_peer) + fs->code = HIER_DIRECT; +#endif + server_fd = fd; + n_tries++; + request->flags.pinned = 1; + if (pinned_connection->pinnedAuth()) + request->flags.auth = 1; + comm_add_close_handler(fd, fwdServerClosedWrapper, this); + connectDone(fd, COMM_OK, 0); + return; + } + /* Failure. Fall back on next path */ + request->releasePinnedConnection(); + servers = fs->next; + fwdServerFree(fs); + connectStart(); + return; + } + fd = fwdPconnPool->pop(host, port, domain, client_addr, checkRetriable()); if (fd >= 0) { debugs(17, 3, "fwdConnectStart: reusing pconn FD " << fd); === modified file 'src/http.cc' --- src/http.cc 2008-09-13 13:43:00 +0000 +++ src/http.cc 2008-09-29 20:53:18 +0000 @@ -377,7 +377,7 @@ } } - if (request->flags.auth) { + if (request->flags.auth || request->flags.auth_sent) { /* * Responses to requests with authorization may be cached * only if a Cache-Control: public reply header is present. @@ -709,6 +709,9 @@ httpChunkDecoder = new ChunkedCodingParser; } + if(!peerSupportsConnectionPinning()) + orig_request->flags.connection_auth_disabled = 1; + HttpReply *vrep = setVirginReply(newrep); flags.headers_parsed = 1; @@ -726,6 +729,67 @@ } +/** + * returns true if the peer can support connection pinning +*/ +bool HttpStateData::peerSupportsConnectionPinning() const +{ + const HttpReply *rep = entry->mem_obj->getReply(); + const HttpHeader *hdr = &rep->header; + bool rc; + String header; + + if (!_peer) + return true; + + /*If this peer does not support connection pinning (authenticated + connections) return false + */ + if (!_peer->connection_auth) + return false; + + /*The peer supports connection pinning and the http reply status + is not unauthorized, so the related connection can be pinned + */ + if (rep->sline.status != HTTP_UNAUTHORIZED) + return true; + + /*The server respond with HTTP_UNAUTHORIZED and the peer configured + with "connection-auth=on" we know that the peer supports pinned + connections + */ + if (_peer->connection_auth == 1) + return true; + + /*At this point peer has configured with "connection-auth=auto" + parameter so we need some extra checks to decide if we are going + to allow pinned connections or not + */ + + /*if the peer configured with originserver just allow connection + pinning (squid 2.6 behaviour) + */ + if (_peer->options.originserver) + return true; + + /*if the connections it is already pinned it is OK*/ + if (request->flags.pinned) + return true; + + /*Allow pinned connections only if the Proxy-support header exists in + reply and has in its list the "Session-Based-Authentication" + which means that the peer supports connection pinning. + */ + if (!hdr->has(HDR_PROXY_SUPPORT)) + return false; + + header = hdr->getStrOrList(HDR_PROXY_SUPPORT); + /* XXX This ought to be done in a case-insensitive manner */ + rc = (strstr(header.buf(), "Session-Based-Authentication") != NULL); + + return rc; +} + // Called when we parsed (and possibly adapted) the headers but // had not starting storing (a.k.a., sending) the body yet. void @@ -1135,6 +1199,7 @@ { AsyncCall::Pointer call; IPAddress client_addr; + bool ispinned = false; if (!flags.headers_parsed) { flags.do_next_read = 1; @@ -1200,7 +1265,17 @@ if (orig_request->flags.spoof_client_ip) client_addr = orig_request->client_addr; - if (_peer) { + + if (request->flags.pinned) { + ispinned = true; + } else if (request->flags.connection_auth && request->flags.auth_sent) { + ispinned = true; + } + + if (orig_request->pinnedConnection() && ispinned) { + orig_request->pinnedConnection()->pinConnection(fd, orig_request, _peer, + (request->flags.connection_auth != 0)); + } else if (_peer) { if (_peer->options.originserver) fwd->pconnPush(fd, _peer->name, orig_request->port, orig_request->GetHost(), client_addr); else @@ -1709,7 +1784,7 @@ */ if (NULL == orig_request->range || !orig_request->flags.cachable - || orig_request->range->offsetLimitExceeded()) + || orig_request->range->offsetLimitExceeded() || orig_request->flags.connection_auth) result = false; debugs(11, 8, "decideIfWeDoRanges: range specs: " << @@ -1739,6 +1814,12 @@ HttpHeader hdr(hoRequest); Packer p; httpBuildRequestHeader(request, orig_request, entry, &hdr, flags); + + if (request->flags.pinned && request->flags.connection_auth) + request->flags.auth_sent = 1; + else if (hdr.has(HDR_AUTHORIZATION)) + request->flags.auth_sent = 1; + packerToMemInit(&p, mb); hdr.packInto(&p); hdr.clean(); @@ -1792,7 +1873,9 @@ /* * Is keep-alive okay for all request methods? */ - if (!Config.onoff.server_pconns) + if (orig_request->flags.must_keepalive) + flags.keepalive = 1; + else if (!Config.onoff.server_pconns) flags.keepalive = 0; else if (_peer == NULL) flags.keepalive = 1; === modified file 'src/http.h' --- src/http.h 2008-09-13 13:43:00 +0000 +++ src/http.h 2008-09-25 21:25:22 +0000 @@ -118,6 +118,7 @@ MemBuf * mb, http_state_flags flags); static bool decideIfWeDoRanges (HttpRequest * orig_request); + bool peerSupportsConnectionPinning() const; ChunkedCodingParser *httpChunkDecoder; private: === modified file 'src/neighbors.cc' --- src/neighbors.cc 2008-07-18 11:24:16 +0000 +++ src/neighbors.cc 2008-09-20 15:39:41 +0000 @@ -51,7 +51,7 @@ /* count mcast group peers every 15 minutes */ #define MCAST_COUNT_RATE 900 -static int peerAllowedToUse(const peer *, HttpRequest *); +int peerAllowedToUse(const peer *, HttpRequest *); static int peerWouldBePinged(const peer *, HttpRequest *); static void neighborRemove(peer *); static void neighborAlive(peer *, const MemObject *, const icp_common_t *); @@ -136,7 +136,7 @@ * this function figures out if it is appropriate to fetch REQUEST * from PEER. */ -static int +int peerAllowedToUse(const peer * p, HttpRequest * request) { @@ -1635,6 +1635,13 @@ if (p->domain) storeAppendPrintf(sentry, " forceddomain=%s", p->domain); + if(p->connection_auth == 0) + storeAppendPrintf(sentry, " connection-auth=off"); + else if(p->connection_auth == 1) + storeAppendPrintf(sentry, " connection-auth=on"); + else if(p->connection_auth == 2) + storeAppendPrintf(sentry, " connection-auth=auto"); + storeAppendPrintf(sentry, "\n"); } === modified file 'src/peer_select.cc' --- src/peer_select.cc 2008-07-11 20:43:43 +0000 +++ src/peer_select.cc 2008-09-29 20:53:18 +0000 @@ -100,6 +100,7 @@ static void peerGetSomeParent(ps_state *); static void peerGetAllParents(ps_state *); static void peerAddFwdServer(FwdServer **, peer *, hier_code); +static void peerSelectPinned(ps_state * ps); CBDATA_CLASS_INIT(ps_state); @@ -322,6 +323,8 @@ debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct]); } + if (!entry || entry->ping_status == PING_NONE) + peerSelectPinned(ps); if (entry == NULL) { (void) 0; } else if (entry->ping_status == PING_NONE) { @@ -363,6 +366,33 @@ } /* + * peerSelectPinned + * + * Selects a pinned connection + */ +int peerAllowedToUse(const peer * p, HttpRequest * request); +static void +peerSelectPinned(ps_state * ps) +{ + HttpRequest *request = ps->request; + peer *peer; + if (!request->pinnedConnection()) + return; + if (request->pinnedConnection()->validatePinnedConnection(request) != -1) { + peer = request->pinnedConnection()->pinnedPeer(); + if (peer && peerAllowedToUse(peer, request)) { + peerAddFwdServer(&ps->servers, peer, PINNED); + if (ps->entry) + ps->entry->ping_status = PING_DONE; /* Skip ICP */ + } else if (!peer && ps->direct != DIRECT_NO) { + peerAddFwdServer(&ps->servers, NULL, PINNED); + if (ps->entry) + ps->entry->ping_status = PING_DONE; /* Skip ICP */ + } + } +} + +/* * peerGetSomeNeighbor * * Selects a neighbor (parent or sibling) based on one of the === modified file 'src/structs.h' --- src/structs.h 2008-08-09 06:24:33 +0000 +++ src/structs.h 2008-09-25 21:25:22 +0000 @@ -1011,6 +1011,7 @@ #endif int front_end_https; + int connection_auth; }; struct _net_db_name @@ -1095,6 +1096,11 @@ unsigned int internal:1; unsigned int internalclient:1; unsigned int must_keepalive:1; + unsigned int connection_auth:1; /** Request wants connection oriented auth */ + unsigned int connection_auth_disabled:1; /** Connection oriented auth can not be supported */ + unsigned int connection_proxy_auth:1; /** Request wants connection oriented auth */ + unsigned int pinned:1; /* Request sent on a pinned connection */ + unsigned int auth_sent:1; /* Authentication forwarded */ // When adding new flags, please update cloneAdaptationImmune() as needed. # Begin bundle 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 EqSpTc1grERcP/D8mf6BdyRThQkIgi+/wA==