michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsISystemProxySettings.h" michael@0: #include "mozilla/ModuleUtils.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIGConfService.h" michael@0: #include "nsIURI.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsArrayUtils.h" michael@0: #include "prnetdb.h" michael@0: #include "prenv.h" michael@0: #include "nsPrintfCString.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsIGSettingsService.h" michael@0: #include "nsInterfaceHashtable.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsIURI.h" michael@0: michael@0: class nsUnixSystemProxySettings MOZ_FINAL : public nsISystemProxySettings { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSISYSTEMPROXYSETTINGS michael@0: michael@0: nsUnixSystemProxySettings() michael@0: : mSchemeProxySettings(5) michael@0: { michael@0: } michael@0: nsresult Init(); michael@0: michael@0: private: michael@0: ~nsUnixSystemProxySettings() {} michael@0: michael@0: nsCOMPtr mGConf; michael@0: nsCOMPtr mGSettings; michael@0: nsCOMPtr mProxySettings; michael@0: nsInterfaceHashtable mSchemeProxySettings; michael@0: bool IsProxyMode(const char* aMode); michael@0: nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult); michael@0: nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult); michael@0: nsresult GetProxyFromGSettings(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult); michael@0: nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, nsACString& aResult); michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings) michael@0: michael@0: NS_IMETHODIMP michael@0: nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) michael@0: { michael@0: // dbus prevents us from being threadsafe, but this routine should not block anyhow michael@0: *aMainThreadOnly = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::Init() michael@0: { michael@0: mGSettings = do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); michael@0: if (mGSettings) { michael@0: mGSettings->GetCollectionForSchema(NS_LITERAL_CSTRING("org.gnome.system.proxy"), michael@0: getter_AddRefs(mProxySettings)); michael@0: } michael@0: if (!mProxySettings) { michael@0: mGConf = do_GetService(NS_GCONFSERVICE_CONTRACTID); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsUnixSystemProxySettings::IsProxyMode(const char* aMode) michael@0: { michael@0: nsAutoCString mode; michael@0: return NS_SUCCEEDED(mGConf->GetString(NS_LITERAL_CSTRING("/system/proxy/mode"), mode)) && michael@0: mode.EqualsASCII(aMode); michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::GetPACURI(nsACString& aResult) michael@0: { michael@0: if (mProxySettings) { michael@0: nsCString proxyMode; michael@0: // Check if mode is auto michael@0: nsresult rv = mProxySettings->GetString(NS_LITERAL_CSTRING("mode"), proxyMode); michael@0: if (rv == NS_OK && proxyMode.Equals("auto")) { michael@0: return mProxySettings->GetString(NS_LITERAL_CSTRING("autoconfig-url"), aResult); michael@0: } michael@0: /* The org.gnome.system.proxy schema has been found, but auto mode is not set. michael@0: * Don't try the GConf and return empty string. */ michael@0: aResult.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mGConf && IsProxyMode("auto")) { michael@0: return mGConf->GetString(NS_LITERAL_CSTRING("/system/proxy/autoconfig_url"), michael@0: aResult); michael@0: } michael@0: // Return an empty string when auto mode is not set. michael@0: aResult.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool michael@0: IsInNoProxyList(const nsACString& aHost, int32_t aPort, const char* noProxyVal) michael@0: { michael@0: NS_ASSERTION(aPort >= 0, "Negative port?"); michael@0: michael@0: nsAutoCString noProxy(noProxyVal); michael@0: if (noProxy.EqualsLiteral("*")) michael@0: return true; michael@0: michael@0: noProxy.StripWhitespace(); michael@0: michael@0: nsReadingIterator pos; michael@0: nsReadingIterator end; michael@0: noProxy.BeginReading(pos); michael@0: noProxy.EndReading(end); michael@0: while (pos != end) { michael@0: nsReadingIterator last = pos; michael@0: nsReadingIterator nextPos; michael@0: if (FindCharInReadable(',', last, end)) { michael@0: nextPos = last; michael@0: ++nextPos; michael@0: } else { michael@0: last = end; michael@0: nextPos = end; michael@0: } michael@0: michael@0: nsReadingIterator colon = pos; michael@0: int32_t port = -1; michael@0: if (FindCharInReadable(':', colon, last)) { michael@0: ++colon; michael@0: nsDependentCSubstring portStr(colon, last); michael@0: nsAutoCString portStr2(portStr); // We need this for ToInteger. String API's suck. michael@0: nsresult err; michael@0: port = portStr2.ToInteger(&err); michael@0: if (NS_FAILED(err)) { michael@0: port = -2; // don't match any port, so we ignore this pattern michael@0: } michael@0: --colon; michael@0: } else { michael@0: colon = last; michael@0: } michael@0: michael@0: if (port == -1 || port == aPort) { michael@0: nsDependentCSubstring hostStr(pos, colon); michael@0: // By using StringEndsWith instead of an equality comparator, we can include sub-domains michael@0: if (StringEndsWith(aHost, hostStr, nsCaseInsensitiveCStringComparator())) michael@0: return true; michael@0: } michael@0: michael@0: pos = nextPos; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: static void SetProxyResult(const char* aType, const nsACString& aHost, michael@0: int32_t aPort, nsACString& aResult) michael@0: { michael@0: aResult.AppendASCII(aType); michael@0: aResult.Append(' '); michael@0: aResult.Append(aHost); michael@0: if (aPort > 0) { michael@0: aResult.Append(':'); michael@0: aResult.Append(nsPrintfCString("%d", aPort)); michael@0: } michael@0: } michael@0: michael@0: static nsresult michael@0: GetProxyFromEnvironment(const nsACString& aScheme, michael@0: const nsACString& aHost, michael@0: int32_t aPort, michael@0: nsACString& aResult) michael@0: { michael@0: nsAutoCString envVar; michael@0: envVar.Append(aScheme); michael@0: envVar.AppendLiteral("_proxy"); michael@0: const char* proxyVal = PR_GetEnv(envVar.get()); michael@0: if (!proxyVal) { michael@0: proxyVal = PR_GetEnv("all_proxy"); michael@0: if (!proxyVal) { michael@0: // Return failure so that the caller can detect the failure and michael@0: // fall back to other proxy detection (e.g., WPAD) michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: const char* noProxyVal = PR_GetEnv("no_proxy"); michael@0: if (noProxyVal && IsInNoProxyList(aHost, aPort, noProxyVal)) { michael@0: aResult.AppendLiteral("DIRECT"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Use our URI parser to crack the proxy URI michael@0: nsCOMPtr proxyURI; michael@0: nsresult rv = NS_NewURI(getter_AddRefs(proxyURI), proxyVal); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Is there a way to specify "socks://" or something in these environment michael@0: // variables? I can't find any documentation. michael@0: bool isHTTP; michael@0: rv = proxyURI->SchemeIs("http", &isHTTP); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (!isHTTP) michael@0: return NS_ERROR_UNKNOWN_PROTOCOL; michael@0: michael@0: nsAutoCString proxyHost; michael@0: rv = proxyURI->GetHost(proxyHost); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: int32_t proxyPort; michael@0: rv = proxyURI->GetPort(&proxyPort); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: SetProxyResult("PROXY", proxyHost, proxyPort, aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::SetProxyResultFromGConf(const char* aKeyBase, const char* aType, michael@0: nsACString& aResult) michael@0: { michael@0: nsAutoCString hostKey; michael@0: hostKey.AppendASCII(aKeyBase); michael@0: hostKey.AppendLiteral("host"); michael@0: nsAutoCString host; michael@0: nsresult rv = mGConf->GetString(hostKey, host); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (host.IsEmpty()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsAutoCString portKey; michael@0: portKey.AppendASCII(aKeyBase); michael@0: portKey.AppendLiteral("port"); michael@0: int32_t port; michael@0: rv = mGConf->GetInt(portKey, &port); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: /* When port is 0, proxy is not considered as enabled even if host is set. */ michael@0: if (port == 0) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: SetProxyResult(aType, host, port, aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, michael@0: nsACString& aResult) michael@0: { michael@0: nsDependentCString key(aKeyBase); michael@0: michael@0: nsCOMPtr proxy_settings = mSchemeProxySettings.Get(key); michael@0: nsresult rv; michael@0: if (!proxy_settings) { michael@0: rv = mGSettings->GetCollectionForSchema(key, getter_AddRefs(proxy_settings)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mSchemeProxySettings.Put(key, proxy_settings); michael@0: } michael@0: michael@0: nsAutoCString host; michael@0: rv = proxy_settings->GetString(NS_LITERAL_CSTRING("host"), host); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (host.IsEmpty()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: int32_t port; michael@0: rv = proxy_settings->GetInt(NS_LITERAL_CSTRING("port"), &port); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: /* When port is 0, proxy is not considered as enabled even if host is set. */ michael@0: if (port == 0) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: SetProxyResult(aType, host, port, aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* copied from nsProtocolProxyService.cpp --- we should share this! */ michael@0: static void michael@0: proxy_MaskIPv6Addr(PRIPv6Addr &addr, uint16_t mask_len) michael@0: { michael@0: if (mask_len == 128) michael@0: return; michael@0: michael@0: if (mask_len > 96) { michael@0: addr.pr_s6_addr32[3] = PR_htonl( michael@0: PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len))); michael@0: } michael@0: else if (mask_len > 64) { michael@0: addr.pr_s6_addr32[3] = 0; michael@0: addr.pr_s6_addr32[2] = PR_htonl( michael@0: PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len))); michael@0: } michael@0: else if (mask_len > 32) { michael@0: addr.pr_s6_addr32[3] = 0; michael@0: addr.pr_s6_addr32[2] = 0; michael@0: addr.pr_s6_addr32[1] = PR_htonl( michael@0: PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len))); michael@0: } michael@0: else { michael@0: addr.pr_s6_addr32[3] = 0; michael@0: addr.pr_s6_addr32[2] = 0; michael@0: addr.pr_s6_addr32[1] = 0; michael@0: addr.pr_s6_addr32[0] = PR_htonl( michael@0: PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len))); michael@0: } michael@0: } michael@0: michael@0: static bool ConvertToIPV6Addr(const nsACString& aName, michael@0: PRIPv6Addr* aAddr, int32_t* aMask) michael@0: { michael@0: PRNetAddr addr; michael@0: // try to convert hostname to IP michael@0: if (PR_StringToNetAddr(PromiseFlatCString(aName).get(), &addr) != PR_SUCCESS) michael@0: return false; michael@0: michael@0: // convert parsed address to IPv6 michael@0: if (addr.raw.family == PR_AF_INET) { michael@0: // convert to IPv4-mapped address michael@0: PR_ConvertIPv4AddrToIPv6(addr.inet.ip, aAddr); michael@0: if (aMask) { michael@0: if (*aMask <= 32) michael@0: *aMask += 96; michael@0: else michael@0: return false; michael@0: } michael@0: } else if (addr.raw.family == PR_AF_INET6) { michael@0: // copy the address michael@0: memcpy(aAddr, &addr.ipv6.ip, sizeof(PRIPv6Addr)); michael@0: } else { michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static bool HostIgnoredByProxy(const nsACString& aIgnore, michael@0: const nsACString& aHost) michael@0: { michael@0: if (aIgnore.Equals(aHost, nsCaseInsensitiveCStringComparator())) michael@0: return true; michael@0: michael@0: if (aIgnore.First() == '*' && michael@0: StringEndsWith(aHost, nsDependentCSubstring(aIgnore, 1), michael@0: nsCaseInsensitiveCStringComparator())) michael@0: return true; michael@0: michael@0: int32_t mask = 128; michael@0: nsReadingIterator start; michael@0: nsReadingIterator slash; michael@0: nsReadingIterator end; michael@0: aIgnore.BeginReading(start); michael@0: aIgnore.BeginReading(slash); michael@0: aIgnore.EndReading(end); michael@0: if (FindCharInReadable('/', slash, end)) { michael@0: ++slash; michael@0: nsDependentCSubstring maskStr(slash, end); michael@0: nsAutoCString maskStr2(maskStr); michael@0: nsresult err; michael@0: mask = maskStr2.ToInteger(&err); michael@0: if (NS_FAILED(err)) { michael@0: mask = 128; michael@0: } michael@0: --slash; michael@0: } else { michael@0: slash = end; michael@0: } michael@0: michael@0: nsDependentCSubstring ignoreStripped(start, slash); michael@0: PRIPv6Addr ignoreAddr, hostAddr; michael@0: if (!ConvertToIPV6Addr(ignoreStripped, &ignoreAddr, &mask) || michael@0: !ConvertToIPV6Addr(aHost, &hostAddr, nullptr)) michael@0: return false; michael@0: michael@0: proxy_MaskIPv6Addr(ignoreAddr, mask); michael@0: proxy_MaskIPv6Addr(hostAddr, mask); michael@0: michael@0: return memcmp(&ignoreAddr, &hostAddr, sizeof(PRIPv6Addr)) == 0; michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::GetProxyFromGConf(const nsACString& aScheme, michael@0: const nsACString& aHost, michael@0: int32_t aPort, michael@0: nsACString& aResult) michael@0: { michael@0: bool masterProxySwitch = false; michael@0: mGConf->GetBool(NS_LITERAL_CSTRING("/system/http_proxy/use_http_proxy"), &masterProxySwitch); michael@0: // if no proxy is set in GConf return NS_ERROR_FAILURE michael@0: if (!(IsProxyMode("manual") || masterProxySwitch)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr ignoreList; michael@0: if (NS_SUCCEEDED(mGConf->GetStringList(NS_LITERAL_CSTRING("/system/http_proxy/ignore_hosts"), michael@0: getter_AddRefs(ignoreList))) && ignoreList) { michael@0: uint32_t len = 0; michael@0: ignoreList->GetLength(&len); michael@0: for (uint32_t i = 0; i < len; ++i) { michael@0: nsCOMPtr str = do_QueryElementAt(ignoreList, i); michael@0: if (str) { michael@0: nsAutoString s; michael@0: if (NS_SUCCEEDED(str->GetData(s)) && !s.IsEmpty()) { michael@0: if (HostIgnoredByProxy(NS_ConvertUTF16toUTF8(s), aHost)) { michael@0: aResult.AppendLiteral("DIRECT"); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool useHttpProxyForAll = false; michael@0: // This setting sometimes doesn't exist, don't bail on failure michael@0: mGConf->GetBool(NS_LITERAL_CSTRING("/system/http_proxy/use_same_proxy"), &useHttpProxyForAll); michael@0: michael@0: nsresult rv; michael@0: if (!useHttpProxyForAll) { michael@0: rv = SetProxyResultFromGConf("/system/proxy/socks_", "SOCKS", aResult); michael@0: if (NS_SUCCEEDED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: if (aScheme.LowerCaseEqualsLiteral("http") || useHttpProxyForAll) { michael@0: rv = SetProxyResultFromGConf("/system/http_proxy/", "PROXY", aResult); michael@0: } else if (aScheme.LowerCaseEqualsLiteral("https")) { michael@0: rv = SetProxyResultFromGConf("/system/proxy/secure_", "PROXY", aResult); michael@0: } else if (aScheme.LowerCaseEqualsLiteral("ftp")) { michael@0: rv = SetProxyResultFromGConf("/system/proxy/ftp_", "PROXY", aResult); michael@0: } else { michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::GetProxyFromGSettings(const nsACString& aScheme, michael@0: const nsACString& aHost, michael@0: int32_t aPort, michael@0: nsACString& aResult) michael@0: { michael@0: nsCString proxyMode; michael@0: nsresult rv = mProxySettings->GetString(NS_LITERAL_CSTRING("mode"), proxyMode); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // return NS_ERROR_FAILURE when no proxy is set michael@0: if (!proxyMode.Equals("manual")) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr ignoreList; michael@0: if (NS_SUCCEEDED(mProxySettings->GetStringList(NS_LITERAL_CSTRING("ignore-hosts"), michael@0: getter_AddRefs(ignoreList))) && ignoreList) { michael@0: uint32_t len = 0; michael@0: ignoreList->GetLength(&len); michael@0: for (uint32_t i = 0; i < len; ++i) { michael@0: nsCOMPtr str = do_QueryElementAt(ignoreList, i); michael@0: if (str) { michael@0: nsCString s; michael@0: if (NS_SUCCEEDED(str->GetData(s)) && !s.IsEmpty()) { michael@0: if (HostIgnoredByProxy(s, aHost)) { michael@0: aResult.AppendLiteral("DIRECT"); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aScheme.LowerCaseEqualsLiteral("http")) { michael@0: rv = SetProxyResultFromGSettings("org.gnome.system.proxy.http", "PROXY", aResult); michael@0: } else if (aScheme.LowerCaseEqualsLiteral("https")) { michael@0: rv = SetProxyResultFromGSettings("org.gnome.system.proxy.https", "PROXY", aResult); michael@0: /* Try to use HTTP proxy when HTTPS proxy is not explicitly defined */ michael@0: if (rv != NS_OK) michael@0: rv = SetProxyResultFromGSettings("org.gnome.system.proxy.http", "PROXY", aResult); michael@0: } else if (aScheme.LowerCaseEqualsLiteral("ftp")) { michael@0: rv = SetProxyResultFromGSettings("org.gnome.system.proxy.ftp", "PROXY", aResult); michael@0: } else { michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: if (rv != NS_OK) { michael@0: /* If proxy for scheme is not specified, use SOCKS proxy for all schemes */ michael@0: rv = SetProxyResultFromGSettings("org.gnome.system.proxy.socks", "SOCKS", aResult); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: aResult.AppendLiteral("DIRECT"); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec, michael@0: const nsACString & aScheme, michael@0: const nsACString & aHost, michael@0: const int32_t aPort, michael@0: nsACString & aResult) michael@0: { michael@0: if (mProxySettings) { michael@0: nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult); michael@0: if (NS_SUCCEEDED(rv)) michael@0: return rv; michael@0: } michael@0: if (mGConf) michael@0: return GetProxyFromGConf(aScheme, aHost, aPort, aResult); michael@0: michael@0: return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult); michael@0: } michael@0: michael@0: #define NS_UNIXSYSTEMPROXYSERVICE_CID /* 0fa3158c-d5a7-43de-9181-a285e74cf1d4 */\ michael@0: { 0x0fa3158c, 0xd5a7, 0x43de, \ michael@0: {0x91, 0x81, 0xa2, 0x85, 0xe7, 0x4c, 0xf1, 0xd4 } } michael@0: michael@0: NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUnixSystemProxySettings, Init) michael@0: NS_DEFINE_NAMED_CID(NS_UNIXSYSTEMPROXYSERVICE_CID); michael@0: michael@0: static const mozilla::Module::CIDEntry kUnixProxyCIDs[] = { michael@0: { &kNS_UNIXSYSTEMPROXYSERVICE_CID, false, nullptr, nsUnixSystemProxySettingsConstructor }, michael@0: { nullptr } michael@0: }; michael@0: michael@0: static const mozilla::Module::ContractIDEntry kUnixProxyContracts[] = { michael@0: { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_UNIXSYSTEMPROXYSERVICE_CID }, michael@0: { nullptr } michael@0: }; michael@0: michael@0: static const mozilla::Module kUnixProxyModule = { michael@0: mozilla::Module::kVersion, michael@0: kUnixProxyCIDs, michael@0: kUnixProxyContracts michael@0: }; michael@0: michael@0: NSMODULE_DEFN(nsUnixProxyModule) = &kUnixProxyModule;