forked from mirrors/gecko-dev
Initially reported and discussed in Bug 610896.
The simple solution of just flipping the pref `network.proxy.socks_remote_dns`
is risky due to potentially breaking SOCKS4 proxy users. Proxying
DNS on SOCKS4 isn't supported. Therefore we speak the incompatible
SOCKS4a protocol when `socks_remote_dns` is enabled, potentially
breaking users setup.
To keep backwards compatibility on SOCKS4 proxy users, that don't have
SOCKS4a support, the pref `network.proxy.socks_remote_dns` is split into
two prefs:
* `network.proxy.socks_remote_dns`: remote DNS for SOCKS4
* `network.proxy.socks5_remote_dns`: remote DNS for SOCKS5.
This way we proxy DNS by default on SOCKS5 while keeping user settings
on SOCKS4. This is a similar approach to the one described in
[Bug 610896 comment 17].
Proxying DNS in SOCKS4 by default is desireable (See [Bug 610896 comment 11]),
but out of scope for this patch. [Telemetry] on proxy usage by socks
version indicated that changing the default for SOCKS4 is likely break
some users setup and needs to be taken with more care.
The default values of [proxyDNS] now defaults to true for SOCKS5 proxies.
When creating nsIProxyInfo objects of SOCKS4 proxies, the default value
false is kept. Setting proxyDNS affects both SOCKS4 and SOCKS5 proxy by
modifying both `socks_remote_dns` and `socks5_remote_dns`. Therefore no
extension breakage is expected.
The enterprise policy can also modify the new pref
`network.proxy.socks5_remote_dns`.
Follow up bugs filed while implementing:
* Bug 1890542 - Also disable Prefetch non-manual configurations of socks
proxy
* Bug 1890554 - Use `ProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST` flag in
`nsHttpChannel::GetProxyDNSStrategy`
* Bug 1890549 - nsHttpChannel implementation DNS resolve strategy for
proxies incomplete
* Bug 1893670 - Proxy DNS by default for SOCK4 proxies. Defaulting to
SOCKS4a
[Bug 610896 comment 17]: https://bugzilla.mozilla.org/show_bug.cgi?id=610896#c17
[Bug 610896 comment 11]: https://bugzilla.mozilla.org/show_bug.cgi?id=610896#c11
[Telemetry]: https://bugzilla.mozilla.org/show_bug.cgi?id=1741375#c27
[proxyDNS]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/settings#proxydns
Differential Revision: https://phabricator.services.mozilla.com/D207532
430 lines
13 KiB
C++
430 lines
13 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef nsProtocolProxyService_h__
|
|
#define nsProtocolProxyService_h__
|
|
|
|
#include "nsString.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsTArray.h"
|
|
#include "nsIProtocolProxyService2.h"
|
|
#include "nsIProtocolProxyFilter.h"
|
|
#include "nsIProxyInfo.h"
|
|
#include "nsIObserver.h"
|
|
#include "nsTHashMap.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsITimer.h"
|
|
#include "prio.h"
|
|
#include "mozilla/Attributes.h"
|
|
|
|
class nsIPrefBranch;
|
|
class nsISystemProxySettings;
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
using nsFailedProxyTable = nsTHashMap<nsCStringHashKey, uint32_t>;
|
|
|
|
class nsPACMan;
|
|
class nsProxyInfo;
|
|
struct nsProtocolInfo;
|
|
|
|
// CID for the nsProtocolProxyService class
|
|
// 091eedd8-8bae-4fe3-ad62-0c87351e640d
|
|
#define NS_PROTOCOL_PROXY_SERVICE_IMPL_CID \
|
|
{ \
|
|
0x091eedd8, 0x8bae, 0x4fe3, { \
|
|
0xad, 0x62, 0x0c, 0x87, 0x35, 0x1e, 0x64, 0x0d \
|
|
} \
|
|
}
|
|
|
|
class nsProtocolProxyService final : public nsIProtocolProxyService2,
|
|
public nsIObserver,
|
|
public nsITimerCallback,
|
|
public nsINamed {
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIPROTOCOLPROXYSERVICE2
|
|
NS_DECL_NSIPROTOCOLPROXYSERVICE
|
|
NS_DECL_NSIOBSERVER
|
|
NS_DECL_NSITIMERCALLBACK
|
|
NS_DECL_NSINAMED
|
|
|
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROTOCOL_PROXY_SERVICE_IMPL_CID)
|
|
|
|
nsProtocolProxyService();
|
|
|
|
nsresult Init();
|
|
|
|
public:
|
|
// An instance of this struct is allocated for each registered
|
|
// nsIProtocolProxyFilter and each nsIProtocolProxyChannelFilter.
|
|
class FilterLink {
|
|
public:
|
|
NS_INLINE_DECL_REFCOUNTING(FilterLink)
|
|
|
|
uint32_t position;
|
|
nsCOMPtr<nsIProtocolProxyFilter> filter;
|
|
nsCOMPtr<nsIProtocolProxyChannelFilter> channelFilter;
|
|
|
|
FilterLink(uint32_t p, nsIProtocolProxyFilter* f);
|
|
FilterLink(uint32_t p, nsIProtocolProxyChannelFilter* cf);
|
|
|
|
private:
|
|
~FilterLink();
|
|
};
|
|
|
|
protected:
|
|
friend class nsAsyncResolveRequest;
|
|
friend class TestProtocolProxyService_LoadHostFilters_Test; // for gtest
|
|
|
|
~nsProtocolProxyService();
|
|
|
|
/**
|
|
* This method is called whenever a preference may have changed or
|
|
* to initialize all preferences.
|
|
*
|
|
* @param prefs
|
|
* This must be a pointer to the root pref branch.
|
|
* @param name
|
|
* This can be the name of a fully-qualified preference, or it can
|
|
* be null, in which case all preferences will be initialized.
|
|
*/
|
|
void PrefsChanged(nsIPrefBranch* prefBranch, const char* pref);
|
|
|
|
/**
|
|
* This method is called to create a nsProxyInfo instance from the given
|
|
* PAC-style proxy string. It parses up to the end of the string, or to
|
|
* the next ';' character.
|
|
*
|
|
* @param proxy
|
|
* The PAC-style proxy string to parse. This must not be null.
|
|
* @param aResolveFlags
|
|
* The flags passed to Resolve or AsyncResolve that are stored in
|
|
* proxyInfo.
|
|
* @param result
|
|
* Upon return this points to a newly allocated nsProxyInfo or null
|
|
* if the proxy string was invalid.
|
|
*
|
|
* @return A pointer beyond the parsed proxy string (never null).
|
|
*/
|
|
const char* ExtractProxyInfo(const char* start, uint32_t aResolveFlags,
|
|
nsProxyInfo** result);
|
|
|
|
/**
|
|
* Load the specified PAC file.
|
|
*
|
|
* @param pacURI
|
|
* The URI spec of the PAC file to load.
|
|
*/
|
|
nsresult ConfigureFromPAC(const nsCString& spec, bool forceReload);
|
|
|
|
/**
|
|
* This method builds a list of nsProxyInfo objects from the given PAC-
|
|
* style string.
|
|
*
|
|
* @param pacString
|
|
* The PAC-style proxy string to parse. This may be empty.
|
|
* @param aResolveFlags
|
|
* The flags passed to Resolve or AsyncResolve that are stored in
|
|
* proxyInfo.
|
|
* @param result
|
|
* The resulting list of proxy info objects.
|
|
*/
|
|
void ProcessPACString(const nsCString& pacString, uint32_t aResolveFlags,
|
|
nsIProxyInfo** result);
|
|
|
|
/**
|
|
* This method generates a string valued identifier for the given
|
|
* nsProxyInfo object.
|
|
*
|
|
* @param pi
|
|
* The nsProxyInfo object from which to generate the key.
|
|
* @param result
|
|
* Upon return, this parameter holds the generated key.
|
|
*/
|
|
void GetProxyKey(nsProxyInfo* pi, nsCString& key);
|
|
|
|
/**
|
|
* @return Seconds since start of session.
|
|
*/
|
|
uint32_t SecondsSinceSessionStart();
|
|
|
|
/**
|
|
* This method removes the specified proxy from the disabled list.
|
|
*
|
|
* @param pi
|
|
* The nsProxyInfo object identifying the proxy to enable.
|
|
*/
|
|
void EnableProxy(nsProxyInfo* pi);
|
|
|
|
/**
|
|
* This method adds the specified proxy to the disabled list.
|
|
*
|
|
* @param pi
|
|
* The nsProxyInfo object identifying the proxy to disable.
|
|
*/
|
|
void DisableProxy(nsProxyInfo* pi);
|
|
|
|
/**
|
|
* This method tests to see if the given proxy is disabled.
|
|
*
|
|
* @param pi
|
|
* The nsProxyInfo object identifying the proxy to test.
|
|
*
|
|
* @return True if the specified proxy is disabled.
|
|
*/
|
|
bool IsProxyDisabled(nsProxyInfo* pi);
|
|
|
|
/**
|
|
* This method queries the protocol handler for the given scheme to check
|
|
* for the protocol flags and default port.
|
|
*
|
|
* @param uri
|
|
* The URI to query.
|
|
* @param info
|
|
* Holds information about the protocol upon return. Pass address
|
|
* of structure when you call this method. This parameter must not
|
|
* be null.
|
|
*/
|
|
nsresult GetProtocolInfo(nsIURI* uri, nsProtocolInfo* info);
|
|
|
|
/**
|
|
* This method is an internal version nsIProtocolProxyService::newProxyInfo
|
|
* that expects a string literal for the type.
|
|
*
|
|
* @param type
|
|
* The proxy type.
|
|
* @param host
|
|
* The proxy host name (UTF-8 ok).
|
|
* @param port
|
|
* The proxy port number.
|
|
* @param username
|
|
* The username for the proxy (ASCII). May be "", but not null.
|
|
* @param password
|
|
* The password for the proxy (ASCII). May be "", but not null.
|
|
* @param flags
|
|
* The proxy flags (nsIProxyInfo::flags).
|
|
* @param timeout
|
|
* The failover timeout for this proxy.
|
|
* @param next
|
|
* The next proxy to try if this one fails.
|
|
* @param aResolveFlags
|
|
* The flags passed to resolve (from nsIProtocolProxyService).
|
|
* @param result
|
|
* The resulting nsIProxyInfo object.
|
|
*/
|
|
nsresult NewProxyInfo_Internal(const char* type, const nsACString& host,
|
|
int32_t port, const nsACString& username,
|
|
const nsACString& password,
|
|
const nsACString& aProxyAuthorizationHeader,
|
|
const nsACString& aConnectionIsolationKey,
|
|
uint32_t flags, uint32_t timeout,
|
|
nsIProxyInfo* aFailoverProxy,
|
|
uint32_t aResolveFlags, nsIProxyInfo** result);
|
|
|
|
/**
|
|
* This method is an internal version of Resolve that does not query PAC.
|
|
* It performs all of the built-in processing, and reports back to the
|
|
* caller with either the proxy info result or a flag to instruct the
|
|
* caller to use PAC instead.
|
|
*
|
|
* @param channel
|
|
* The channel to test.
|
|
* @param info
|
|
* Information about the URI's protocol.
|
|
* @param flags
|
|
* The flags passed to either the resolve or the asyncResolve method.
|
|
* @param usePAC
|
|
* If this flag is set upon return, then PAC should be queried to
|
|
* resolve the proxy info.
|
|
* @param result
|
|
* The resulting proxy info or null.
|
|
*/
|
|
nsresult Resolve_Internal(nsIChannel* channel, const nsProtocolInfo& info,
|
|
uint32_t flags, bool* usePAC,
|
|
nsIProxyInfo** result);
|
|
|
|
/**
|
|
* Shallow copy of the current list of registered filters so that
|
|
* we can safely let them asynchronously process a single proxy
|
|
* resolution request.
|
|
*/
|
|
void CopyFilters(nsTArray<RefPtr<FilterLink>>& aCopy);
|
|
|
|
/**
|
|
* This method applies the provided filter to the given proxy info
|
|
* list, and expects |callback| be called on (synchronously or
|
|
* asynchronously) to provide the updated proxyinfo list.
|
|
*/
|
|
bool ApplyFilter(FilterLink const* filterLink, nsIChannel* channel,
|
|
const nsProtocolInfo& info, nsCOMPtr<nsIProxyInfo> list,
|
|
nsIProxyProtocolFilterResult* callback);
|
|
|
|
/**
|
|
* This method prunes out disabled and disallowed proxies from a given
|
|
* proxy info list.
|
|
*
|
|
* @param info
|
|
* Information about the URI's protocol.
|
|
* @param proxyInfo
|
|
* The proxy info list to be modified. This is an inout param.
|
|
*/
|
|
void PruneProxyInfo(const nsProtocolInfo& info, nsIProxyInfo** list);
|
|
|
|
/**
|
|
* This method is a simple wrapper around PruneProxyInfo that takes the
|
|
* proxy info list inout param as a nsCOMPtr.
|
|
*/
|
|
void PruneProxyInfo(const nsProtocolInfo& info,
|
|
nsCOMPtr<nsIProxyInfo>& proxyInfo) {
|
|
nsIProxyInfo* pi = nullptr;
|
|
proxyInfo.swap(pi);
|
|
PruneProxyInfo(info, &pi);
|
|
proxyInfo.swap(pi);
|
|
}
|
|
|
|
/**
|
|
* This method populates mHostFiltersArray from the given string.
|
|
*
|
|
* @param hostFilters
|
|
* A "no-proxy-for" exclusion list.
|
|
*/
|
|
void LoadHostFilters(const nsACString& aFilters);
|
|
|
|
/**
|
|
* This method checks the given URI against mHostFiltersArray.
|
|
*
|
|
* @param uri
|
|
* The URI to test.
|
|
* @param defaultPort
|
|
* The default port for the given URI.
|
|
*
|
|
* @return True if the URI can use the specified proxy.
|
|
*/
|
|
bool CanUseProxy(nsIURI* uri, int32_t defaultPort);
|
|
|
|
/**
|
|
* Disable Prefetch in the DNS service if a proxy is in use.
|
|
*
|
|
* @param aProxy
|
|
* The proxy information
|
|
*/
|
|
void MaybeDisableDNSPrefetch(nsIProxyInfo* aProxy);
|
|
|
|
private:
|
|
nsresult SetupPACThread(
|
|
nsISerialEventTarget* mainThreadEventTarget = nullptr);
|
|
nsresult ResetPACThread();
|
|
nsresult ReloadNetworkPAC();
|
|
|
|
nsresult AsyncConfigureWPADOrFromPAC(bool aForceReload, bool aResetPACThread,
|
|
bool aSystemWPADAllowed);
|
|
nsresult OnAsyncGetPACURIOrSystemWPADSetting(bool aForceReload,
|
|
bool aResetPACThread,
|
|
nsresult aResult,
|
|
const nsACString& aUri,
|
|
bool aSystemWPADSetting);
|
|
|
|
public:
|
|
// The Sun Forte compiler and others implement older versions of the
|
|
// C++ standard's rules on access and nested classes. These structs
|
|
// need to be public in order to deal with those compilers.
|
|
|
|
struct HostInfoIP {
|
|
uint16_t family;
|
|
uint16_t mask_len;
|
|
PRIPv6Addr addr; // possibly IPv4-mapped address
|
|
};
|
|
|
|
struct HostInfoName {
|
|
char* host;
|
|
uint32_t host_len;
|
|
};
|
|
|
|
protected:
|
|
// simplified array of filters defined by this struct
|
|
struct HostInfo {
|
|
bool is_ipaddr{false};
|
|
int32_t port{0};
|
|
// other members intentionally uninitialized
|
|
union {
|
|
HostInfoIP ip;
|
|
HostInfoName name;
|
|
};
|
|
|
|
HostInfo() = default;
|
|
~HostInfo() {
|
|
if (!is_ipaddr && name.host) {
|
|
free(name.host);
|
|
}
|
|
}
|
|
};
|
|
|
|
private:
|
|
// Private methods to insert and remove FilterLinks from the FilterLink chain.
|
|
nsresult InsertFilterLink(RefPtr<FilterLink>&& link);
|
|
nsresult RemoveFilterLink(nsISupports* givenObject);
|
|
|
|
protected:
|
|
// Indicates if local hosts (plain hostnames, no dots) should use the proxy
|
|
bool mFilterLocalHosts{false};
|
|
|
|
// Holds an array of HostInfo objects
|
|
nsTArray<UniquePtr<HostInfo>> mHostFiltersArray;
|
|
|
|
// Filters, always sorted by the position.
|
|
nsTArray<RefPtr<FilterLink>> mFilters;
|
|
|
|
nsTArray<nsCOMPtr<nsIProxyConfigChangedCallback>>
|
|
mProxyConfigChangedCallbacks;
|
|
|
|
uint32_t mProxyConfig{PROXYCONFIG_DIRECT};
|
|
|
|
nsCString mHTTPProxyHost;
|
|
int32_t mHTTPProxyPort{-1};
|
|
|
|
nsCString mHTTPSProxyHost;
|
|
int32_t mHTTPSProxyPort{-1};
|
|
|
|
// mSOCKSProxyTarget could be a host, a domain socket path,
|
|
// or a named-pipe name.
|
|
nsCString mSOCKSProxyTarget;
|
|
int32_t mSOCKSProxyPort{-1};
|
|
int32_t mSOCKSProxyVersion{nsIProxyInfo::SOCKS_V4};
|
|
bool mSOCKS4ProxyRemoteDNS{false};
|
|
bool mSOCKS5ProxyRemoteDNS{false};
|
|
bool mProxyOverTLS{true};
|
|
bool mWPADOverDHCPEnabled{false};
|
|
|
|
RefPtr<nsPACMan> mPACMan; // non-null if we are using PAC
|
|
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
|
|
|
|
PRTime mSessionStart;
|
|
nsFailedProxyTable mFailedProxies;
|
|
// 30 minute default
|
|
int32_t mFailedProxyTimeout{30 * 60};
|
|
|
|
private:
|
|
nsresult AsyncResolveInternal(nsIChannel* channel, uint32_t flags,
|
|
nsIProtocolProxyCallback* callback,
|
|
nsICancelable** result, bool isSyncOK,
|
|
nsISerialEventTarget* mainThreadEventTarget);
|
|
|
|
// compute `NewProxyInfo_Internal` parameters based on mSOCKS variables
|
|
const char* SOCKSProxyType();
|
|
bool SOCKSRemoteDNS();
|
|
|
|
bool mIsShutdown{false};
|
|
nsCOMPtr<nsITimer> mReloadPACTimer;
|
|
};
|
|
|
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsProtocolProxyService,
|
|
NS_PROTOCOL_PROXY_SERVICE_IMPL_CID)
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|
|
#endif // !nsProtocolProxyService_h__
|