Index: mozilla/netwerk/dns/src/nsDNSService2.cpp =================================================================== RCS file: /cvsroot/mozilla/netwerk/dns/src/nsDNSService2.cpp,v retrieving revision 1.4 diff -u -r1.4 nsDNSService2.cpp --- mozilla/netwerk/dns/src/nsDNSService2.cpp 28 Jan 2004 23:45:16 -0000 1.4 +++ mozilla/netwerk/dns/src/nsDNSService2.cpp 23 Feb 2004 22:46:06 -0000 @@ -50,10 +50,13 @@ #include "prnetdb.h" #include "prmon.h" #include "prio.h" +#include "plstr.h" static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries"; static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration"; static const char kPrefEnableIDN[] = "network.enableIDN"; +static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains"; +static const char kPrefDisableIPv6[] = "network.dns.disableIPv6"; //----------------------------------------------------------------------------- @@ -258,14 +261,21 @@ //----------------------------------------------------------------------------- nsDNSService::nsDNSService() - : mLock(nsnull) + : mLock(nsnull), mIPv4OnlyDomains(nsnull) { } nsDNSService::~nsDNSService() { - if (mLock) + if (mLock) { + if(mIPv4OnlyDomains) { + nsAutoLock lock(mLock); + PL_strfree(mIPv4OnlyDomains); + mIPv4OnlyDomains = nsnull; + } + PR_DestroyLock(mLock); + } } NS_IMPL_THREADSAFE_ISUPPORTS2(nsDNSService, nsIDNSService, nsIObserver) @@ -281,6 +291,7 @@ PRUint32 maxCacheEntries = 20; PRUint32 maxCacheLifetime = 1; // minutes PRBool enableIDN = PR_TRUE; + char *IPv4OnlyDomains = nsnull; // read prefs nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); @@ -292,6 +303,9 @@ maxCacheLifetime = (val / 60); // convert from seconds to minutes if (NS_SUCCEEDED(prefs->GetBoolPref(kPrefEnableIDN, (PRBool*)&val))) enableIDN = (PRBool) val; + if (NS_SUCCEEDED(prefs->GetBoolPref(kPrefDisableIPv6, (PRBool*)&val))) + mDisableIPv6 = (PRBool) val; + prefs->GetCharPref(kPrefIPv4OnlyDomains, &IPv4OnlyDomains); } // we have to null out mIDN since we might be getting re-initialized @@ -303,13 +317,25 @@ if (firstTime) { mLock = PR_NewLock(); - if (!mLock) + if (!mLock) { + if(IPv4OnlyDomains) + PL_strfree(IPv4OnlyDomains); + return NS_ERROR_OUT_OF_MEMORY; - + } + // register as prefs observer prefs->AddObserver(kPrefDnsCacheEntries, this, PR_FALSE); prefs->AddObserver(kPrefDnsCacheExpiration, this, PR_FALSE); prefs->AddObserver(kPrefEnableIDN, this, PR_FALSE); + prefs->AddObserver(kPrefIPv4OnlyDomains, this, PR_FALSE); + prefs->AddObserver(kPrefDisableIPv6, this, PR_FALSE); + } + + if(IPv4OnlyDomains) { + nsAutoLock lock(mLock); + mIPv4OnlyDomains = PL_strdup(IPv4OnlyDomains); + PL_strfree(IPv4OnlyDomains); } return nsHostResolver::Create(maxCacheEntries, @@ -325,6 +351,11 @@ nsAutoLock lock(mLock); res = mResolver; mResolver = nsnull; + + if (mIPv4OnlyDomains) { + PL_strfree(mIPv4OnlyDomains); + mIPv4OnlyDomains = nsnull; + } } if (res) res->Shutdown(); @@ -374,9 +405,11 @@ return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*result = req); + PRUint16 af = GetAFForLookup(req->mHost.get()); + // addref for resolver; will be released when OnLookupComplete is called. NS_ADDREF(req); - rv = res->ResolveHost(req->mHost.get(), bypassCache, req); + rv = res->ResolveHost(req->mHost.get(), bypassCache, req, af); if (NS_FAILED(rv)) { NS_RELEASE(req); NS_RELEASE(*result); @@ -424,7 +457,9 @@ PR_EnterMonitor(mon); nsDNSSyncRequest syncReq(mon); - rv = res->ResolveHost(PromiseFlatCString(*hostPtr).get(), bypassCache, &syncReq); + PRUint16 af = GetAFForLookup(PromiseFlatCString(*hostPtr).get()); + + rv = res->ResolveHost(PromiseFlatCString(*hostPtr).get(), bypassCache, &syncReq, af); if (NS_SUCCEEDED(rv)) { // wait for result while (!syncReq.mDone) @@ -479,4 +514,44 @@ Init(); } return NS_OK; +} + +PRUint16 +nsDNSService::GetAFForLookup(const char *host) +{ + PRUint16 af = PR_AF_UNSPEC; + + if(mDisableIPv6) { + return PR_AF_INET; + } else { + nsAutoLock lock(mLock); + + if(mIPv4OnlyDomains && *mIPv4OnlyDomains) { + char *domain, *end; + PRUint32 hostlen, domainlen; + + // see if host is in one of the IPv4-only domains + domain = mIPv4OnlyDomains; + hostlen = strlen(host); + do { + // Find end of this domain in the string + end = PL_strchr(domain, ','); + if(! end) + end = PL_strchr(domain, '\0'); + + // To see if the host is in the domain, see if the domain matches + // the end of the hostname. (Note that we don't check for dots.) + domainlen = end - domain; + if(domainlen && + ! PL_strncasecmp(domain, host + hostlen - domainlen, domainlen)) { + af = PR_AF_INET; + break; + } + + domain = end + 1; + } while(*end); + } + } + + return af; } Index: mozilla/netwerk/dns/src/nsDNSService2.h =================================================================== RCS file: /cvsroot/mozilla/netwerk/dns/src/nsDNSService2.h,v retrieving revision 1.1 diff -u -r1.1 nsDNSService2.h --- mozilla/netwerk/dns/src/nsDNSService2.h 11 Sep 2003 20:32:33 -0000 1.1 +++ mozilla/netwerk/dns/src/nsDNSService2.h 23 Feb 2004 22:46:06 -0000 @@ -57,5 +57,12 @@ nsCOMPtr mIDN; PRLock *mLock; - // mLock protects access to mResolver + // mLock protects access to mResolver and mIPv4OnlyDomains + + // mIPv4OnlyDomains is a comma-separated list of domains for which only + // IPv4 DNS lookups are performed. This allows the user to disable IPv6 on + // a per-domain basis and work around broken DNS servers. See bug 68796. + char *mIPv4OnlyDomains; + PRBool mDisableIPv6; + PRUint16 GetAFForLookup(const char *host); }; Index: mozilla/netwerk/dns/src/nsHostResolver.cpp =================================================================== RCS file: /cvsroot/mozilla/netwerk/dns/src/nsHostResolver.cpp,v retrieving revision 1.6 diff -u -r1.6 nsHostResolver.cpp --- mozilla/netwerk/dns/src/nsHostResolver.cpp 3 Nov 2003 09:10:57 -0000 1.6 +++ mozilla/netwerk/dns/src/nsHostResolver.cpp 23 Feb 2004 22:46:07 -0000 @@ -351,7 +351,8 @@ nsresult nsHostResolver::ResolveHost(const char *host, PRBool bypassCache, - nsResolveHostCallback *callback) + nsResolveHostCallback *callback, + PRUint16 af = PR_AF_UNSPEC) { NS_ENSURE_TRUE(host && *host, NS_ERROR_UNEXPECTED); @@ -414,6 +415,7 @@ PR_APPEND_LINK(callback, &he->rec->callbacks); if (!he->rec->resolving) { + he->rec->af = af; rv = IssueLookup(he->rec); if (NS_FAILED(rv)) PR_REMOVE_AND_INIT_LINK(callback); @@ -603,10 +605,10 @@ PRAddrInfo *ai; while (resolver->GetHostToLookup(&rec)) { LOG(("resolving %s ...\n", rec->host)); - ai = PR_GetAddrInfoByName(rec->host, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + ai = PR_GetAddrInfoByName(rec->host, rec->af, PR_AI_ADDRCONFIG); #if defined(RES_RETRY_ON_FAILURE) if (!ai && rs.Reset()) - ai = PR_GetAddrInfoByName(rec->host, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + ai = PR_GetAddrInfoByName(rec->host, rec->af, PR_AI_ADDRCONFIG); #endif // convert error code to nsresult. nsresult status = ai ? NS_OK : NS_ERROR_UNKNOWN_HOST; Index: mozilla/netwerk/dns/src/nsHostResolver.h =================================================================== RCS file: /cvsroot/mozilla/netwerk/dns/src/nsHostResolver.h,v retrieving revision 1.3 diff -u -r1.3 nsHostResolver.h --- mozilla/netwerk/dns/src/nsHostResolver.h 25 Oct 2003 23:48:33 -0000 1.3 +++ mozilla/netwerk/dns/src/nsHostResolver.h 23 Feb 2004 22:46:07 -0000 @@ -81,10 +81,12 @@ * otherwise, if |addrinfo| is non-null, then it contains one or many * IP addresses corresponding to the given host name. if both |addrinfo| * and |addr| are null, then the given host has not yet been fully resolved. + * |af| is the address family of the record we are querying for. */ char *host; PRAddrInfo *addrinfo; PRNetAddr *addr; + PRUint16 af; PRUint32 expiration; /* measured in minutes since epoch */ PRBool HasResult() const { return (addrinfo || addr) != nsnull; } @@ -163,7 +165,8 @@ */ nsresult ResolveHost(const char *hostname, PRBool bypassCache, - nsResolveHostCallback *callback); + nsResolveHostCallback *callback, + PRUint16 af); /** * removes the specified callback from the nsHostRecord for the given Index: mozilla/modules/libpref/src/init/all.js =================================================================== RCS file: /cvsroot/mozilla/modules/libpref/src/init/all.js,v retrieving revision 3.496 diff -u -r3.496 all.js --- mozilla/modules/libpref/src/init/all.js 11 Feb 2004 22:22:05 -0000 3.496 +++ mozilla/modules/libpref/src/init/all.js 23 Feb 2004 22:46:22 -0000 @@ -544,6 +544,14 @@ // are handled. IDN requires a nsIIDNService implementation. pref("network.enableIDN", true); +// This preference specifies a list of domains for which DNS lookups will be +// IPv4 only. Works around broken DNS servers which can't handle IPv6 lookups +// and/or allows the user to disable IPv6 on a per-domain basis. See bug 68796. +pref("network.dns.ipv4OnlyDomains", ".doubleclick.net"); + +// This preference can be used to turn off IPv6 name lookups. See bug 68796. +pref("network.dns.disableIPv6, false); + // This preference controls whether or not URLs with UTF-8 characters are // escaped. Set this preference to TRUE for strict RFC2396 conformance. pref("network.standard-url.escape-utf8", true);