]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Update the http(s)_port directives protocol= parameter
authorAmos Jeffries <squid3@treenet.co.nz>
Fri, 26 Jul 2013 02:06:25 +0000 (20:06 -0600)
committerAmos Jeffries <squid3@treenet.co.nz>
Fri, 26 Jul 2013 02:06:25 +0000 (20:06 -0600)
... 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.

src/anyp/PortCfg.cc
src/anyp/PortCfg.h
src/anyp/ProtocolVersion.h
src/cache_cf.cc
src/client_side.cc

index 41a6b9ee1ce3ab9f7853402a8bcb8869f5c7dfef..a63ca960cb9e6af0c7fbc6176c25924d14a75056 100644 (file)
@@ -1,21 +1,24 @@
 #include "squid.h"
 #include "anyp/PortCfg.h"
 #include "comm.h"
-#if HAVE_LIMITS
-#include <limits>
-#endif
+#include "fatal.h"
 #if USE_SSL
 #include "ssl/support.h"
 #endif
 
+#include <cstring>
+#if HAVE_LIMITS
+#include <limits>
+#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);
+}
index 9553caeeb2ebb0b84a0d7908b8b877145d1cdf2e..c47ba32d942239f99f67a16d90c8fac689619006 100644 (file)
@@ -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 */
 
index 3ba01cd147538c20a97eb6453d0da56dd867672a..9e246d4b561164bb667d7eff35eef9f5e93f416a 100644 (file)
@@ -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 */
index 447f85156348b7f63bccb81f662af9f09ceb0ccb..218620a36282b65882bc1cc9ca6c97b0d636434b 100644 (file)
@@ -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");
index a513e594883192ccc3e7839b17690b4c4a42849d..39508e8ef63bd4f7bd39baa984b3d2590e4a2291 100644 (file)
@@ -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;