From: Amos Jeffries Date: Fri, 26 Jul 2013 02:06:25 +0000 (-0600) Subject: Update the http(s)_port directives protocol= parameter X-Git-Tag: SQUID_3_5_0_1~684 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb6ac8089e8b4157aad32f3e4616569746ffe6f3;p=thirdparty%2Fsquid.git Update the http(s)_port directives protocol= parameter ... to use AnyP::ProtocolVersion for internal storage instead of opaque string text. This both limits the possible parameter values to one of HTTP, HTTP/1.1, HTTPS or HTTPS/1.1 and ensures that URLs generated from that protocol parameter value are http:// and https:// URL. Other values will cause Squid to abort. --- diff --git a/src/anyp/PortCfg.cc b/src/anyp/PortCfg.cc index 41a6b9ee1c..a63ca960cb 100644 --- a/src/anyp/PortCfg.cc +++ b/src/anyp/PortCfg.cc @@ -1,21 +1,24 @@ #include "squid.h" #include "anyp/PortCfg.h" #include "comm.h" -#if HAVE_LIMITS -#include -#endif +#include "fatal.h" #if USE_SSL #include "ssl/support.h" #endif +#include +#if HAVE_LIMITS +#include +#endif + CBDATA_NAMESPACED_CLASS_INIT(AnyP, PortCfg); int NHttpSockets = 0; int HttpSockets[MAXTCPLISTENPORTS]; -AnyP::PortCfg::PortCfg(const char *aProtocol) : +AnyP::PortCfg::PortCfg() : next(NULL), - protocol(xstrdup(aProtocol)), + transport(AnyP::PROTO_HTTP,1,1), // "Squid is an HTTP proxy", etc. name(NULL), defaultsite(NULL) #if USE_SSL @@ -32,7 +35,6 @@ AnyP::PortCfg::~PortCfg() safe_free(name); safe_free(defaultsite); - safe_free(protocol); #if USE_SSL safe_free(cert); @@ -50,14 +52,14 @@ AnyP::PortCfg::~PortCfg() AnyP::PortCfg * AnyP::PortCfg::clone() const { - AnyP::PortCfg *b = new AnyP::PortCfg(protocol); - + AnyP::PortCfg *b = new AnyP::PortCfg(); b->s = s; if (name) b->name = xstrdup(name); if (defaultsite) b->defaultsite = xstrdup(defaultsite); + b->transport = transport; b->flags = flags; b->allow_direct = allow_direct; b->vhost = vhost; @@ -99,18 +101,18 @@ AnyP::PortCfg::configureSslServerContext() if (!signingCert) { char buf[128]; - fatalf("No valid signing SSL certificate configured for %s_port %s", protocol, s.toUrl(buf, sizeof(buf))); + fatalf("No valid signing SSL certificate configured for %s_port %s", AnyP::ProtocolType_str[transport.protocol], s.toUrl(buf, sizeof(buf))); } if (!signPkey) - debugs(3, DBG_IMPORTANT, "No SSL private key configured for " << protocol << "_port " << s); + debugs(3, DBG_IMPORTANT, "No SSL private key configured for " << AnyP::ProtocolType_str[transport.protocol] << "_port " << s); Ssl::generateUntrustedCert(untrustedSigningCert, untrustedSignPkey, signingCert, signPkey); if (!untrustedSigningCert) { char buf[128]; - fatalf("Unable to generate signing SSL certificate for untrusted sites for %s_port %s", protocol, s.toUrl(buf, sizeof(buf))); + fatalf("Unable to generate signing SSL certificate for untrusted sites for %s_port %s", AnyP::ProtocolType_str[transport.protocol], s.toUrl(buf, sizeof(buf))); } if (crlfile) @@ -139,8 +141,23 @@ AnyP::PortCfg::configureSslServerContext() if (!staticSslContext) { char buf[128]; - fatalf("%s_port %s initialization error", protocol, s.toUrl(buf, sizeof(buf))); + fatalf("%s_port %s initialization error", AnyP::ProtocolType_str[transport.protocol], s.toUrl(buf, sizeof(buf))); } } #endif +void +AnyP::PortCfg::setTransport(const char *aProtocol) +{ + // HTTP/1.0 not supported because we are version 1.1 which contains a superset of 1.0 + // and RFC 2616 requires us to upgrade 1.0 to 1.1 + + if (strcasecmp("http", aProtocol) != 0 || strcmp("HTTP/1.1", aProtocol) != 0) + transport = AnyP::ProtocolVersion(AnyP::PROTO_HTTP, 1,1); + + else if (strcasecmp("https", aProtocol) != 0 || strcmp("HTTPS/1.1", aProtocol) != 0) + transport = AnyP::ProtocolVersion(AnyP::PROTO_HTTPS, 1,1); + + else + fatalf("http(s)_port protocol=%s is not supported\n", aProtocol); +} diff --git a/src/anyp/PortCfg.h b/src/anyp/PortCfg.h index 9553caeeb2..c47ba32d94 100644 --- a/src/anyp/PortCfg.h +++ b/src/anyp/PortCfg.h @@ -2,6 +2,7 @@ #define SQUID_ANYP_PORTCFG_H #include "anyp/forward.h" +#include "anyp/ProtocolVersion.h" #include "anyp/TrafficMode.h" #include "comm/Connection.h" @@ -15,7 +16,7 @@ namespace AnyP class PortCfg { public: - PortCfg(const char *aProtocol); + PortCfg(); ~PortCfg(); AnyP::PortCfg *clone() const; #if USE_SSL @@ -23,10 +24,17 @@ public: void configureSslServerContext(); #endif + /** + * Set this ports transport type from a string representation. + * Unknown transport type representations will halt Squid. + * Supports: HTTP, HTTP/1.1, HTTPS, HTTPS/1.1. + */ + void setTransport(const char *aProtocol); + PortCfg *next; Ip::Address s; - char *protocol; /* protocol name */ + AnyP::ProtocolVersion transport; ///< transport protocol and version received by this port char *name; /* visible name */ char *defaultsite; /* default web site */ diff --git a/src/anyp/ProtocolVersion.h b/src/anyp/ProtocolVersion.h index 3ba01cd147..9e246d4b56 100644 --- a/src/anyp/ProtocolVersion.h +++ b/src/anyp/ProtocolVersion.h @@ -87,7 +87,7 @@ public: inline std::ostream & operator << (std::ostream &os, const AnyP::ProtocolVersion &v) { - return (os << AnyP::ProtocolType_str[v.protocol] << v.major << '.' << v.minor); + return (os << AnyP::ProtocolType_str[v.protocol] << '/' << v.major << '.' << v.minor); } #endif /* SQUID_ANYP_PROTOCOLVERSION_H */ diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 447f851563..218620a362 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -79,6 +79,7 @@ #include "wordlist.h" #include "neighbors.h" #include "tools.h" +#include "URLScheme.h" /* wccp2 has its own conditional definitions */ #include "wccp2.h" #if USE_ADAPTATION @@ -3512,22 +3513,24 @@ parsePortSpecification(AnyP::PortCfg * s, char *token) s->name = xstrdup(token); s->connection_auth_disabled = false; + const char *portType = URLScheme(s->transport.protocol).const_str(); + if (*token == '[') { /* [ipv6]:port */ host = token + 1; t = strchr(host, ']'); if (!t) { - debugs(3, DBG_CRITICAL, s->protocol << "_port: missing ']' on IPv6 address: " << token); + debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing ']' on IPv6 address: " << token); self_destruct(); } *t = '\0'; ++t; if (*t != ':') { - debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port in: " << token); + debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port in: " << token); self_destruct(); } if (!Ip::EnableIpv6) { - debugs(3, DBG_CRITICAL, "FATAL: " << s->protocol << "_port: IPv6 is not available."); + debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: IPv6 is not available."); self_destruct(); } port = xatos(t + 1); @@ -3540,14 +3543,14 @@ parsePortSpecification(AnyP::PortCfg * s, char *token) } else if (strtol(token, &junk, 10) && !*junk) { port = xatos(token); - debugs(3, 3, s->protocol << "_port: found Listen on Port: " << port); + debugs(3, 3, portType << "_port: found Listen on Port: " << port); } else { - debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port: " << token); + debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port: " << token); self_destruct(); } if (port == 0 && host != NULL) { - debugs(3, DBG_CRITICAL, s->protocol << "_port: Port cannot be 0: " << token); + debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: Port cannot be 0: " << token); self_destruct(); } @@ -3556,21 +3559,21 @@ parsePortSpecification(AnyP::PortCfg * s, char *token) s->s.port(port); if (!Ip::EnableIpv6) s->s.setIPv4(); - debugs(3, 3, s->protocol << "_port: found Listen on wildcard address: *:" << s->s.port() ); + debugs(3, 3, portType << "_port: found Listen on wildcard address: *:" << s->s.port()); } else if ( (s->s = host) ) { /* check/parse numeric IPA */ s->s.port(port); if (!Ip::EnableIpv6) s->s.setIPv4(); - debugs(3, 3, s->protocol << "_port: Listen on Host/IP: " << host << " --> " << s->s); + debugs(3, 3, portType << "_port: Listen on Host/IP: " << host << " --> " << s->s); } else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */ /* dont use ipcache */ s->defaultsite = xstrdup(host); s->s.port(port); if (!Ip::EnableIpv6) s->s.setIPv4(); - debugs(3, 3, s->protocol << "_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s); + debugs(3, 3, portType << "_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s); } else { - debugs(3, DBG_CRITICAL, s->protocol << "_port: failed to resolve Host/IP: " << host); + debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: failed to resolve Host/IP: " << host); self_destruct(); } } @@ -3647,7 +3650,7 @@ parse_port_option(AnyP::PortCfg * s, char *token) debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: protocol option requires Acceleration mode flag."); self_destruct(); } - s->protocol = xstrdup(token + 9); + s->setTransport(token + 9); } else if (strcmp(token, "allow-direct") == 0) { if (!s->flags.accelSurrogate) { debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: allow-direct option requires Acceleration mode flag."); @@ -3770,7 +3773,8 @@ parse_port_option(AnyP::PortCfg * s, char *token) void add_http_port(char *portspec) { - AnyP::PortCfg *s = new AnyP::PortCfg("http_port"); + AnyP::PortCfg *s = new AnyP::PortCfg(); + s->setTransport("HTTP"); parsePortSpecification(s, portspec); // we may need to merge better if the above returns a list with clones assert(s->next == NULL); @@ -3800,7 +3804,8 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName) return; } - AnyP::PortCfg *s = new AnyP::PortCfg(protocol); + AnyP::PortCfg *s = new AnyP::PortCfg(); + s->setTransport(protocol); parsePortSpecification(s, token); /* parse options ... */ @@ -3809,7 +3814,7 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName) } #if USE_SSL - if (strcmp(protocol, "https") == 0) { + if (transport.protocol == AnyP::PROTO_HTTPS) { /* ssl-bump on https_port configuration requires either tproxy or intercept, and vice versa */ const bool hijacked = s->flags.isIntercepted(); if (s->flags.tunnelSslBumping && !hijacked) { @@ -3827,7 +3832,7 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName) // clone the port options from *s to *(s->next) s->next = cbdataReference(s->clone()); s->next->s.setIPv4(); - debugs(3, 3, protocol << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s); + debugs(3, 3, URLScheme(s->transport.protocol) << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s); } while (*head) @@ -3866,8 +3871,9 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfg * s) if (s->defaultsite) storeAppendPrintf(e, " defaultsite=%s", s->defaultsite); - if (s->protocol && strcmp(s->protocol,"http") != 0) - storeAppendPrintf(e, " protocol=%s", s->protocol); + // TODO: compare against prefix of 'n' instead of assuming http_port + if (s->transport.protocol != AnyP::PROTO_HTTP) + storeAppendPrintf(e, " protocol=%s", URLScheme(s->transport.protocol).const_str()); if (s->allow_direct) storeAppendPrintf(e, " allow-direct"); diff --git a/src/client_side.cc b/src/client_side.cc index a513e59488..39508e8ef6 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -2148,7 +2148,7 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, strlen(host); http->uri = (char *)xcalloc(url_sz, 1); const char *protocol = switchedToHttps ? - "https" : conn->port->protocol; + "https" : URLScheme(conn->port->transport.protocol).const_str(); snprintf(http->uri, url_sz, "%s://%s%s", protocol, host, url); debugs(33, 5, "ACCEL VHOST REWRITE: '" << http->uri << "'"); } else if (conn->port->defaultsite /* && !vhost */) { @@ -2162,7 +2162,7 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, snprintf(vportStr, sizeof(vportStr),":%d",vport); } snprintf(http->uri, url_sz, "%s://%s%s%s", - conn->port->protocol, conn->port->defaultsite, vportStr, url); + URLScheme(conn->port->transport.protocol).const_str(), conn->port->defaultsite, vportStr, url); debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: '" << http->uri <<"'"); } else if (vport > 0 /* && (!vhost || no Host:) */) { debugs(33, 5, "ACCEL VPORT REWRITE: http_port IP + vport=" << vport); @@ -2171,7 +2171,7 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, http->uri = (char *)xcalloc(url_sz, 1); http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN); snprintf(http->uri, url_sz, "%s://%s:%d%s", - http->getConn()->port->protocol, + URLScheme(conn->port->transport.protocol).const_str(), ipbuf, vport, url); debugs(33, 5, "ACCEL VPORT REWRITE: '" << http->uri << "'"); } @@ -2192,7 +2192,7 @@ prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "%s://%s%s", conn->port->protocol, host, url); + snprintf(http->uri, url_sz, "%s://%s%s", URLScheme(conn->port->transport.protocol).const_str(), host, url); debugs(33, 5, "TRANSPARENT HOST REWRITE: '" << http->uri <<"'"); } else { /* Put the local socket IP address as the hostname. */ @@ -2200,7 +2200,7 @@ prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, http->uri = (char *)xcalloc(url_sz, 1); http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN); snprintf(http->uri, url_sz, "%s://%s:%d%s", - http->getConn()->port->protocol, + URLScheme(http->getConn()->port->transport.protocol).const_str(), ipbuf, http->getConn()->clientConnection->local.port(), url); debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'"); } @@ -2294,7 +2294,7 @@ parseHttpRequest(ConnStateData *csd, HttpParser *hp, HttpRequestMethod * method_ /* deny CONNECT via accelerated ports */ if (*method_p == Http::METHOD_CONNECT && csd->port && csd->port->flags.accelSurrogate) { - debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->protocol << " Accelerator port " << csd->port->s.port() ); + debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->transport.protocol << " Accelerator port " << csd->port->s.port()); /* XXX need a way to say "this many character length string" */ debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->buf); hp->request_parse_status = Http::scMethodNotAllowed;