mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
landing backend changes for bug 134105 "SOCKS5: DNS lookups should occur on proxy, not client side." (remote dns pref disabled by default) patch by malsmith@cs.rmit.edu.au, r=biesi, sr=darin
This commit is contained in:
parent
0bb526779c
commit
d19eff04b7
@ -210,8 +210,8 @@ nsLDAPSSLConnect(const char *hostlist, int defport, int timeout,
|
||||
// the certificate. Need to investigate.
|
||||
//
|
||||
rv = tlsSocketProvider->AddToSocket(PR_AF_INET,
|
||||
sessionClosure->hostname, defport,
|
||||
nsnull, 0, socketInfo.soinfo_prfd,
|
||||
sessionClosure->hostname, defport,
|
||||
nsnull, 0, 0, socketInfo.soinfo_prfd,
|
||||
getter_AddRefs(securityInfo));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("nsLDAPSSLConnect(): unable to add SSL layer to socket");
|
||||
|
@ -622,6 +622,7 @@ pref("network.proxy.ssl_port", 0);
|
||||
pref("network.proxy.socks", "");
|
||||
pref("network.proxy.socks_port", 0);
|
||||
pref("network.proxy.socks_version", 5);
|
||||
pref("network.proxy.socks_remote_dns", false);
|
||||
pref("network.proxy.no_proxies_on", "localhost, 127.0.0.1");
|
||||
pref("network.proxy.failover_timeout", 1800); // 30 minutes
|
||||
pref("network.online", true); //online/offline
|
||||
|
@ -47,7 +47,7 @@ interface nsIURI;
|
||||
* nsIProtocolProxyService provides methods to access information about
|
||||
* various network proxies.
|
||||
*/
|
||||
[scriptable, uuid(6b40d918-c01a-42a2-ab4d-4ea0b707f91f)]
|
||||
[scriptable, uuid(ec2da5ae-eb2e-11d8-9782-0004e22243f8)]
|
||||
interface nsIProtocolProxyService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -97,8 +97,12 @@ interface nsIProtocolProxyService : nsISupports
|
||||
* The proxy hostname or IP address.
|
||||
* @param aPort
|
||||
* The proxy port.
|
||||
* @param aFlags
|
||||
* Flags associated with this connection. See nsIProxyInfo.idl
|
||||
* for currently defined flags.
|
||||
*/
|
||||
nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost, in long aPort);
|
||||
nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost,
|
||||
in long aPort, in unsigned long aFlags);
|
||||
|
||||
/**
|
||||
* This method may be called to re-configure proxy settings given a URI
|
||||
|
@ -21,6 +21,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bradley Baetz <bbaetz@netscape.com> (Original Developer)
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -52,10 +53,17 @@
|
||||
*/
|
||||
native constCharPtr(const char*);
|
||||
|
||||
[scriptable, uuid(d49f429c-7c8e-4f7a-90a3-ea6122bd3887)]
|
||||
[scriptable, uuid(cefb3b30-e82f-11d8-329c-0004e22243f8)]
|
||||
interface nsIProxyInfo : nsISupports
|
||||
{
|
||||
[noscript, notxpcom] constCharPtr Host();
|
||||
[noscript, notxpcom] PRInt32 Port();
|
||||
[noscript, notxpcom] constCharPtr Type();
|
||||
[noscript, notxpcom] PRUint32 Flags();
|
||||
|
||||
/* This flag is set if the proxy is to perform name resolution
|
||||
* itself. If this is the case, the hostname is used in some
|
||||
* fashion, and we shouldn't do any form of DNS lookup ourselves.
|
||||
*/
|
||||
const unsigned short TRANSPARENT_PROXY_RESOLVES_HOST = 1 << 0;
|
||||
};
|
||||
|
@ -22,6 +22,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bradley Baetz <bbaetz@student.usyd.edu.au>
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -588,13 +589,14 @@ inline nsresult
|
||||
NS_NewProxyInfo(const nsACString &type,
|
||||
const nsACString &host,
|
||||
PRInt32 port,
|
||||
PRUint32 flags,
|
||||
nsIProxyInfo **result)
|
||||
{
|
||||
nsresult rv;
|
||||
static NS_DEFINE_CID(kPPSServiceCID, NS_PROTOCOLPROXYSERVICE_CID);
|
||||
nsCOMPtr<nsIProtocolProxyService> pps = do_GetService(kPPSServiceCID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = pps->NewProxyInfo(type, host, port, result);
|
||||
rv = pps->NewProxyInfo(type, host, port, flags, result);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -131,6 +132,19 @@ proxy_GetIntPref(nsIPrefBranch *aPrefBranch,
|
||||
aResult = temp;
|
||||
}
|
||||
|
||||
static void
|
||||
proxy_GetBoolPref(nsIPrefBranch *aPrefBranch,
|
||||
const char *aPref,
|
||||
PRBool &aResult)
|
||||
{
|
||||
PRBool temp;
|
||||
nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp);
|
||||
if (NS_FAILED(rv))
|
||||
aResult = PR_FALSE;
|
||||
else
|
||||
aResult = temp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class nsProxyInfo : public nsIProxyInfo
|
||||
@ -153,6 +167,10 @@ public:
|
||||
return mType;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(PRUint32) Flags() {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
~nsProxyInfo()
|
||||
{
|
||||
NS_IF_RELEASE(mNext);
|
||||
@ -161,12 +179,14 @@ public:
|
||||
nsProxyInfo(const char *type = nsnull)
|
||||
: mType(type)
|
||||
, mPort(-1)
|
||||
, mFlags(0)
|
||||
, mNext(nsnull)
|
||||
{}
|
||||
|
||||
const char *mType; // pointer to static kProxyType_XYZ value
|
||||
nsCString mHost;
|
||||
PRInt32 mPort;
|
||||
PRUint32 mFlags;
|
||||
nsProxyInfo *mNext;
|
||||
};
|
||||
|
||||
@ -207,6 +227,7 @@ nsProtocolProxyService::nsProtocolProxyService()
|
||||
, mHTTPSProxyPort(-1)
|
||||
, mSOCKSProxyPort(-1)
|
||||
, mSOCKSProxyVersion(4)
|
||||
, mSOCKSProxyRemoteDNS(PR_FALSE)
|
||||
, mSessionStart(PR_Now())
|
||||
, mFailedProxyTimeout(30 * 60) // 30 minute default
|
||||
{
|
||||
@ -320,6 +341,9 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
||||
mSOCKSProxyVersion = 4;
|
||||
}
|
||||
|
||||
if (!pref || !strcmp(pref, "network.proxy.socks_remote_dns"))
|
||||
proxy_GetBoolPref(prefBranch, "network.proxy.socks_remote_dns", mSOCKSProxyRemoteDNS);
|
||||
|
||||
if (!pref || !strcmp(pref, "network.proxy.failover_timeout"))
|
||||
proxy_GetIntPref(prefBranch, "network.proxy.failover_timeout", mFailedProxyTimeout);
|
||||
|
||||
@ -484,6 +508,7 @@ const char *
|
||||
nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, nsProxyInfo **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
PRUint32 flags = 0;
|
||||
|
||||
// see BNF in nsIProxyAutoConfig.idl
|
||||
|
||||
@ -518,6 +543,13 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n
|
||||
if (type) {
|
||||
const char *host = nsnull, *hostEnd = nsnull;
|
||||
PRInt32 port = -1;
|
||||
|
||||
// If it's a SOCKS5 proxy, do name resolution on the server side.
|
||||
// We could use this with SOCKS4a servers too, but they might not
|
||||
// support it.
|
||||
if (type == kProxyType_SOCKS)
|
||||
flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
|
||||
|
||||
// extract host:port
|
||||
start = sp;
|
||||
while ((*start == ' ' || *start == '\t') && start < end)
|
||||
@ -539,6 +571,7 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n
|
||||
nsProxyInfo *pi = new nsProxyInfo;
|
||||
if (pi) {
|
||||
pi->mType = type;
|
||||
pi->mFlags = flags;
|
||||
// YES, it is ok to specify a null proxy host.
|
||||
if (host) {
|
||||
pi->mHost.Assign(host, hostEnd - host);
|
||||
@ -762,6 +795,8 @@ nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult)
|
||||
const nsACString *host = nsnull;
|
||||
PRInt32 port = -1;
|
||||
|
||||
PRUint32 proxyFlags = 0;
|
||||
|
||||
if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 &&
|
||||
scheme.EqualsLiteral("http")) {
|
||||
host = &mHTTPProxyHost;
|
||||
@ -793,10 +828,12 @@ nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult)
|
||||
else
|
||||
type = kProxyType_SOCKS;
|
||||
port = mSOCKSProxyPort;
|
||||
if (mSOCKSProxyRemoteDNS)
|
||||
proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
|
||||
}
|
||||
|
||||
if (type)
|
||||
return NewProxyInfo_Internal(type, *host, port, aResult);
|
||||
return NewProxyInfo_Internal(type, *host, port, proxyFlags, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -805,6 +842,7 @@ NS_IMETHODIMP
|
||||
nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
|
||||
const nsACString &aHost,
|
||||
PRInt32 aPort,
|
||||
PRUint32 aFlags,
|
||||
nsIProxyInfo **aResult)
|
||||
{
|
||||
static const char *types[] = {
|
||||
@ -827,7 +865,7 @@ nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
|
||||
if (aPort <= 0)
|
||||
aPort = -1;
|
||||
|
||||
return NewProxyInfo_Internal(type, aHost, aPort, aResult);
|
||||
return NewProxyInfo_Internal(type, aHost, aPort, aFlags, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1075,6 +1113,7 @@ nsresult
|
||||
nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
|
||||
const nsACString &aHost,
|
||||
PRInt32 aPort,
|
||||
PRUint32 aFlags,
|
||||
nsIProxyInfo **aResult)
|
||||
{
|
||||
nsProxyInfo *proxyInfo = new nsProxyInfo();
|
||||
@ -1084,6 +1123,7 @@ nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
|
||||
proxyInfo->mType = aType;
|
||||
proxyInfo->mHost = aHost;
|
||||
proxyInfo->mPort = aPort;
|
||||
proxyInfo->mFlags = aFlags;
|
||||
|
||||
NS_ADDREF(*aResult = proxyInfo);
|
||||
return NS_OK;
|
||||
|
@ -20,6 +20,7 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -87,7 +88,7 @@ protected:
|
||||
NS_HIDDEN_(PRBool) IsProxyDisabled(nsProxyInfo *);
|
||||
NS_HIDDEN_(nsresult) ExaminePACForProxy(nsIURI *aURI, PRUint32 protoFlags, nsIProxyInfo **aResult);
|
||||
NS_HIDDEN_(nsresult) GetProtocolInfo(const char *scheme, PRUint32 &flags, PRInt32 &defaultPort);
|
||||
NS_HIDDEN_(nsresult) NewProxyInfo_Internal(const char *type, const nsACString &host, PRInt32 port, nsIProxyInfo **);
|
||||
NS_HIDDEN_(nsresult) NewProxyInfo_Internal(const char *type, const nsACString &host, PRInt32 port, PRUint32 flags, nsIProxyInfo **);
|
||||
NS_HIDDEN_(void) LoadFilters(const char *filters);
|
||||
NS_HIDDEN_(PRBool) CanUseProxy(nsIURI *aURI, PRInt32 defaultPort);
|
||||
NS_HIDDEN_(void) ConfigureFromWPAD();
|
||||
@ -150,6 +151,7 @@ protected:
|
||||
nsCString mSOCKSProxyHost;
|
||||
PRInt32 mSOCKSProxyPort;
|
||||
PRInt32 mSOCKSProxyVersion;
|
||||
PRBool mSOCKSProxyRemoteDNS;
|
||||
|
||||
nsCOMPtr<nsIProxyAutoConfig> mPAC;
|
||||
nsCString mPACURI;
|
||||
|
@ -21,6 +21,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com>
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -677,6 +678,7 @@ nsSocketTransport::nsSocketTransport()
|
||||
, mPort(0)
|
||||
, mProxyPort(0)
|
||||
, mProxyTransparent(PR_FALSE)
|
||||
, mProxyTransparentResolvesHost(PR_FALSE)
|
||||
, mState(STATE_CLOSED)
|
||||
, mAttached(PR_FALSE)
|
||||
, mInputClosed(PR_TRUE)
|
||||
@ -769,8 +771,15 @@ nsSocketTransport::Init(const char **types, PRUint32 typeCount,
|
||||
|
||||
// note if socket type corresponds to a transparent proxy
|
||||
if ((strcmp(mTypes[i], "socks") == 0) ||
|
||||
(strcmp(mTypes[i], "socks4") == 0))
|
||||
(strcmp(mTypes[i], "socks4") == 0)) {
|
||||
mProxyTransparent = PR_TRUE;
|
||||
|
||||
if (proxyInfo->Flags() & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST) {
|
||||
// we want the SOCKS layer to send the hostname
|
||||
// and port to the proxy and let it do the DNS.
|
||||
mProxyTransparentResolvesHost = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -865,6 +874,20 @@ nsSocketTransport::ResolveHost()
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (!mProxyHost.IsEmpty() && mProxyTransparentResolvesHost) {
|
||||
// Name resolution is done on the server side. Just pretend
|
||||
// client resolution is complete, this will get picked up later.
|
||||
// since we don't need to do DNS now, we bypass the resolving
|
||||
// step by initializing mNetAddr to an empty address, but we
|
||||
// must keep the port. The SOCKS IO layer will use the hostname
|
||||
// we send it when it's created, rather than the empty address
|
||||
// we send with the connect call.
|
||||
mState = STATE_RESOLVING;
|
||||
PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, SocketPort(), &mNetAddr);
|
||||
return PostEvent(MSG_DNS_LOOKUP_COMPLETE, NS_OK, nsnull);
|
||||
}
|
||||
|
||||
|
||||
nsCOMPtr<nsIDNSService> dns = do_GetService(kDNSServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
@ -903,10 +926,11 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, PRBool &proxyTransparent, PRBool
|
||||
do_GetService(kSocketProviderServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
const char *host = mHost.get();
|
||||
PRInt32 port = (PRInt32) mPort;
|
||||
const char *proxyHost = mProxyHost.IsEmpty() ? nsnull : mProxyHost.get();
|
||||
PRInt32 proxyPort = (PRInt32) mProxyPort;
|
||||
const char *host = mHost.get();
|
||||
PRInt32 port = (PRInt32) mPort;
|
||||
const char *proxyHost = mProxyHost.IsEmpty() ? nsnull : mProxyHost.get();
|
||||
PRInt32 proxyPort = (PRInt32) mProxyPort;
|
||||
PRUint32 proxyFlags = 0;
|
||||
|
||||
PRUint32 i;
|
||||
for (i=0; i<mTypeCount; ++i) {
|
||||
@ -918,13 +942,17 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, PRBool &proxyTransparent, PRBool
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
if (mProxyTransparentResolvesHost)
|
||||
proxyFlags |= nsISocketProvider::PROXY_RESOLVES_HOST;
|
||||
|
||||
nsCOMPtr<nsISupports> secinfo;
|
||||
if (i == 0) {
|
||||
// if this is the first type, we'll want the
|
||||
// service to allocate a new socket
|
||||
rv = provider->NewSocket(mNetAddr.raw.family,
|
||||
host, port, proxyHost, proxyPort,
|
||||
&fd, getter_AddRefs(secinfo));
|
||||
proxyFlags, &fd,
|
||||
getter_AddRefs(secinfo));
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !fd) {
|
||||
NS_NOTREACHED("NewSocket succeeded but failed to create a PRFileDesc");
|
||||
@ -937,8 +965,10 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, PRBool &proxyTransparent, PRBool
|
||||
// to the stack (such as pushing an io layer)
|
||||
rv = provider->AddToSocket(mNetAddr.raw.family,
|
||||
host, port, proxyHost, proxyPort,
|
||||
fd, getter_AddRefs(secinfo));
|
||||
proxyFlags, fd,
|
||||
getter_AddRefs(secinfo));
|
||||
}
|
||||
proxyFlags = 0;
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
|
@ -187,13 +187,14 @@ private:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// socket type info:
|
||||
char **mTypes;
|
||||
PRUint32 mTypeCount;
|
||||
nsCString mHost;
|
||||
nsCString mProxyHost;
|
||||
PRUint16 mPort;
|
||||
PRUint16 mProxyPort;
|
||||
PRBool mProxyTransparent;
|
||||
char **mTypes;
|
||||
PRUint32 mTypeCount;
|
||||
nsCString mHost;
|
||||
nsCString mProxyHost;
|
||||
PRUint16 mPort;
|
||||
PRUint16 mProxyPort;
|
||||
PRPackedBool mProxyTransparent;
|
||||
PRPackedBool mProxyTransparentResolvesHost;
|
||||
|
||||
PRUint16 SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
|
||||
const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
|
||||
|
@ -20,6 +20,7 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -42,7 +43,7 @@
|
||||
/**
|
||||
* nsISocketProvider
|
||||
*/
|
||||
[noscript, uuid(4c29772e-cf73-414a-98d9-661761a4511a)]
|
||||
[noscript, uuid(00b3df92-e830-11d8-d48e-0004e22243f8)]
|
||||
interface nsISocketProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -58,6 +59,8 @@ interface nsISocketProvider : nsISupports
|
||||
* If non-null, the proxy hostname for this connection.
|
||||
* @param aProxyPort
|
||||
* The proxy port for this connection.
|
||||
* @param aFlags
|
||||
* Control flags that govern this connection (see below.)
|
||||
* @param aFileDesc
|
||||
* The resulting PRFileDesc.
|
||||
* @param aSecurityInfo
|
||||
@ -69,25 +72,38 @@ interface nsISocketProvider : nsISupports
|
||||
in long aPort,
|
||||
in string aProxyHost,
|
||||
in long aProxyPort,
|
||||
in unsigned long aFlags,
|
||||
out nsFileDescStar aFileDesc,
|
||||
out nsISupports aSecurityInfo);
|
||||
|
||||
/**
|
||||
* addToSocket
|
||||
*
|
||||
* This function is called to allow the socket provider to layer a PRFileDesc
|
||||
* on top of another PRFileDesc. For example, SSL via a SOCKS proxy.
|
||||
* This function is called to allow the socket provider to layer a
|
||||
* PRFileDesc on top of another PRFileDesc. For example, SSL via a SOCKS
|
||||
* proxy.
|
||||
*
|
||||
* Parameters are the same as newSocket with the exception of aFileDesc, which
|
||||
* is an in-param instead.
|
||||
* Parameters are the same as newSocket with the exception of aFileDesc,
|
||||
* which is an in-param instead.
|
||||
*/
|
||||
void addToSocket(in long aFamily,
|
||||
in string aHost,
|
||||
in long aPort,
|
||||
in string aProxyHost,
|
||||
in long aProxyPort,
|
||||
in unsigned long aFlags,
|
||||
in nsFileDescStar aFileDesc,
|
||||
out nsISupports aSecurityInfo);
|
||||
|
||||
/**
|
||||
* PROXY_RESOLVES_HOST
|
||||
*
|
||||
* This flag is set if the proxy is to perform hostname resolution instead
|
||||
* of the client. When set, the hostname parameter passed when in this
|
||||
* interface will be used instead of the address structure passed for a
|
||||
* later connect et al. request.
|
||||
*/
|
||||
const long PROXY_RESOLVES_HOST = 1 << 0;
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -24,6 +24,7 @@
|
||||
* Justin Bradford <jab@atdot.org>
|
||||
* Bradley Baetz <bbaetz@acm.org>
|
||||
* Darin Fisher <darin@meer.net>
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -46,6 +47,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsISOCKSSocketInfo.h"
|
||||
#include "nsISocketProvider.h"
|
||||
#include "nsSOCKSIOLayer.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
@ -72,16 +74,24 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISOCKSSOCKETINFO
|
||||
|
||||
void Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort);
|
||||
void Init(PRInt32 version,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
const char *destinationHost,
|
||||
PRUint32 flags);
|
||||
|
||||
const nsCString &ProxyHost() { return mProxyHost; }
|
||||
PRInt32 ProxyPort() { return mProxyPort; }
|
||||
PRInt32 Version() { return mVersion; }
|
||||
const nsCString &DestinationHost() { return mDestinationHost; }
|
||||
const nsCString &ProxyHost() { return mProxyHost; }
|
||||
PRInt32 ProxyPort() { return mProxyPort; }
|
||||
PRInt32 Version() { return mVersion; }
|
||||
PRUint32 Flags() { return mFlags; }
|
||||
|
||||
private:
|
||||
nsCString mDestinationHost;
|
||||
nsCString mProxyHost;
|
||||
PRInt32 mProxyPort;
|
||||
PRInt32 mProxyPort;
|
||||
PRInt32 mVersion; // SOCKS version 4 or 5
|
||||
PRUint32 mFlags;
|
||||
PRNetAddr mInternalProxyAddr;
|
||||
PRNetAddr mExternalProxyAddr;
|
||||
PRNetAddr mDestinationAddr;
|
||||
@ -90,6 +100,7 @@ private:
|
||||
nsSOCKSSocketInfo::nsSOCKSSocketInfo()
|
||||
: mProxyPort(-1)
|
||||
, mVersion(-1)
|
||||
, mFlags(0)
|
||||
{
|
||||
PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr);
|
||||
PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr);
|
||||
@ -97,11 +108,13 @@ nsSOCKSSocketInfo::nsSOCKSSocketInfo()
|
||||
}
|
||||
|
||||
void
|
||||
nsSOCKSSocketInfo::Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort)
|
||||
nsSOCKSSocketInfo::Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort, const char *host, PRUint32 flags)
|
||||
{
|
||||
mVersion = version;
|
||||
mProxyHost = proxyHost;
|
||||
mProxyPort = proxyPort;
|
||||
mVersion = version;
|
||||
mProxyHost = proxyHost;
|
||||
mProxyPort = proxyPort;
|
||||
mDestinationHost = host;
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsSOCKSSocketInfo, nsISOCKSSocketInfo)
|
||||
@ -226,16 +239,69 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
|
||||
// we are now authenticated, so lets tell
|
||||
// the server where to connect to
|
||||
|
||||
request_len = 6;
|
||||
request_len = 0;
|
||||
|
||||
request[0] = 0x05; // SOCKS version 5
|
||||
request[1] = 0x01; // CONNECT command
|
||||
request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)
|
||||
|
||||
if (PR_NetAddrFamily(addr) == PR_AF_INET) {
|
||||
// get destination port
|
||||
PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
|
||||
nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
|
||||
|
||||
if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
|
||||
|
||||
LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
|
||||
|
||||
// if the PROXY_RESOLVES_HOST flag is set, we assume
|
||||
// that the transport wants us to pass the SOCKS server the
|
||||
// hostname and port and let it do the name resolution.
|
||||
|
||||
// the real destination hostname and port was stored
|
||||
// in our info object earlier when this layer was created.
|
||||
|
||||
const nsCString& destHost = info->DestinationHost();
|
||||
|
||||
LOGDEBUG(("host:port -> %s:%li", destHost.get(), destPort));
|
||||
|
||||
request[3] = 0x03; // encoding of destination address (3 == hostname)
|
||||
|
||||
int host_len = destHost.Length();
|
||||
if (host_len > 255) {
|
||||
// SOCKS5 transmits the length of the hostname in a single char.
|
||||
// This gives us an absolute limit of 255 chars in a hostname, and
|
||||
// there's nothing we can do to extend it. I don't think many
|
||||
// hostnames will ever be bigger than this, so hopefully it's an
|
||||
// uneventful abort condition.
|
||||
LOGERROR (("Hostname too big for SOCKS5."));
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
request[4] = (char) host_len;
|
||||
request_len = 5;
|
||||
|
||||
// Send the initial header first...
|
||||
write_len = PR_Send(fd, request, request_len, 0, timeout);
|
||||
if (write_len != request_len) {
|
||||
// bad write
|
||||
LOGERROR(("PR_Send() failed sending connect command. Wrote: %d bytes; Expected: %d.", write_len, request_len));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Now send the hostname...
|
||||
write_len = PR_Send(fd, destHost.get(), host_len, 0, timeout);
|
||||
if (write_len != host_len) {
|
||||
// bad write
|
||||
LOGERROR(("PR_Send() failed sending connect command. Wrote: %d bytes; Expected: %d.", write_len, host_len));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// There's no data left because we just sent it.
|
||||
request_len = 0;
|
||||
|
||||
} else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
|
||||
|
||||
request[3] = 0x01; // encoding of destination address (1 == IPv4)
|
||||
request_len += 4;
|
||||
request_len = 8; // 4 for address, 4 SOCKS headers
|
||||
|
||||
char * ip = (char*)(&addr->inet.ip);
|
||||
request[4] = *ip++;
|
||||
@ -246,13 +312,17 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
|
||||
} else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
|
||||
|
||||
request[3] = 0x04; // encoding of destination address (4 == IPv6)
|
||||
request_len += 16;
|
||||
request_len = 20; // 16 for address, 4 SOCKS headers
|
||||
|
||||
char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);
|
||||
request[4] = *ip++; request[5] = *ip++; request[6] = *ip++; request[7] = *ip++;
|
||||
request[8] = *ip++; request[9] = *ip++; request[10] = *ip++; request[11] = *ip++;
|
||||
request[12] = *ip++; request[13] = *ip++; request[14] = *ip++; request[15] = *ip++;
|
||||
request[16] = *ip++; request[17] = *ip++; request[18] = *ip++; request[19] = *ip++;
|
||||
request[4] = *ip++; request[5] = *ip++;
|
||||
request[6] = *ip++; request[7] = *ip++;
|
||||
request[8] = *ip++; request[9] = *ip++;
|
||||
request[10] = *ip++; request[11] = *ip++;
|
||||
request[12] = *ip++; request[13] = *ip++;
|
||||
request[14] = *ip++; request[15] = *ip++;
|
||||
request[16] = *ip++; request[17] = *ip++;
|
||||
request[18] = *ip++; request[19] = *ip++;
|
||||
|
||||
// we're going to test to see if this address can
|
||||
// be mapped back into IPv4 without loss. if so,
|
||||
@ -260,28 +330,23 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
|
||||
// support for IPv6 is probably questionable.
|
||||
|
||||
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
|
||||
|
||||
request[3] = 0x01; // ipv4 encoding
|
||||
request[4] = request[16];
|
||||
request[5] = request[17];
|
||||
request[6] = request[18];
|
||||
request[7] = request[19];
|
||||
request_len -= 12;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Unknown address type
|
||||
LOGERROR(("Don't know what kind of IP address this is."));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// destination port
|
||||
PRUint16 destPort = PR_htons(PR_NetAddrInetPort(addr));
|
||||
|
||||
request[request_len-2] = (unsigned char)(destPort >> 8);
|
||||
request[request_len-1] = (unsigned char)destPort;
|
||||
// add the destination port to the request
|
||||
request[request_len] = (unsigned char)(destPort >> 8);
|
||||
request[request_len+1] = (unsigned char)destPort;
|
||||
request_len += 2;
|
||||
|
||||
write_len = PR_Send(fd, request, request_len, 0, timeout);
|
||||
if (write_len != request_len) {
|
||||
@ -358,10 +423,14 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
|
||||
PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, extAddr);
|
||||
|
||||
ip = (char*)(&extAddr->ipv6.ip.pr_s6_addr);
|
||||
*ip++ = response[4]; *ip++ = response[5]; *ip++ = response[6]; *ip++ = response[7];
|
||||
*ip++ = response[8]; *ip++ = response[9]; *ip++ = response[10]; *ip++ = response[11];
|
||||
*ip++ = response[12]; *ip++ = response[13]; *ip++ = response[14]; *ip++ = response[15];
|
||||
*ip++ = response[16]; *ip++ = response[17]; *ip++ = response[18]; *ip++ = response[19];
|
||||
*ip++ = response[4]; *ip++ = response[5];
|
||||
*ip++ = response[6]; *ip++ = response[7];
|
||||
*ip++ = response[8]; *ip++ = response[9];
|
||||
*ip++ = response[10]; *ip++ = response[11];
|
||||
*ip++ = response[12]; *ip++ = response[13];
|
||||
*ip++ = response[14]; *ip++ = response[15];
|
||||
*ip++ = response[16]; *ip++ = response[17];
|
||||
*ip++ = response[18]; *ip++ = response[19];
|
||||
|
||||
break;
|
||||
case 0x03: // FQDN (should not get this back)
|
||||
@ -387,48 +456,21 @@ ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
||||
|
||||
unsigned char request[12];
|
||||
int request_len = 0;
|
||||
int write_len;
|
||||
unsigned char response[10];
|
||||
int response_len = 0;
|
||||
char *ip = nsnull;
|
||||
|
||||
request[0] = 0x04; // SOCKS version 4
|
||||
request[1] = 0x01; // CD command code -- 1 for connect
|
||||
|
||||
// destination port
|
||||
PRUint16 destPort = PR_htons(PR_NetAddrInetPort(addr));
|
||||
PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
|
||||
|
||||
// store the port
|
||||
request[2] = (unsigned char)(destPort >> 8);
|
||||
request[3] = (unsigned char)destPort;
|
||||
|
||||
// destination IP
|
||||
char * ip = nsnull;
|
||||
|
||||
// IPv4
|
||||
if (PR_NetAddrFamily(addr) == PR_AF_INET)
|
||||
ip = (char*)(&addr->inet.ip);
|
||||
|
||||
// IPv6
|
||||
else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
|
||||
|
||||
// IPv4 address encoded in an IPv6 address
|
||||
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped))
|
||||
ip = (char*)(&addr->ipv6.ip.pr_s6_addr[12]);
|
||||
else {
|
||||
LOGERROR(("IPv6 not supported in SOCK 4."));
|
||||
return NS_ERROR_FAILURE; // SOCKS 4 can't do IPv6
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
LOGERROR(("Don't know what kind of IP address this is."));
|
||||
return NS_ERROR_FAILURE; // don't recognize this type
|
||||
}
|
||||
|
||||
request[4] = *ip++;
|
||||
request[5] = *ip++;
|
||||
request[6] = *ip++;
|
||||
request[7] = *ip++;
|
||||
|
||||
// username
|
||||
request[8] = 'M';
|
||||
request[9] = 'O';
|
||||
@ -437,11 +479,87 @@ ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
||||
request[11] = 0x00;
|
||||
|
||||
request_len = 12;
|
||||
int write_len = PR_Send(fd, request, request_len, 0, timeout);
|
||||
if (write_len != request_len) {
|
||||
|
||||
LOGERROR(("PR_Send() failed. Wrote: %d bytes; Expected: %d.", write_len, request_len));
|
||||
return NS_ERROR_FAILURE;
|
||||
nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
|
||||
|
||||
if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
|
||||
|
||||
LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
|
||||
|
||||
// if the PROXY_RESOLVES_HOST flag is set, we assume that the
|
||||
// transport wants us to pass the SOCKS server the hostname
|
||||
// and port and let it do the name resolution.
|
||||
|
||||
// an extension to SOCKS 4, called 4a, specifies a way
|
||||
// to do this, so we'll try that and hope the
|
||||
// server supports it.
|
||||
|
||||
// the real destination hostname and port was stored
|
||||
// in our info object earlier when this layer was created.
|
||||
|
||||
const nsCString& destHost = info->DestinationHost();
|
||||
|
||||
LOGDEBUG(("host:port -> %s:%li\n", destHost.get(), destPort));
|
||||
|
||||
// the IP portion of the query is set to this special address.
|
||||
request[4] = 0;
|
||||
request[5] = 0;
|
||||
request[6] = 0;
|
||||
request[7] = 1;
|
||||
|
||||
write_len = PR_Send(fd, request, request_len, 0, timeout);
|
||||
if (write_len != request_len) {
|
||||
LOGERROR(("PR_Send() failed. Wrote: %d bytes; Expected: %d.", write_len, request_len));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Remember the NULL.
|
||||
int host_len = destHost.Length() + 1;
|
||||
|
||||
write_len = PR_Send(fd, destHost.get(), host_len, 0, timeout);
|
||||
if (write_len != host_len) {
|
||||
LOGERROR(("PR_Send() failed. Wrote: %d bytes; Expected: %d.", write_len, host_len));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// No data to send, just sent it.
|
||||
request_len = 0;
|
||||
|
||||
} else if (PR_NetAddrFamily(addr) == PR_AF_INET) { // IPv4
|
||||
|
||||
// store the ip
|
||||
ip = (char*)(&addr->inet.ip);
|
||||
request[4] = *ip++;
|
||||
request[5] = *ip++;
|
||||
request[6] = *ip++;
|
||||
request[7] = *ip++;
|
||||
|
||||
} else if (PR_NetAddrFamily(addr) == PR_AF_INET6) { // IPv6
|
||||
|
||||
// IPv4 address encoded in an IPv6 address
|
||||
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
|
||||
// store the ip
|
||||
ip = (char*)(&addr->ipv6.ip.pr_s6_addr[12]);
|
||||
request[4] = *ip++;
|
||||
request[5] = *ip++;
|
||||
request[6] = *ip++;
|
||||
request[7] = *ip++;
|
||||
} else {
|
||||
LOGERROR(("IPv6 is not supported in SOCKS 4."));
|
||||
return NS_ERROR_FAILURE; // SOCKS 4 can't do IPv6
|
||||
}
|
||||
|
||||
} else {
|
||||
LOGERROR(("Don't know what kind of IP address this is."));
|
||||
return NS_ERROR_FAILURE; // don't recognize this type
|
||||
}
|
||||
|
||||
if (request_len > 0) {
|
||||
write_len = PR_Send(fd, request, request_len, 0, timeout);
|
||||
if (write_len != request_len) {
|
||||
LOGERROR(("PR_Send() failed. Wrote: %d bytes; Expected: %d.", write_len, request_len));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// get the server's response
|
||||
@ -689,6 +807,7 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRInt32 socksVersion,
|
||||
PRUint32 flags,
|
||||
PRFileDesc *fd,
|
||||
nsISupports** info)
|
||||
{
|
||||
@ -739,7 +858,7 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family,
|
||||
}
|
||||
|
||||
NS_ADDREF(infoObject);
|
||||
infoObject->Init(socksVersion, proxyHost, proxyPort);
|
||||
infoObject->Init(socksVersion, proxyHost, proxyPort, host, flags);
|
||||
layer->secret = (PRFilePrivate*) infoObject;
|
||||
rv = PR_PushIOLayer(fd, PR_GetLayersIdentity(fd), layer);
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Bradford <jab@atdot.org>
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -44,13 +45,14 @@
|
||||
#include "prio.h"
|
||||
#include "nscore.h"
|
||||
|
||||
nsresult nsSOCKSIOLayerAddToSocket(PRInt32 family,
|
||||
const char *host,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRInt32 socksVersion,
|
||||
PRFileDesc *fd,
|
||||
nsresult nsSOCKSIOLayerAddToSocket(PRInt32 family,
|
||||
const char *host,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRInt32 socksVersion,
|
||||
PRUint32 flags,
|
||||
PRFileDesc *fd,
|
||||
nsISupports **info);
|
||||
|
||||
#endif /* nsSOCKSIOLayer_h__ */
|
||||
|
@ -23,6 +23,7 @@
|
||||
* Contributor(s):
|
||||
* Justin Bradford <jab@atdot.org>
|
||||
* Darin Fisher <darin@meer.net>
|
||||
* Malcolm Smith <malsmith@cs.rmit.edu.au>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -80,6 +81,7 @@ nsSOCKSSocketProvider::NewSocket(PRInt32 family,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRUint32 flags,
|
||||
PRFileDesc **result,
|
||||
nsISupports **socksInfo)
|
||||
{
|
||||
@ -95,6 +97,7 @@ nsSOCKSSocketProvider::NewSocket(PRInt32 family,
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
mVersion,
|
||||
flags,
|
||||
sock,
|
||||
socksInfo);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -111,6 +114,7 @@ nsSOCKSSocketProvider::AddToSocket(PRInt32 family,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRUint32 flags,
|
||||
PRFileDesc *sock,
|
||||
nsISupports **socksInfo)
|
||||
{
|
||||
@ -120,6 +124,7 @@ nsSOCKSSocketProvider::AddToSocket(PRInt32 family,
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
mVersion,
|
||||
flags,
|
||||
sock,
|
||||
socksInfo);
|
||||
|
||||
|
@ -58,6 +58,7 @@ nsSSLSocketProvider::NewSocket(PRInt32 family,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRUint32 flags,
|
||||
PRFileDesc **_result,
|
||||
nsISupports **securityInfo)
|
||||
{
|
||||
@ -79,6 +80,7 @@ nsSSLSocketProvider::AddToSocket(PRInt32 family,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRUint32 flags,
|
||||
PRFileDesc *aSocket,
|
||||
nsISupports **securityInfo)
|
||||
{
|
||||
|
@ -58,6 +58,7 @@ nsTLSSocketProvider::NewSocket(PRInt32 family,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRUint32 flags,
|
||||
PRFileDesc **_result,
|
||||
nsISupports **securityInfo)
|
||||
{
|
||||
@ -80,6 +81,7 @@ nsTLSSocketProvider::AddToSocket(PRInt32 family,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRUint32 flags,
|
||||
PRFileDesc *aSocket,
|
||||
nsISupports **securityInfo)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user