accel Accelerator / reverse proxy mode
+ tproxy Support Linux TPROXY for spoofing outgoing
+ connections using the client IP address.
+ NP: disables authentication and maybe IPv6 on the port.
+
+ ssl-bump Intercept each SSL request matching ssl_bump ACL,
+ establish secure connection with the client and with
+ the server, decrypt HTTP messages as they pass through
+ Squid, and treat them as unencrypted HTTP messages,
+ becoming the man-in-the-middle.
+
+ The ssl_bump option is required to fully enable
+ the SslBump feature.
+
+ Requires tproxy.
+
Omitting the mode flag causes default forward proxy mode to be used.
sslcontext= SSL session ID context identifier.
+ generate-host-certificates[=<on|off>]
+ Dynamically create SSL server certificates for the
+ destination hosts of bumped SSL requests.When
+ enabled, the cert and key options are used to sign
+ generated certificates. Otherwise generated
+ certificate will be selfsigned.
+ If there is CA certificate life time of generated
+ certificate equals lifetime of CA certificate. If
+ generated certificate is selfsigned lifetime is three
+ years.
+ This option is enabled by default when SslBump is used.
+ See the sslBump option above for more information.
+
+ dynamic_cert_mem_cache_size=SIZE
+ Approximate total RAM size spent on cached generated
+ certificates. If set to zero, caching is disabled. The
+ default value is 4MB. An average XXX-bit certificate
+ consumes about XXX bytes of RAM.
+
DOC_END
NAME: tcp_outgoing_tos tcp_outgoing_ds tcp_outgoing_dscp
int url_sz = strlen(url) + 32 + Config.appendDomainLen +
strlen(host);
http->uri = (char *)xcalloc(url_sz, 1);
- snprintf(http->uri, url_sz, "http://%s%s", /*conn->port->protocol,*/ host, url);
+ snprintf(http->uri, url_sz, "%s://%s%s", conn->port->protocol, host, url);
debugs(33, 5, "TRANSPARENT HOST REWRITE: '" << http->uri <<"'");
} else {
/* Put the local socket IP address as the hostname. */
int url_sz = strlen(url) + 32 + Config.appendDomainLen;
http->uri = (char *)xcalloc(url_sz, 1);
http->getConn()->clientConnection->local.ToHostname(ipbuf,MAX_IPSTRLEN),
- snprintf(http->uri, url_sz, "http://%s:%d%s",
- // http->getConn()->port->protocol,
+ snprintf(http->uri, url_sz, "%s://%s:%d%s",
+ http->getConn()->port->protocol,
ipbuf, http->getConn()->clientConnection->local.GetPort(), url);
debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'");
}
* from the port settings to the request.
*/
if (http->clientConnection != NULL) {
- request->flags.intercepted = (http->clientConnection->flags & COMM_INTERCEPTION);
- request->flags.spoof_client_ip = (http->clientConnection->flags & COMM_TRANSPARENT);
+ request->flags.intercepted = ((http->clientConnection->flags & COMM_INTERCEPTION) != 0);
+ request->flags.spoof_client_ip = ((http->clientConnection->flags & COMM_TRANSPARENT) != 0 ) ;
}
if (internalCheck(request->urlpath.termedBuf())) {
conn->readSomeData();
}
+/**
+ * Initializes an ssl connection to squid.
+ * In the case the SSL_CTX is not given it calls the ConnStateData::switchToHttps method
+ * to start procedure to generate a dynamic SSL_CTX
+ */
+static void
+httpsEstablish(ConnStateData *connState, SSL_CTX *sslContext)
+{
+ SSL *ssl = NULL;
+ assert(connState);
+ const Comm::ConnectionPointer &details = connState->clientConnection;
+
+ if (sslContext && !(ssl = httpsCreate(details, sslContext)))
+ return;
+
+ typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, connState, ConnStateData::requestTimeout);
+ commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
+
+ if (ssl)
+ Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
+ else {
+ char buf[MAX_IPSTRLEN];
+ debugs(33, 4, HERE << details << " try to generate a Dynamic SSL CTX");
+ connState->switchToHttps(details->local.NtoA(buf, sizeof(buf)));
+ }
+}
+
+/**
+ * A callback function to use with the ACLFilledChecklist callback.
+ * In the case of ACCES_ALLOWED answer initializes an ssl bumped connection,
+ * else revert the connection to tunnel mode.
+ */
+static void
+httpsSslBumpAccessCheckDone(allow_t answer, void *data)
+{
+ ConnStateData *connState = (ConnStateData *) data;
+
+ //if connection closed/closing just return.
+ if (!connState->isOpen())
+ return;
+
+ if (answer == ACCESS_ALLOWED) {
+ debugs(33, 2, HERE << " sslBump done data: " << connState->clientConnection);
+ httpsEstablish(connState, NULL);
+ } else {
+ // fake a CONNECT request to force connState to tunnel
+
+ debugs(33, 2, HERE << " normal SSL connection: " << connState->clientConnection << " revert to tunnel mode");
+ static char ip[MAX_IPSTRLEN];
+ static char reqStr[MAX_IPSTRLEN + 80];
+ connState->clientConnection->local.NtoA(ip, sizeof(ip));
+ snprintf(reqStr, sizeof(reqStr), "CONNECT %s:%d\r\n\r\n", ip, connState->clientConnection->local.GetPort());
+ bool ret = connState->handleReadData(reqStr, strlen(reqStr));
+ if (ret)
+ ret = connState->clientParseRequests();
+
+ if (!ret) {
+ debugs(33, 2, HERE << "Failed to start fake CONNECT request for ssl bumped connection: " << connState->clientConnection);
+ connState->clientConnection->close();
+ }
+ }
+}
+
/** handle a new HTTPS connection */
static void
httpsAccept(const CommAcceptCbParams ¶ms)
return;
}
- SSL_CTX *sslContext = s->staticSslContext.get();
- SSL *ssl = NULL;
- if (!(ssl = httpsCreate(params.conn, sslContext)))
- return;
-
debugs(33, 4, HERE << params.conn << " accepted, starting SSL negotiation.");
fd_note(params.conn->fd, "client https connect");
// Socket is ready, setup the connection manager to start using it
ConnStateData *connState = connStateCreate(params.conn, &s->http);
- typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
- TimeoutDialer, connState, ConnStateData::requestTimeout);
- commSetConnTimeout(params.conn, Config.Timeout.request, timeoutCall);
+ if (s->sslBump) {
+ assert(params.conn->flags & COMM_TRANSPARENT);
+
+ debugs(33, 5, "httpsAccept: accept transparent connection: " << params.conn);
- Comm::SetSelect(params.conn->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
+ if (!Config.accessList.ssl_bump) {
+ httpsSslBumpAccessCheckDone(ACCESS_DENIED, connState);
+ return;
+ }
+
+ // Create a fake HTTP request for ssl_bump ACL check,
+ // using tproxy-provided destination IP and port.
+ HttpRequest *request = new HttpRequest();
+ static char ip[MAX_IPSTRLEN];
+ request->SetHost(params.conn->local.NtoA(ip, sizeof(ip)));
+ request->port = params.conn->local.GetPort();
+ request->myportname = s->name;
+
+ ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, request, NULL);
+ acl_checklist->src_addr = params.conn->remote;
+ acl_checklist->my_addr = s->s;
+ acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, connState);
+ return;
+ } else {
+ SSL_CTX *sslContext = s->staticSslContext.get();
+ httpsEstablish(connState, sslContext);
+ }
}
void
comm_read(from.conn, from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), call);
}
+/**
+ * Set the HTTP status for this request and sets the read handlers for client
+ * and server side connections.
+ */
+static void
+tunnelStartShoveling(TunnelStateData *tunnelState)
+{
+ *tunnelState->status_ptr = HTTP_OK;
+ if (cbdataReferenceValid(tunnelState)) {
+ tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
+ tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
+ }
+}
+
/**
* All the pieces we need to write to client and/or server connection
* have been written.
- * - Set the HTTP status for this request.
- * - Start the blind pump.
+ * Call the tunnelStartShoveling to start the blind pump.
*/
static void
tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
return;
}
- *tunnelState->status_ptr = HTTP_OK;
- if (cbdataReferenceValid(tunnelState)) {
- tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
- tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
- }
+ tunnelStartShoveling(tunnelState);
}
/*
{
TunnelStateData *tunnelState = (TunnelStateData *)data;
debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
- AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
- CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
- Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
+
+ if (tunnelState->request && tunnelState->request->flags.spoof_client_ip)
+ tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
+ else {
+ AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
+ CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
+ Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
+ }
}
static void