From: Robert O'Callahan Subject: proxy.pac: host resolution error References: https://bugzilla.novell.com/show_bug.cgi?id=196506 https://bugzilla.mozilla.org/show_bug.cgi?id=347307 Index: netwerk/base/src/nsProxyAutoConfig.js ================================================================================ --- netwerk/base/src/nsProxyAutoConfig.js +++ netwerk/base/src/nsProxyAutoConfig.js @@ -50,7 +50,7 @@ const nsISupports = Components.interfaces.nsISupports; const nsIProxyAutoConfig = Components.interfaces.nsIProxyAutoConfig; -const nsIDNSService = Components.interfaces.nsIDNSService; +const nsPIDNSService = Components.interfaces.nsPIDNSService; // implementor of nsIProxyAutoConfig function nsProxyAutoConfig() {}; @@ -114,7 +114,7 @@ // wrapper for getting local IP address called by PAC file function myIpAddress() { try { - return dns.resolve(dns.myHostName, 0).getNextAddrAsString(); + return dns.getNetworkAddrAsString(); } catch (e) { return '127.0.0.1'; } @@ -176,7 +176,7 @@ } var pac = new nsProxyAutoConfig() ; -var dns = Components.classes[kDNS_CONTRACTID].getService(nsIDNSService); +var dns = Components.classes[kDNS_CONTRACTID].getService(nsPIDNSService); var pacUtils = "function dnsDomainIs(host, domain) {\n" + --- netwerk/dns/public/nsPIDNSService.idl +++ netwerk/dns/public/nsPIDNSService.idl @@ -58,4 +58,11 @@ * this method. */ void shutdown(); + + /** + * Returns the IP address of the machine that is most suitable for + * identifying the machine's network. Favour VPN addresses above + * wired/wireless addresses above 127.x.x.x addresses. + */ + ACString getNetworkAddrAsString(); }; --- netwerk/dns/src/nsDNSService2.cpp +++ netwerk/dns/src/nsDNSService2.cpp @@ -56,6 +56,11 @@ #include "prio.h" #include "plstr.h" +#include +#include +#include +#include + static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries"; static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration"; static const char kPrefEnableIDN[] = "network.enableIDN"; @@ -135,6 +140,18 @@ return NS_OK; } +static nsresult +AddrToString(PRNetAddr* aAddr, nsACString& aResult) +{ + char buf[64]; + if (PR_NetAddrToString(aAddr, buf, sizeof(buf)) == PR_SUCCESS) { + aResult.Assign(buf); + return NS_OK; + } + NS_ERROR("PR_NetAddrToString failed unexpectedly"); + return NS_ERROR_FAILURE; // conversion failed for some reason +} + NS_IMETHODIMP nsDNSRecord::GetNextAddrAsString(nsACString &result) { @@ -142,13 +159,7 @@ nsresult rv = GetNextAddr(0, &addr); if (NS_FAILED(rv)) return rv; - char buf[64]; - if (PR_NetAddrToString(&addr, buf, sizeof(buf)) == PR_SUCCESS) { - result.Assign(buf); - return NS_OK; - } - NS_ERROR("PR_NetAddrToString failed unexpectedly"); - return NS_ERROR_FAILURE; // conversion failed for some reason + return AddrToString(&addr, result); } NS_IMETHODIMP @@ -580,3 +591,68 @@ return af; } + +static PRInt32 +GetScoreForInterface(struct ifaddrs* aInterface) +{ + // Interface must be up + if (!(aInterface->ifa_flags & IFF_UP)) + return 0; + // Interface must be configured + if (!(aInterface->ifa_flags & IFF_RUNNING)) + return 0; + + // Only look at IP interfaces + sa_family_t type = aInterface->ifa_addr->sa_family; + if (type != AF_INET && type != AF_INET6) + return 0; + + // Loopback interfaces get the lowest score + if (aInterface->ifa_flags & IFF_LOOPBACK) + return 1; + + if (strchr(aInterface->ifa_name, ':')) { + // guess that it's probably a VPN address + return 3; + } + + // Regular interface + return 2; +} + +nsresult +SockaddrToString(struct sockaddr* aAddr, nsACString& aResult) +{ + PRNetAddr* addr = NS_REINTERPRET_CAST(PRNetAddr*, aAddr); + return AddrToString(addr, aResult); +} + +NS_IMETHODIMP +nsDNSService::GetNetworkAddrAsString(nsACString& aResult) +{ + aResult.AssignLiteral("127.0.0.1"); + + struct ifaddrs* addrs; + if (getifaddrs(&addrs) < 0) + return NS_OK; + + struct ifaddrs* bestAddr = nsnull; + PRInt32 bestScore = 0; + struct ifaddrs* addr; + for (addr = addrs; addr; addr = addr->ifa_next) { + PRInt32 score = GetScoreForInterface(addr); + if (score > 0 && (!bestAddr || score > bestScore)) { + bestAddr = addr; + bestScore = score; + } + } + + if (!bestAddr) { + freeifaddrs(addrs); + return NS_OK; + } + + nsresult rv = SockaddrToString(bestAddr->ifa_addr, aResult); + freeifaddrs(addrs); + return rv; +}