Subject: proxy.pac: host resolution error
From: Robert O'Callahan <[email-masked]>

diff --git a/netwerk/base/src/nsProxyAutoConfig.js b/netwerk/base/src/nsProxyAutoConfig.js
index 6a34044..2186502 100644
--- a/netwerk/base/src/nsProxyAutoConfig.js
+++ b/netwerk/base/src/nsProxyAutoConfig.js
@@ -50,7 +50,7 @@ const kPAC_CID = Components.ID("{63ac8c66-1dd2-11b2-b070-84d00d3eaece}");
 
 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 @@ function proxyAlert(msg) {
 // 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 @@ function NSGetModule(compMgr, fileSpec) {
 }
 
 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" +
diff --git a/netwerk/dns/public/nsPIDNSService.idl b/netwerk/dns/public/nsPIDNSService.idl
index e0eea6d..1abb223 100644
--- a/netwerk/dns/public/nsPIDNSService.idl
+++ b/netwerk/dns/public/nsPIDNSService.idl
@@ -58,4 +58,11 @@ interface nsPIDNSService : nsIDNSService
      * 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();
 };
diff --git a/netwerk/dns/src/nsDNSService2.cpp b/netwerk/dns/src/nsDNSService2.cpp
index f38e0c1..e928a76 100644
--- a/netwerk/dns/src/nsDNSService2.cpp
+++ b/netwerk/dns/src/nsDNSService2.cpp
@@ -56,6 +56,11 @@
 #include "prio.h"
 #include "plstr.h"
 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+
 static const char kPrefDnsCacheEntries[]    = "network.dnsCacheEntries";
 static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
 static const char kPrefEnableIDN[]          = "network.enableIDN";
@@ -135,6 +140,18 @@ nsDNSRecord::GetNextAddr(PRUint16 port, PRNetAddr *addr)
     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 @@ nsDNSRecord::GetNextAddrAsString(nsACString &result)
     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,76 @@ nsDNSService::GetAFForLookup(const nsACString &host)
 
     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;
+    
+    // Interface must have an address
+    if (aInterface->ifa_addr == NULL)
+        return 0;
+    
+    // Interface must have an address
+    if (aInterface->ifa_addr == NULL)
+	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;
+}