Bug 1211567 - Enable domain socket support for SOCKS; r=bagder
MozReview-Commit-ID: 9yMFckwPf6C
--- a/netwerk/base/nsProtocolProxyService.cpp
+++ b/netwerk/base/nsProtocolProxyService.cpp
@@ -389,16 +389,26 @@ proxy_GetBoolPref(nsIPrefBranch *aPrefBr
bool temp;
nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp);
if (NS_FAILED(rv))
aResult = false;
else
aResult = temp;
}
+static inline bool
+IsHostDomainSocket(const nsACString& aHost)
+{
+#ifdef XP_UNIX
+ return Substring(aHost, 0, 5) == "file:";
+#else
+ return false;
+#endif // XP_UNIX
+}
+
//----------------------------------------------------------------------------
static const int32_t PROXYCONFIG_DIRECT4X = 3;
static const int32_t PROXYCONFIG_COUNT = 6;
NS_IMPL_ADDREF(nsProtocolProxyService)
NS_IMPL_RELEASE(nsProtocolProxyService)
NS_IMPL_CLASSINFO(nsProtocolProxyService, nullptr, nsIClassInfo::SINGLETON,
@@ -614,17 +624,17 @@ nsProtocolProxyService::PrefsChanged(nsI
if (!pref || !strcmp(pref, PROXY_PREF("ftp")))
proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost);
if (!pref || !strcmp(pref, PROXY_PREF("ftp_port")))
proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort);
if (!pref || !strcmp(pref, PROXY_PREF("socks")))
- proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyHost);
+ proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyTarget);
if (!pref || !strcmp(pref, PROXY_PREF("socks_port")))
proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort);
if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) {
int32_t version;
proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version);
// make sure this preference value remains sane
@@ -1862,18 +1872,19 @@ nsProtocolProxyService::Resolve_Internal
// proxy info values for manual configuration mode
const char *type = nullptr;
const nsACString *host = nullptr;
int32_t port = -1;
uint32_t proxyFlags = 0;
if ((flags & RESOLVE_PREFER_SOCKS_PROXY) &&
- !mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) {
- host = &mSOCKSProxyHost;
+ !mSOCKSProxyTarget.IsEmpty() &&
+ (IsHostDomainSocket(mSOCKSProxyTarget) || mSOCKSProxyPort > 0)) {
+ host = &mSOCKSProxyTarget;
if (mSOCKSProxyVersion == 4)
type = kProxyType_SOCKS4;
else
type = kProxyType_SOCKS;
port = mSOCKSProxyPort;
if (mSOCKSProxyRemoteDNS)
proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
}
@@ -1899,18 +1910,19 @@ nsProtocolProxyService::Resolve_Internal
}
else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 &&
!(flags & RESOLVE_IGNORE_URI_SCHEME) &&
info.scheme.EqualsLiteral("ftp")) {
host = &mFTPProxyHost;
type = kProxyType_HTTP;
port = mFTPProxyPort;
}
- else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) {
- host = &mSOCKSProxyHost;
+ else if (!mSOCKSProxyTarget.IsEmpty() &&
+ (IsHostDomainSocket(mSOCKSProxyTarget) || mSOCKSProxyPort > 0)) {
+ host = &mSOCKSProxyTarget;
if (mSOCKSProxyVersion == 4)
type = kProxyType_SOCKS4;
else
type = kProxyType_SOCKS;
port = mSOCKSProxyPort;
if (mSOCKSProxyRemoteDNS)
proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
}
--- a/netwerk/base/nsProtocolProxyService.h
+++ b/netwerk/base/nsProtocolProxyService.h
@@ -382,18 +382,19 @@ protected:
nsCString mHTTPProxyHost;
int32_t mHTTPProxyPort;
nsCString mFTPProxyHost;
int32_t mFTPProxyPort;
nsCString mHTTPSProxyHost;
int32_t mHTTPSProxyPort;
-
- nsCString mSOCKSProxyHost;
+
+ // mSOCKSProxyTarget could be a host or a domain socket path.
+ nsCString mSOCKSProxyTarget;
int32_t mSOCKSProxyPort;
int32_t mSOCKSProxyVersion;
bool mSOCKSProxyRemoteDNS;
bool mProxyOverTLS;
RefPtr<nsPACMan> mPACMan; // non-null if we are using PAC
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
--- a/netwerk/socket/nsSOCKSIOLayer.cpp
+++ b/netwerk/socket/nsSOCKSIOLayer.cpp
@@ -14,18 +14,20 @@
#include "nsIDNSRecord.h"
#include "nsISOCKSSocketInfo.h"
#include "nsISocketProvider.h"
#include "nsSOCKSIOLayer.h"
#include "nsNetCID.h"
#include "nsIDNSListener.h"
#include "nsICancelable.h"
#include "nsThreadUtils.h"
+#include "nsIURL.h"
#include "mozilla/Logging.h"
#include "mozilla/net/DNS.h"
+#include "mozilla/unused.h"
using mozilla::LogLevel;
using namespace mozilla::net;
static PRDescIdentity nsSOCKSIOLayerIdentity;
static PRIOMethods nsSOCKSIOLayerMethods;
static bool firstTime = true;
static bool ipv6Supported = true;
@@ -106,16 +108,64 @@ private:
uint32_t ReadUint32();
void ReadNetAddr(NetAddr *addr, uint16_t fam);
void ReadNetPort(NetAddr *addr);
void WantRead(uint32_t sz);
PRStatus ReadFromSocket(PRFileDesc *fd);
PRStatus WriteToSocket(PRFileDesc *fd);
+ bool IsHostDomainSocket()
+ {
+#ifdef XP_UNIX
+ nsAutoCString proxyHost;
+ mProxy->GetHost(proxyHost);
+ return Substring(proxyHost, 0, 5) == "file:";
+#else
+ return false;
+#endif // XP_UNIX
+ }
+
+ nsresult SetDomainSocketPath(const nsACString& aDomainSocketPath,
+ NetAddr* aProxyAddr)
+ {
+#ifdef XP_UNIX
+ nsresult rv;
+ MOZ_ASSERT(aProxyAddr);
+
+ nsCOMPtr<nsIURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(rv = url->SetSpec(aDomainSocketPath)))) {
+ return rv;
+ }
+
+ nsAutoCString path;
+ if (NS_WARN_IF(NS_FAILED(rv = url->GetPath(path)))) {
+ return rv;
+ }
+
+ if (sizeof(aProxyAddr->local.path) <= path.Length()) {
+ NS_WARNING("domain socket path too long.");
+ return NS_ERROR_FAILURE;
+ }
+
+ aProxyAddr->raw.family = AF_UNIX;
+ strcpy(aProxyAddr->local.path, path.get());
+
+ return NS_OK;
+#else
+ mozilla::Unused << aProxyAddr;
+ mozilla::Unused << aDomainSocketPath;
+ return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
private:
State mState;
uint8_t * mData;
uint8_t * mDataIoPtr;
uint32_t mDataLength;
uint32_t mReadOffset;
uint32_t mAmountToRead;
nsCOMPtr<nsIDNSRecord> mDnsRec;
@@ -415,39 +465,50 @@ nsSOCKSSocketInfo::ConnectToProxy(PRFile
}
// Try socks5 if the destination addrress is IPv6
if (mVersion == 4 &&
mDestinationAddr.raw.family == AF_INET6) {
mVersion = 5;
}
+ nsAutoCString proxyHost;
+ mProxy->GetHost(proxyHost);
+
int32_t proxyPort;
mProxy->GetPort(&proxyPort);
int32_t addresses = 0;
do {
- if (addresses++)
- mDnsRec->ReportUnusable(proxyPort);
-
- rv = mDnsRec->GetNextAddr(proxyPort, &mInternalProxyAddr);
- // No more addresses to try? If so, we'll need to bail
- if (NS_FAILED(rv)) {
- nsCString proxyHost;
- mProxy->GetHost(proxyHost);
- LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
- proxyHost.get()));
- return PR_FAILURE;
- }
+ if (IsHostDomainSocket()) {
+ rv = SetDomainSocketPath(proxyHost, &mInternalProxyAddr);
+ if (NS_FAILED(rv)) {
+ LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
+ proxyHost.get()));
+ return PR_FAILURE;
+ }
+ } else {
+ if (addresses++) {
+ mDnsRec->ReportUnusable(proxyPort);
+ }
- if (MOZ_LOG_TEST(gSOCKSLog, LogLevel::Debug)) {
- char buf[kIPv6CStrBufSize];
- NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
- LOGDEBUG(("socks: trying proxy server, %s:%hu",
- buf, ntohs(mInternalProxyAddr.inet.port)));
+ rv = mDnsRec->GetNextAddr(proxyPort, &mInternalProxyAddr);
+ // No more addresses to try? If so, we'll need to bail
+ if (NS_FAILED(rv)) {
+ LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
+ proxyHost.get()));
+ return PR_FAILURE;
+ }
+
+ if (MOZ_LOG_TEST(gSOCKSLog, LogLevel::Debug)) {
+ char buf[kIPv6CStrBufSize];
+ NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
+ LOGDEBUG(("socks: trying proxy server, %s:%hu",
+ buf, ntohs(mInternalProxyAddr.inet.port)));
+ }
}
NetAddr proxy = mInternalProxyAddr;
FixupAddressFamily(fd, &proxy);
PRNetAddr prProxy;
NetAddrToPRNetAddr(&proxy, &prProxy);
status = fd->lower->methods->connect(fd->lower, &prProxy, mTimeout);
if (status != PR_SUCCESS) {
@@ -966,16 +1027,22 @@ nsSOCKSSocketInfo::SetConnectTimeout(PRI
PRStatus
nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, int16_t oflags)
{
LOGDEBUG(("socks: DoHandshake(), state = %d", mState));
switch (mState) {
case SOCKS_INITIAL:
+ if (IsHostDomainSocket()) {
+ mState = SOCKS_DNS_COMPLETE;
+ mLookupStatus = NS_OK;
+ return ConnectToProxy(fd);
+ }
+
return StartDNS(fd);
case SOCKS_DNS_IN_PROGRESS:
PR_SetError(PR_IN_PROGRESS_ERROR, 0);
return PR_FAILURE;
case SOCKS_DNS_COMPLETE:
return ConnectToProxy(fd);
case SOCKS_CONNECTING_TO_PROXY:
return ContinueConnectingToProxy(fd, oflags);