Bug 1463509 - SOCKS support for Alternative Services r=valentin draft
authorPatrick McManus <mcmanus@ducksong.com>
Tue, 22 May 2018 13:50:56 -0400
changeset 798873 462f9479531ca5293b11f14f100a20faa46fb84a
parent 798084 b75acf9652937ce79a9bf02de843c100db0e5ec7
push id110861
push userbmo:mcmanus@ducksong.com
push dateWed, 23 May 2018 16:15:48 +0000
reviewersvalentin
bugs1463509
milestone62.0a1
Bug 1463509 - SOCKS support for Alternative Services r=valentin MozReview-Commit-ID: 1oXnQuzOqsC
netwerk/base/nsSocketTransport2.cpp
netwerk/protocol/http/AlternateServices.cpp
netwerk/protocol/http/AlternateServices.h
netwerk/protocol/http/nsHttpChannel.cpp
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -1156,17 +1156,17 @@ nsSocketTransport::BuildSocket(PRFileDes
         // SocketProvider (e.g. PSM) the origin hostname but can still do DNS
         // on an explicit alternate service host name
         const char *host       = mOriginHost.get();
         int32_t     port       = (int32_t) mOriginPort;
         nsCOMPtr<nsIProxyInfo> proxyInfo = mProxyInfo;
         uint32_t    controlFlags = 0;
 
         uint32_t i;
-        for (i=0; i<mTypeCount; ++i) {
+        for (i = 0; i < mTypeCount; ++i) {
             nsCOMPtr<nsISocketProvider> provider;
 
             SOCKET_LOG(("  pushing io layer [%u:%s]\n", i, mTypes[i]));
 
             rv = spserv->GetSocketProvider(mTypes[i], getter_AddRefs(provider));
             if (NS_FAILED(rv))
                 break;
 
@@ -1185,32 +1185,49 @@ nsSocketTransport::BuildSocket(PRFileDes
             if (mConnectionFlags & nsISocketTransport::BE_CONSERVATIVE)
                 controlFlags |= nsISocketProvider::BE_CONSERVATIVE;
 
             nsCOMPtr<nsISupports> secinfo;
             if (i == 0) {
                 // if this is the first type, we'll want the
                 // service to allocate a new socket
 
+                // Most layers _ESPECIALLY_ PSM want the origin name here as they
+                // will use it for secure checks, etc.. and any connection management
+                // differences between the origin name and the routed name can be
+                // taken care of via DNS. However, SOCKS is a special case as there is
+                // no DNS. in the case of SOCKS and PSM the PSM is a separate layer
+                // and receives the origin name.
+                const char *socketProviderHost = host;
+                int32_t socketProviderPort = port;
+                if (mProxyTransparentResolvesHost &&
+                    (!strcmp(mTypes[0], "socks") || !strcmp(mTypes[0], "socks4"))) {
+                    SOCKET_LOG(("SOCKS %d Host/Route override: %s:%d -> %s:%d\n",
+                                mHttpsProxy,
+                                socketProviderHost, socketProviderPort,
+                                mHost.get(), mPort));
+                    socketProviderHost = mHost.get();
+                    socketProviderPort = mPort;
+                }
+
                 // when https proxying we want to just connect to the proxy as if
                 // it were the end host (i.e. expect the proxy's cert)
 
                 rv = provider->NewSocket(mNetAddr.raw.family,
-                                         mHttpsProxy ? mProxyHost.get() : host,
-                                         mHttpsProxy ? mProxyPort : port,
+                                         mHttpsProxy ? mProxyHost.get() : socketProviderHost,
+                                         mHttpsProxy ? mProxyPort : socketProviderPort,
                                          proxyInfo, mOriginAttributes,
                                          controlFlags, mTlsFlags, &fd,
                                          getter_AddRefs(secinfo));
 
                 if (NS_SUCCEEDED(rv) && !fd) {
                     NS_NOTREACHED("NewSocket succeeded but failed to create a PRFileDesc");
                     rv = NS_ERROR_UNEXPECTED;
                 }
-            }
-            else {
+            } else {
                 // the socket has already been allocated,
                 // so we just want the service to add itself
                 // to the stack (such as pushing an io layer)
                 rv = provider->AddToSocket(mNetAddr.raw.family,
                                            host, port, proxyInfo,
                                            mOriginAttributes, controlFlags, mTlsFlags, fd,
                                            getter_AddRefs(secinfo));
             }
@@ -1231,19 +1248,18 @@ nsSocketTransport::BuildSocket(PRFileDes
                     SOCKET_LOG(("  [secinfo=%p callbacks=%p]\n", mSecInfo.get(), mCallbacks.get()));
                 }
                 // don't call into PSM while holding mLock!!
                 nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(secinfo));
                 if (secCtrl)
                     secCtrl->SetNotificationCallbacks(callbacks);
                 // remember if socket type is SSL so we can ProxyStartSSL if need be.
                 usingSSL = isSSL;
-            }
-            else if ((strcmp(mTypes[i], "socks") == 0) ||
-                     (strcmp(mTypes[i], "socks4") == 0)) {
+            } else if ((strcmp(mTypes[i], "socks") == 0) ||
+                       (strcmp(mTypes[i], "socks4") == 0)) {
                 // since socks is transparent, any layers above
                 // it do not have to worry about proxy stuff
                 proxyInfo = nullptr;
                 proxyTransparent = true;
             }
         }
 
         if (NS_FAILED(rv)) {
--- a/netwerk/protocol/http/AlternateServices.cpp
+++ b/netwerk/protocol/http/AlternateServices.cpp
@@ -41,30 +41,36 @@ SchemeIsHTTPS(const nsACString &originSc
 
   if (!outIsHTTPS && !originScheme.EqualsLiteral("http")) {
       MOZ_ASSERT(false, "unexpected scheme");
       return NS_ERROR_UNEXPECTED;
   }
   return NS_OK;
 }
 
+bool
+AltSvcMapping::AcceptableProxy(nsProxyInfo *proxyInfo)
+{
+  return !proxyInfo || proxyInfo->IsDirect() || proxyInfo->IsSOCKS();
+}
+
 void
 AltSvcMapping::ProcessHeader(const nsCString &buf, const nsCString &originScheme,
                              const nsCString &originHost, int32_t originPort,
                              const nsACString &username, bool privateBrowsing,
                              nsIInterfaceRequestor *callbacks, nsProxyInfo *proxyInfo,
                              uint32_t caps, const OriginAttributes &originAttributes)
 {
   MOZ_ASSERT(NS_IsMainThread());
   LOG(("AltSvcMapping::ProcessHeader: %s\n", buf.get()));
   if (!callbacks) {
     return;
   }
 
-  if (proxyInfo && !proxyInfo->IsDirect()) {
+  if (!AcceptableProxy(proxyInfo)) {
     LOG(("AltSvcMapping::ProcessHeader ignoring due to proxy\n"));
     return;
   }
 
   bool isHTTPS;
   if (NS_FAILED(SchemeIsHTTPS(originScheme, isHTTPS))) {
     return;
   }
--- a/netwerk/protocol/http/AlternateServices.h
+++ b/netwerk/protocol/http/AlternateServices.h
@@ -61,16 +61,20 @@ public:
   AltSvcMapping(DataStorage *storage, int32_t storageEpoch, const nsCString &serialized);
 
   static void ProcessHeader(const nsCString &buf, const nsCString &originScheme,
                             const nsCString &originHost, int32_t originPort,
                             const nsACString &username, bool privateBrowsing,
                             nsIInterfaceRequestor *callbacks, nsProxyInfo *proxyInfo,
                             uint32_t caps, const OriginAttributes &originAttributes);
 
+  // AcceptableProxy() decides whether a particular proxy configuration (pi) is suitable
+  // for use with Alt-Svc. No proxy (including a null pi) is suitable.
+  static bool AcceptableProxy(nsProxyInfo *pi);
+
   const nsCString &AlternateHost() const { return mAlternateHost; }
   const nsCString &OriginHost() const { return mOriginHost; }
   uint32_t OriginPort() const { return mOriginPort; }
   const nsCString &HashKey() const { return mHashKey; }
   uint32_t AlternatePort() const { return mAlternatePort; }
   bool Validated() { return mValidated; }
   int32_t GetExpiresAt() { return mExpiresAt; }
   bool RouteEquals(AltSvcMapping *map);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6177,19 +6177,18 @@ nsHttpChannel::BeginConnect()
     SetDoNotTrack();
 
     OriginAttributes originAttributes;
     NS_GetOriginAttributes(this, originAttributes);
 
     RefPtr<AltSvcMapping> mapping;
     if (!mConnectionInfo && mAllowAltSvc && // per channel
         !(mLoadFlags & LOAD_FRESH_CONNECTION) &&
-        (scheme.EqualsLiteral("http") ||
-         scheme.EqualsLiteral("https")) &&
-        (!proxyInfo || proxyInfo->IsDirect()) &&
+        AltSvcMapping::AcceptableProxy(proxyInfo) &&
+        (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) &&
         (mapping = gHttpHandler->GetAltServiceMapping(scheme,
                                                       host, port,
                                                       mPrivateBrowsing,
                                                       originAttributes))) {
         LOG(("nsHttpChannel %p Alt Service Mapping Found %s://%s:%d [%s]\n",
              this, scheme.get(), mapping->AlternateHost().get(),
              mapping->AlternatePort(), mapping->HashKey().get()));