From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- netwerk/dns/ChildDNSService.cpp | 330 + netwerk/dns/ChildDNSService.h | 60 + netwerk/dns/DNS.cpp | 368 + netwerk/dns/DNS.h | 183 + netwerk/dns/DNSListenerProxy.cpp | 43 + netwerk/dns/DNSListenerProxy.h | 72 + netwerk/dns/DNSRequestChild.cpp | 313 + netwerk/dns/DNSRequestChild.h | 61 + netwerk/dns/DNSRequestParent.cpp | 132 + netwerk/dns/DNSRequestParent.h | 50 + netwerk/dns/GetAddrInfo.cpp | 369 + netwerk/dns/GetAddrInfo.h | 67 + netwerk/dns/PDNSParams.h | 23 + netwerk/dns/PDNSRequest.ipdl | 36 + netwerk/dns/PDNSRequestParams.ipdlh | 31 + netwerk/dns/effective_tld_names.dat | 10834 +++++++++++++++++++ netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp | 779 ++ netwerk/dns/mdns/libmdns/MDNSResponderOperator.h | 152 + netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp | 302 + netwerk/dns/mdns/libmdns/MDNSResponderReply.h | 164 + netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm | 244 + netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm | 297 + netwerk/dns/mdns/libmdns/fallback/DNSRecord.jsm | 70 + .../mdns/libmdns/fallback/DNSResourceRecord.jsm | 221 + netwerk/dns/mdns/libmdns/fallback/DNSTypes.jsm | 100 + netwerk/dns/mdns/libmdns/fallback/DataReader.jsm | 133 + netwerk/dns/mdns/libmdns/fallback/DataWriter.jsm | 98 + netwerk/dns/mdns/libmdns/fallback/MulticastDNS.jsm | 875 ++ netwerk/dns/mdns/libmdns/moz.build | 56 + netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp | 285 + netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h | 48 + netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js | 201 + .../mdns/libmdns/nsDNSServiceDiscovery.manifest | 3 + netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp | 209 + netwerk/dns/mdns/libmdns/nsDNSServiceInfo.h | 50 + netwerk/dns/mdns/libmdns/nsMulticastDNSModule.cpp | 61 + netwerk/dns/mdns/moz.build | 13 + netwerk/dns/mdns/nsIDNSServiceDiscovery.idl | 219 + netwerk/dns/moz.build | 78 + netwerk/dns/nameprep.c | 347 + netwerk/dns/nameprep_template.c | 139 + netwerk/dns/nameprepdata.c | 2588 +++++ netwerk/dns/nsDNSService2.cpp | 1071 ++ netwerk/dns/nsDNSService2.h | 72 + netwerk/dns/nsEffectiveTLDService.cpp | 368 + netwerk/dns/nsEffectiveTLDService.h | 98 + netwerk/dns/nsHostResolver.cpp | 1579 +++ netwerk/dns/nsHostResolver.h | 372 + netwerk/dns/nsIDNKitInterface.h | 195 + netwerk/dns/nsIDNSListener.idl | 46 + netwerk/dns/nsIDNSRecord.idl | 100 + netwerk/dns/nsIDNSService.idl | 171 + netwerk/dns/nsIDNService.cpp | 959 ++ netwerk/dns/nsIDNService.h | 195 + netwerk/dns/nsIEffectiveTLDService.idl | 125 + netwerk/dns/nsIIDNService.idl | 58 + netwerk/dns/nsPIDNSService.idl | 34 + netwerk/dns/prepare_tlds.py | 121 + netwerk/dns/punycode.c | 289 + netwerk/dns/punycode.h | 108 + 60 files changed, 26665 insertions(+) create mode 100644 netwerk/dns/ChildDNSService.cpp create mode 100644 netwerk/dns/ChildDNSService.h create mode 100644 netwerk/dns/DNS.cpp create mode 100644 netwerk/dns/DNS.h create mode 100644 netwerk/dns/DNSListenerProxy.cpp create mode 100644 netwerk/dns/DNSListenerProxy.h create mode 100644 netwerk/dns/DNSRequestChild.cpp create mode 100644 netwerk/dns/DNSRequestChild.h create mode 100644 netwerk/dns/DNSRequestParent.cpp create mode 100644 netwerk/dns/DNSRequestParent.h create mode 100644 netwerk/dns/GetAddrInfo.cpp create mode 100644 netwerk/dns/GetAddrInfo.h create mode 100644 netwerk/dns/PDNSParams.h create mode 100644 netwerk/dns/PDNSRequest.ipdl create mode 100644 netwerk/dns/PDNSRequestParams.ipdlh create mode 100644 netwerk/dns/effective_tld_names.dat create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderOperator.h create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderReply.h create mode 100644 netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/DNSRecord.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/DNSResourceRecord.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/DNSTypes.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/DataReader.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/DataWriter.jsm create mode 100644 netwerk/dns/mdns/libmdns/fallback/MulticastDNS.jsm create mode 100644 netwerk/dns/mdns/libmdns/moz.build create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.manifest create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceInfo.h create mode 100644 netwerk/dns/mdns/libmdns/nsMulticastDNSModule.cpp create mode 100644 netwerk/dns/mdns/moz.build create mode 100644 netwerk/dns/mdns/nsIDNSServiceDiscovery.idl create mode 100644 netwerk/dns/moz.build create mode 100644 netwerk/dns/nameprep.c create mode 100644 netwerk/dns/nameprep_template.c create mode 100644 netwerk/dns/nameprepdata.c create mode 100644 netwerk/dns/nsDNSService2.cpp create mode 100644 netwerk/dns/nsDNSService2.h create mode 100644 netwerk/dns/nsEffectiveTLDService.cpp create mode 100644 netwerk/dns/nsEffectiveTLDService.h create mode 100644 netwerk/dns/nsHostResolver.cpp create mode 100644 netwerk/dns/nsHostResolver.h create mode 100644 netwerk/dns/nsIDNKitInterface.h create mode 100644 netwerk/dns/nsIDNSListener.idl create mode 100644 netwerk/dns/nsIDNSRecord.idl create mode 100644 netwerk/dns/nsIDNSService.idl create mode 100644 netwerk/dns/nsIDNService.cpp create mode 100644 netwerk/dns/nsIDNService.h create mode 100644 netwerk/dns/nsIEffectiveTLDService.idl create mode 100644 netwerk/dns/nsIIDNService.idl create mode 100644 netwerk/dns/nsPIDNSService.idl create mode 100644 netwerk/dns/prepare_tlds.py create mode 100644 netwerk/dns/punycode.c create mode 100644 netwerk/dns/punycode.h (limited to 'netwerk/dns') diff --git a/netwerk/dns/ChildDNSService.cpp b/netwerk/dns/ChildDNSService.cpp new file mode 100644 index 000000000..a3a1f3347 --- /dev/null +++ b/netwerk/dns/ChildDNSService.cpp @@ -0,0 +1,330 @@ +/* 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/. */ + +#include "mozilla/net/ChildDNSService.h" +#include "nsIDNSListener.h" +#include "nsIIOService.h" +#include "nsIThread.h" +#include "nsThreadUtils.h" +#include "nsIXPConnect.h" +#include "nsIPrefService.h" +#include "nsIProtocolProxyService.h" +#include "nsNetCID.h" +#include "mozilla/net/NeckoChild.h" +#include "mozilla/net/DNSListenerProxy.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { +namespace net { + +//----------------------------------------------------------------------------- +// ChildDNSService +//----------------------------------------------------------------------------- + +static ChildDNSService *gChildDNSService; +static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch"; + +ChildDNSService* ChildDNSService::GetSingleton() +{ + MOZ_ASSERT(IsNeckoChild()); + + if (!gChildDNSService) { + gChildDNSService = new ChildDNSService(); + } + + NS_ADDREF(gChildDNSService); + return gChildDNSService; +} + +NS_IMPL_ISUPPORTS(ChildDNSService, + nsIDNSService, + nsPIDNSService, + nsIObserver) + +ChildDNSService::ChildDNSService() + : mFirstTime(true) + , mDisablePrefetch(false) + , mPendingRequestsLock("DNSPendingRequestsLock") +{ + MOZ_ASSERT(IsNeckoChild()); +} + +ChildDNSService::~ChildDNSService() +{ + +} + +void +ChildDNSService::GetDNSRecordHashKey(const nsACString &aHost, + uint32_t aFlags, + const nsACString &aNetworkInterface, + nsIDNSListener* aListener, + nsACString &aHashKey) +{ + aHashKey.Assign(aHost); + aHashKey.AppendInt(aFlags); + if (!aNetworkInterface.IsEmpty()) { + aHashKey.Append(aNetworkInterface); + } + aHashKey.AppendPrintf("%p", aListener); +} + +//----------------------------------------------------------------------------- +// ChildDNSService::nsIDNSService +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ChildDNSService::AsyncResolve(const nsACString &hostname, + uint32_t flags, + nsIDNSListener *listener, + nsIEventTarget *target_, + nsICancelable **result) +{ + return AsyncResolveExtended(hostname, flags, EmptyCString(), listener, + target_, result); +} + +NS_IMETHODIMP +ChildDNSService::AsyncResolveExtended(const nsACString &hostname, + uint32_t flags, + const nsACString &aNetworkInterface, + nsIDNSListener *listener, + nsIEventTarget *target_, + nsICancelable **result) +{ + NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE); + + if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) { + return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + } + + // We need original flags for the pending requests hash. + uint32_t originalFlags = flags; + + // Support apps being 'offline' even if parent is not: avoids DNS traffic by + // apps that have been told they are offline. + if (GetOffline()) { + flags |= RESOLVE_OFFLINE; + } + + // We need original listener for the pending requests hash. + nsIDNSListener *originalListener = listener; + + // make sure JS callers get notification on the main thread + nsCOMPtr target = target_; + nsCOMPtr wrappedListener = do_QueryInterface(listener); + if (wrappedListener && !target) { + nsCOMPtr mainThread; + NS_GetMainThread(getter_AddRefs(mainThread)); + target = do_QueryInterface(mainThread); + } + if (target) { + // Guarantee listener freed on main thread. Not sure we need this in child + // (or in parent in nsDNSService.cpp) but doesn't hurt. + listener = new DNSListenerProxy(listener, target); + } + + RefPtr childReq = + new DNSRequestChild(nsCString(hostname), flags, + nsCString(aNetworkInterface), + listener, target); + + { + MutexAutoLock lock(mPendingRequestsLock); + nsCString key; + GetDNSRecordHashKey(hostname, originalFlags, aNetworkInterface, + originalListener, key); + nsTArray> *hashEntry; + if (mPendingRequests.Get(key, &hashEntry)) { + hashEntry->AppendElement(childReq); + } else { + hashEntry = new nsTArray>(); + hashEntry->AppendElement(childReq); + mPendingRequests.Put(key, hashEntry); + } + } + + childReq->StartRequest(); + + childReq.forget(result); + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::CancelAsyncResolve(const nsACString &aHostname, + uint32_t aFlags, + nsIDNSListener *aListener, + nsresult aReason) +{ + return CancelAsyncResolveExtended(aHostname, aFlags, EmptyCString(), + aListener, aReason); +} + +NS_IMETHODIMP +ChildDNSService::CancelAsyncResolveExtended(const nsACString &aHostname, + uint32_t aFlags, + const nsACString &aNetworkInterface, + nsIDNSListener *aListener, + nsresult aReason) +{ + if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) { + return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + } + + MutexAutoLock lock(mPendingRequestsLock); + nsTArray> *hashEntry; + nsCString key; + GetDNSRecordHashKey(aHostname, aFlags, aNetworkInterface, aListener, key); + if (mPendingRequests.Get(key, &hashEntry)) { + // We cancel just one. + hashEntry->ElementAt(0)->Cancel(aReason); + } + + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::Resolve(const nsACString &hostname, + uint32_t flags, + nsIDNSRecord **result) +{ + // not planning to ever support this, since sync IPDL is evil. + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +ChildDNSService::GetDNSCacheEntries(nsTArray *args) +{ + // Only used by networking dashboard, so may not ever need this in child. + // (and would provide a way to spy on what hosts other apps are connecting to, + // unless we start keeping per-app DNS caches). + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +ChildDNSService::GetMyHostName(nsACString &result) +{ + // TODO: get value from parent during PNecko construction? + return NS_ERROR_NOT_AVAILABLE; +} + +void +ChildDNSService::NotifyRequestDone(DNSRequestChild *aDnsRequest) +{ + // We need the original flags and listener for the pending requests hash. + uint32_t originalFlags = aDnsRequest->mFlags & ~RESOLVE_OFFLINE; + nsCOMPtr originalListener = aDnsRequest->mListener; + nsCOMPtr wrapper = do_QueryInterface(originalListener); + if (wrapper) { + wrapper->GetOriginalListener(getter_AddRefs(originalListener)); + if (NS_WARN_IF(!originalListener)) { + MOZ_ASSERT(originalListener); + return; + } + } + + MutexAutoLock lock(mPendingRequestsLock); + + nsCString key; + GetDNSRecordHashKey(aDnsRequest->mHost, originalFlags, + aDnsRequest->mNetworkInterface, originalListener, key); + + nsTArray> *hashEntry; + + if (mPendingRequests.Get(key, &hashEntry)) { + int idx; + if ((idx = hashEntry->IndexOf(aDnsRequest))) { + hashEntry->RemoveElementAt(idx); + if (hashEntry->IsEmpty()) { + mPendingRequests.Remove(key); + } + } + } +} + +//----------------------------------------------------------------------------- +// ChildDNSService::nsPIDNSService +//----------------------------------------------------------------------------- + +nsresult +ChildDNSService::Init() +{ + // Disable prefetching either by explicit preference or if a manual proxy + // is configured + bool disablePrefetch = false; + int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT; + + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + prefs->GetIntPref("network.proxy.type", &proxyType); + prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch); + } + + if (mFirstTime) { + mFirstTime = false; + if (prefs) { + prefs->AddObserver(kPrefNameDisablePrefetch, this, false); + + // Monitor these to see if there is a change in proxy configuration + // If a manual proxy is in use, disable prefetch implicitly + prefs->AddObserver("network.proxy.type", this, false); + } + } + + mDisablePrefetch = disablePrefetch || + (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL); + + return NS_OK; +} + +nsresult +ChildDNSService::Shutdown() +{ + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::GetPrefetchEnabled(bool *outVal) +{ + *outVal = !mDisablePrefetch; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::SetPrefetchEnabled(bool inVal) +{ + mDisablePrefetch = !inVal; + return NS_OK; +} + +bool +ChildDNSService::GetOffline() const +{ + bool offline = false; + nsCOMPtr io = do_GetService(NS_IOSERVICE_CONTRACTID); + if (io) { + io->GetOffline(&offline); + } + return offline; +} + +//----------------------------------------------------------------------------- +// ChildDNSService::nsIObserver +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ChildDNSService::Observe(nsISupports *subject, const char *topic, + const char16_t *data) +{ + // we are only getting called if a preference has changed. + NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, + "unexpected observe call"); + + // Reread prefs + Init(); + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/ChildDNSService.h b/netwerk/dns/ChildDNSService.h new file mode 100644 index 000000000..1662960bb --- /dev/null +++ b/netwerk/dns/ChildDNSService.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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 mozilla_net_ChildDNSService_h +#define mozilla_net_ChildDNSService_h + + +#include "nsPIDNSService.h" +#include "nsIObserver.h" +#include "mozilla/Attributes.h" +#include "mozilla/Mutex.h" +#include "DNSRequestChild.h" +#include "nsHashKeys.h" +#include "nsClassHashtable.h" + +namespace mozilla { +namespace net { + +class ChildDNSService final + : public nsPIDNSService + , public nsIObserver +{ +public: + // AsyncResolve (and CancelAsyncResolve) can be called off-main + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSPIDNSSERVICE + NS_DECL_NSIDNSSERVICE + NS_DECL_NSIOBSERVER + + ChildDNSService(); + + static ChildDNSService* GetSingleton(); + + void NotifyRequestDone(DNSRequestChild *aDnsRequest); + + bool GetOffline() const; +private: + virtual ~ChildDNSService(); + + void MOZ_ALWAYS_INLINE GetDNSRecordHashKey(const nsACString &aHost, + uint32_t aFlags, + const nsACString &aNetworkInterface, + nsIDNSListener* aListener, + nsACString &aHashKey); + + bool mFirstTime; + bool mDisablePrefetch; + + // We need to remember pending dns requests to be able to cancel them. + nsClassHashtable>> mPendingRequests; + Mutex mPendingRequestsLock; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_ChildDNSService_h diff --git a/netwerk/dns/DNS.cpp b/netwerk/dns/DNS.cpp new file mode 100644 index 000000000..643296af0 --- /dev/null +++ b/netwerk/dns/DNS.cpp @@ -0,0 +1,368 @@ +/* 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/. */ + +#include "mozilla/net/DNS.h" + +#include "mozilla/Assertions.h" +#include "mozilla/mozalloc.h" +#include "mozilla/ArrayUtils.h" +#include + +#ifdef XP_WIN +#include "ws2tcpip.h" +#endif + +namespace mozilla { +namespace net { + +const char *inet_ntop_internal(int af, const void *src, char *dst, socklen_t size) +{ +#ifdef XP_WIN + if (af == AF_INET) { + struct sockaddr_in s; + memset(&s, 0, sizeof(s)); + s.sin_family = AF_INET; + memcpy(&s.sin_addr, src, sizeof(struct in_addr)); + int result = getnameinfo((struct sockaddr *)&s, sizeof(struct sockaddr_in), + dst, size, nullptr, 0, NI_NUMERICHOST); + if (result == 0) { + return dst; + } + } + else if (af == AF_INET6) { + struct sockaddr_in6 s; + memset(&s, 0, sizeof(s)); + s.sin6_family = AF_INET6; + memcpy(&s.sin6_addr, src, sizeof(struct in_addr6)); + int result = getnameinfo((struct sockaddr *)&s, sizeof(struct sockaddr_in6), + dst, size, nullptr, 0, NI_NUMERICHOST); + if (result == 0) { + return dst; + } + } + return nullptr; +#else + return inet_ntop(af, src, dst, size); +#endif +} + +// Copies the contents of a PRNetAddr to a NetAddr. +// Does not do a ptr safety check! +void PRNetAddrToNetAddr(const PRNetAddr *prAddr, NetAddr *addr) +{ + if (prAddr->raw.family == PR_AF_INET) { + addr->inet.family = AF_INET; + addr->inet.port = prAddr->inet.port; + addr->inet.ip = prAddr->inet.ip; + } + else if (prAddr->raw.family == PR_AF_INET6) { + addr->inet6.family = AF_INET6; + addr->inet6.port = prAddr->ipv6.port; + addr->inet6.flowinfo = prAddr->ipv6.flowinfo; + memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8)); + addr->inet6.scope_id = prAddr->ipv6.scope_id; + } +#if defined(XP_UNIX) + else if (prAddr->raw.family == PR_AF_LOCAL) { + addr->local.family = AF_LOCAL; + memcpy(addr->local.path, prAddr->local.path, sizeof(addr->local.path)); + } +#endif +} + +// Copies the contents of a NetAddr to a PRNetAddr. +// Does not do a ptr safety check! +void NetAddrToPRNetAddr(const NetAddr *addr, PRNetAddr *prAddr) +{ + if (addr->raw.family == AF_INET) { + prAddr->inet.family = PR_AF_INET; + prAddr->inet.port = addr->inet.port; + prAddr->inet.ip = addr->inet.ip; + } + else if (addr->raw.family == AF_INET6) { + prAddr->ipv6.family = PR_AF_INET6; + prAddr->ipv6.port = addr->inet6.port; + prAddr->ipv6.flowinfo = addr->inet6.flowinfo; + memcpy(&prAddr->ipv6.ip, &addr->inet6.ip, sizeof(addr->inet6.ip.u8)); + prAddr->ipv6.scope_id = addr->inet6.scope_id; + } +#if defined(XP_UNIX) + else if (addr->raw.family == AF_LOCAL) { + prAddr->local.family = PR_AF_LOCAL; + memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path)); + } +#elif defined(XP_WIN) + else if (addr->raw.family == AF_LOCAL) { + prAddr->local.family = PR_AF_LOCAL; + memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path)); + } +#endif +} + +bool NetAddrToString(const NetAddr *addr, char *buf, uint32_t bufSize) +{ + if (addr->raw.family == AF_INET) { + if (bufSize < INET_ADDRSTRLEN) { + return false; + } + struct in_addr nativeAddr = {}; + nativeAddr.s_addr = addr->inet.ip; + return !!inet_ntop_internal(AF_INET, &nativeAddr, buf, bufSize); + } + else if (addr->raw.family == AF_INET6) { + if (bufSize < INET6_ADDRSTRLEN) { + return false; + } + struct in6_addr nativeAddr = {}; + memcpy(&nativeAddr.s6_addr, &addr->inet6.ip, sizeof(addr->inet6.ip.u8)); + return !!inet_ntop_internal(AF_INET6, &nativeAddr, buf, bufSize); + } +#if defined(XP_UNIX) + else if (addr->raw.family == AF_LOCAL) { + if (bufSize < sizeof(addr->local.path)) { + // Many callers don't bother checking our return value, so + // null-terminate just in case. + if (bufSize > 0) { + buf[0] = '\0'; + } + return false; + } + + // Usually, the size passed to memcpy should be the size of the + // destination. Here, we know that the source is no larger than the + // destination, so using the source's size is always safe, whereas + // using the destination's size may cause us to read off the end of the + // source. + memcpy(buf, addr->local.path, sizeof(addr->local.path)); + return true; + } +#endif + return false; +} + +bool IsLoopBackAddress(const NetAddr *addr) +{ + if (addr->raw.family == AF_INET) { + return (addr->inet.ip == htonl(INADDR_LOOPBACK)); + } + else if (addr->raw.family == AF_INET6) { + if (IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip)) { + return true; + } else if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) && + IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_LOOPBACK)) { + return true; + } + } + return false; +} + +bool IsIPAddrAny(const NetAddr *addr) +{ + if (addr->raw.family == AF_INET) { + if (addr->inet.ip == htonl(INADDR_ANY)) { + return true; + } + } + else if (addr->raw.family == AF_INET6) { + if (IPv6ADDR_IS_UNSPECIFIED(&addr->inet6.ip)) { + return true; + } else if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) && + IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_ANY)) { + return true; + } + } + return false; +} + +bool IsIPAddrV4Mapped(const NetAddr *addr) +{ + if (addr->raw.family == AF_INET6) { + return IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip); + } + return false; +} + +bool IsIPAddrLocal(const NetAddr *addr) +{ + MOZ_ASSERT(addr); + + // IPv4 RFC1918 and Link Local Addresses. + if (addr->raw.family == AF_INET) { + uint32_t addr32 = ntohl(addr->inet.ip); + if (addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918). + addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918). + addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918). + addr32 >> 16 == 0xA9FE) { // 169.254/16 prefix (Link Local). + return true; + } + } + // IPv6 Unique and Link Local Addresses. + if (addr->raw.family == AF_INET6) { + uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]); + if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address. + addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address. + return true; + } + } + // Not an IPv4/6 local address. + return false; +} + +nsresult +GetPort(const NetAddr *aAddr, uint16_t *aResult) +{ + uint16_t port; + if (aAddr->raw.family == PR_AF_INET) { + port = aAddr->inet.port; + } else if (aAddr->raw.family == PR_AF_INET6) { + port = aAddr->inet6.port; + } else { + return NS_ERROR_NOT_INITIALIZED; + } + + *aResult = ntohs(port); + return NS_OK; +} + +bool +NetAddr::operator == (const NetAddr& other) const +{ + if (this->raw.family != other.raw.family) { + return false; + } else if (this->raw.family == AF_INET) { + return (this->inet.port == other.inet.port) && + (this->inet.ip == other.inet.ip); + } else if (this->raw.family == AF_INET6) { + return (this->inet6.port == other.inet6.port) && + (this->inet6.flowinfo == other.inet6.flowinfo) && + (memcmp(&this->inet6.ip, &other.inet6.ip, + sizeof(this->inet6.ip)) == 0) && + (this->inet6.scope_id == other.inet6.scope_id); +#if defined(XP_UNIX) + } else if (this->raw.family == AF_LOCAL) { + return PL_strncmp(this->local.path, other.local.path, + ArrayLength(this->local.path)); +#endif + } + return false; +} + +bool +NetAddr::operator < (const NetAddr& other) const +{ + if (this->raw.family != other.raw.family) { + return this->raw.family < other.raw.family; + } else if (this->raw.family == AF_INET) { + if (this->inet.ip == other.inet.ip) { + return this->inet.port < other.inet.port; + } else { + return this->inet.ip < other.inet.ip; + } + } else if (this->raw.family == AF_INET6) { + int cmpResult = memcmp(&this->inet6.ip, &other.inet6.ip, + sizeof(this->inet6.ip)); + if (cmpResult) { + return cmpResult < 0; + } else if (this->inet6.port != other.inet6.port) { + return this->inet6.port < other.inet6.port; + } else { + return this->inet6.flowinfo < other.inet6.flowinfo; + } + } + return false; +} + +NetAddrElement::NetAddrElement(const PRNetAddr *prNetAddr) +{ + PRNetAddrToNetAddr(prNetAddr, &mAddress); +} + +NetAddrElement::NetAddrElement(const NetAddrElement& netAddr) +{ + mAddress = netAddr.mAddress; +} + +NetAddrElement::~NetAddrElement() = default; + +AddrInfo::AddrInfo(const char *host, const PRAddrInfo *prAddrInfo, + bool disableIPv4, bool filterNameCollision, const char *cname) + : mHostName(nullptr) + , mCanonicalName(nullptr) + , ttl(NO_TTL_DATA) +{ + MOZ_ASSERT(prAddrInfo, "Cannot construct AddrInfo with a null prAddrInfo pointer!"); + const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53 + + Init(host, cname); + PRNetAddr tmpAddr; + void *iter = nullptr; + do { + iter = PR_EnumerateAddrInfo(iter, prAddrInfo, 0, &tmpAddr); + bool addIt = iter && + (!disableIPv4 || tmpAddr.raw.family != PR_AF_INET) && + (!filterNameCollision || tmpAddr.raw.family != PR_AF_INET || (tmpAddr.inet.ip != nameCollisionAddr)); + if (addIt) { + auto *addrElement = new NetAddrElement(&tmpAddr); + mAddresses.insertBack(addrElement); + } + } while (iter); +} + +AddrInfo::AddrInfo(const char *host, const char *cname) + : mHostName(nullptr) + , mCanonicalName(nullptr) + , ttl(NO_TTL_DATA) +{ + Init(host, cname); +} + +AddrInfo::~AddrInfo() +{ + NetAddrElement *addrElement; + while ((addrElement = mAddresses.popLast())) { + delete addrElement; + } + free(mHostName); + free(mCanonicalName); +} + +void +AddrInfo::Init(const char *host, const char *cname) +{ + MOZ_ASSERT(host, "Cannot initialize AddrInfo with a null host pointer!"); + + ttl = NO_TTL_DATA; + size_t hostlen = strlen(host); + mHostName = static_cast(moz_xmalloc(hostlen + 1)); + memcpy(mHostName, host, hostlen + 1); + if (cname) { + size_t cnameLen = strlen(cname); + mCanonicalName = static_cast(moz_xmalloc(cnameLen + 1)); + memcpy(mCanonicalName, cname, cnameLen + 1); + } + else { + mCanonicalName = nullptr; + } +} + +void +AddrInfo::AddAddress(NetAddrElement *address) +{ + MOZ_ASSERT(address, "Cannot add the address to an uninitialized list"); + + mAddresses.insertBack(address); +} + +size_t +AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const +{ + size_t n = mallocSizeOf(this); + n += mallocSizeOf(mHostName); + n += mallocSizeOf(mCanonicalName); + n += mAddresses.sizeOfExcludingThis(mallocSizeOf); + return n; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/DNS.h b/netwerk/dns/DNS.h new file mode 100644 index 000000000..22e1f31f1 --- /dev/null +++ b/netwerk/dns/DNS.h @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 DNS_h_ +#define DNS_h_ + +#include "nscore.h" +#include "prio.h" +#include "prnetdb.h" +#include "plstr.h" +#include "mozilla/LinkedList.h" +#include "mozilla/MemoryReporting.h" + +#if !defined(XP_WIN) +#include +#endif + +#ifdef XP_WIN +#include "winsock2.h" +#endif + +#ifndef AF_LOCAL +#define AF_LOCAL 1 // used for named pipe +#endif + +#define IPv6ADDR_IS_LOOPBACK(a) \ + (((a)->u32[0] == 0) && \ + ((a)->u32[1] == 0) && \ + ((a)->u32[2] == 0) && \ + ((a)->u8[12] == 0) && \ + ((a)->u8[13] == 0) && \ + ((a)->u8[14] == 0) && \ + ((a)->u8[15] == 0x1U)) + +#define IPv6ADDR_IS_V4MAPPED(a) \ + (((a)->u32[0] == 0) && \ + ((a)->u32[1] == 0) && \ + ((a)->u8[8] == 0) && \ + ((a)->u8[9] == 0) && \ + ((a)->u8[10] == 0xff) && \ + ((a)->u8[11] == 0xff)) + +#define IPv6ADDR_V4MAPPED_TO_IPADDR(a) ((a)->u32[3]) + +#define IPv6ADDR_IS_UNSPECIFIED(a) \ + (((a)->u32[0] == 0) && \ + ((a)->u32[1] == 0) && \ + ((a)->u32[2] == 0) && \ + ((a)->u32[3] == 0)) + +namespace mozilla { +namespace net { + +// Required buffer size for text form of an IP address. +// Includes space for null termination. We make our own contants +// because we don't want higher-level code depending on things +// like INET6_ADDRSTRLEN and having to include the associated +// platform-specific headers. +#ifdef XP_WIN +// Windows requires longer buffers for some reason. +const int kIPv4CStrBufSize = 22; +const int kIPv6CStrBufSize = 65; +const int kNetAddrMaxCStrBufSize = kIPv6CStrBufSize; +#else +const int kIPv4CStrBufSize = 16; +const int kIPv6CStrBufSize = 46; +const int kLocalCStrBufSize = 108; +const int kNetAddrMaxCStrBufSize = kLocalCStrBufSize; +#endif + +// This was all created at a time in which we were using NSPR for host +// resolution and we were propagating NSPR types like "PRAddrInfo" and +// "PRNetAddr" all over Gecko. This made it hard to use another host +// resolver -- we were locked into NSPR. The goal here is to get away +// from that. We'll translate what we get from NSPR or any other host +// resolution library into the types below and use them in Gecko. + +union IPv6Addr { + uint8_t u8[16]; + uint16_t u16[8]; + uint32_t u32[4]; + uint64_t u64[2]; +}; + +// This struct is similar to operating system structs like "sockaddr", used for +// things like "connect" and "getsockname". When tempted to cast or do dumb +// copies of this struct to another struct, bear compiler-computed padding +// in mind. The size of this struct, and the layout of the data in it, may +// not be what you expect. +union NetAddr { + struct { + uint16_t family; /* address family (0x00ff maskable) */ + char data[14]; /* raw address data */ + } raw; + struct { + uint16_t family; /* address family (AF_INET) */ + uint16_t port; /* port number */ + uint32_t ip; /* The actual 32 bits of address */ + } inet; + struct { + uint16_t family; /* address family (AF_INET6) */ + uint16_t port; /* port number */ + uint32_t flowinfo; /* routing information */ + IPv6Addr ip; /* the actual 128 bits of address */ + uint32_t scope_id; /* set of interfaces for a scope */ + } inet6; +#if defined(XP_UNIX) || defined(XP_WIN) + struct { /* Unix domain socket or + Windows Named Pipes address */ + uint16_t family; /* address family (AF_UNIX) */ + char path[104]; /* null-terminated pathname */ + } local; +#endif + // introduced to support nsTArray comparisons and sorting + bool operator == (const NetAddr& other) const; + bool operator < (const NetAddr &other) const; +}; + +// This class wraps a NetAddr union to provide C++ linked list +// capabilities and other methods. It is created from a PRNetAddr, +// which is converted to a mozilla::dns::NetAddr. +class NetAddrElement : public LinkedListElement { +public: + explicit NetAddrElement(const PRNetAddr *prNetAddr); + NetAddrElement(const NetAddrElement& netAddr); + ~NetAddrElement(); + + NetAddr mAddress; +}; + +class AddrInfo { +public: + // Creates an AddrInfo object. It calls the AddrInfo(const char*, const char*) + // to initialize the host and the cname. + AddrInfo(const char *host, const PRAddrInfo *prAddrInfo, bool disableIPv4, + bool filterNameCollision, const char *cname); + + // Creates a basic AddrInfo object (initialize only the host and the cname). + AddrInfo(const char *host, const char *cname); + ~AddrInfo(); + + void AddAddress(NetAddrElement *address); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + char *mHostName; + char *mCanonicalName; + uint16_t ttl; + static const uint16_t NO_TTL_DATA = (uint16_t) -1; + + LinkedList mAddresses; + +private: + void Init(const char *host, const char *cname); +}; + +// Copies the contents of a PRNetAddr to a NetAddr. +// Does not do a ptr safety check! +void PRNetAddrToNetAddr(const PRNetAddr *prAddr, NetAddr *addr); + +// Copies the contents of a NetAddr to a PRNetAddr. +// Does not do a ptr safety check! +void NetAddrToPRNetAddr(const NetAddr *addr, PRNetAddr *prAddr); + +bool NetAddrToString(const NetAddr *addr, char *buf, uint32_t bufSize); + +bool IsLoopBackAddress(const NetAddr *addr); + +bool IsIPAddrAny(const NetAddr *addr); + +bool IsIPAddrV4Mapped(const NetAddr *addr); + +bool IsIPAddrLocal(const NetAddr *addr); + +nsresult GetPort(const NetAddr *aAddr, uint16_t *aResult); + +} // namespace net +} // namespace mozilla + +#endif // DNS_h_ diff --git a/netwerk/dns/DNSListenerProxy.cpp b/netwerk/dns/DNSListenerProxy.cpp new file mode 100644 index 000000000..333f0946d --- /dev/null +++ b/netwerk/dns/DNSListenerProxy.cpp @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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/. */ + +#include "mozilla/net/DNSListenerProxy.h" +#include "nsICancelable.h" +#include "nsIEventTarget.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS(DNSListenerProxy, + nsIDNSListener, + nsIDNSListenerProxy) + +NS_IMETHODIMP +DNSListenerProxy::OnLookupComplete(nsICancelable* aRequest, + nsIDNSRecord* aRecord, + nsresult aStatus) +{ + RefPtr r = + new OnLookupCompleteRunnable(mListener, aRequest, aRecord, aStatus); + return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL); +} + +NS_IMETHODIMP +DNSListenerProxy::OnLookupCompleteRunnable::Run() +{ + mListener->OnLookupComplete(mRequest, mRecord, mStatus); + return NS_OK; +} + +NS_IMETHODIMP +DNSListenerProxy::GetOriginalListener(nsIDNSListener **aOriginalListener) +{ + NS_IF_ADDREF(*aOriginalListener = mListener); + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/DNSListenerProxy.h b/netwerk/dns/DNSListenerProxy.h new file mode 100644 index 000000000..307dde0f7 --- /dev/null +++ b/netwerk/dns/DNSListenerProxy.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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 DNSListenerProxy_h__ +#define DNSListenerProxy_h__ + +#include "nsIDNSListener.h" +#include "nsIDNSRecord.h" +#include "nsProxyRelease.h" +#include "nsThreadUtils.h" + +class nsIEventTarget; +class nsICancelable; + +namespace mozilla { +namespace net { + +class DNSListenerProxy final + : public nsIDNSListener + , public nsIDNSListenerProxy +{ +public: + DNSListenerProxy(nsIDNSListener* aListener, nsIEventTarget* aTargetThread) + // Sometimes aListener is a main-thread only object like XPCWrappedJS, and + // sometimes it's a threadsafe object like nsSOCKSSocketInfo. Use a main- + // thread pointer holder, but disable strict enforcement of thread invariants. + // The AddRef implementation of XPCWrappedJS will assert if we go wrong here. + : mListener(new nsMainThreadPtrHolder(aListener, false)) + , mTargetThread(aTargetThread) + { } + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSLISTENER + NS_DECL_NSIDNSLISTENERPROXY + + class OnLookupCompleteRunnable : public Runnable + { + public: + OnLookupCompleteRunnable(const nsMainThreadPtrHandle& aListener, + nsICancelable* aRequest, + nsIDNSRecord* aRecord, + nsresult aStatus) + : mListener(aListener) + , mRequest(aRequest) + , mRecord(aRecord) + , mStatus(aStatus) + { } + + NS_DECL_NSIRUNNABLE + + private: + nsMainThreadPtrHandle mListener; + nsCOMPtr mRequest; + nsCOMPtr mRecord; + nsresult mStatus; + }; + +private: + ~DNSListenerProxy() {} + + nsMainThreadPtrHandle mListener; + nsCOMPtr mTargetThread; +}; + + +} // namespace net +} // namespace mozilla + +#endif // DNSListenerProxy_h__ diff --git a/netwerk/dns/DNSRequestChild.cpp b/netwerk/dns/DNSRequestChild.cpp new file mode 100644 index 000000000..84086202b --- /dev/null +++ b/netwerk/dns/DNSRequestChild.cpp @@ -0,0 +1,313 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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/. */ + +#include "mozilla/net/ChildDNSService.h" +#include "mozilla/net/DNSRequestChild.h" +#include "mozilla/net/NeckoChild.h" +#include "mozilla/Unused.h" +#include "nsIDNSRecord.h" +#include "nsHostResolver.h" +#include "nsTArray.h" +#include "nsNetAddr.h" +#include "nsIThread.h" +#include "nsThreadUtils.h" + +using namespace mozilla::ipc; + +namespace mozilla { +namespace net { + +//----------------------------------------------------------------------------- +// ChildDNSRecord: +// A simple class to provide nsIDNSRecord on the child +//----------------------------------------------------------------------------- + +class ChildDNSRecord : public nsIDNSRecord +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSRECORD + + ChildDNSRecord(const DNSRecord& reply, uint16_t flags); + +private: + virtual ~ChildDNSRecord(); + + nsCString mCanonicalName; + nsTArray mAddresses; + uint32_t mCurrent; // addr iterator + uint32_t mLength; // number of addrs + uint16_t mFlags; +}; + +NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord) + +ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply, uint16_t flags) + : mCurrent(0) + , mFlags(flags) +{ + mCanonicalName = reply.canonicalName(); + + // A shame IPDL gives us no way to grab ownership of array: so copy it. + const nsTArray& addrs = reply.addrs(); + uint32_t i = 0; + mLength = addrs.Length(); + for (; i < mLength; i++) { + mAddresses.AppendElement(addrs[i]); + } +} + +ChildDNSRecord::~ChildDNSRecord() +{ +} + +//----------------------------------------------------------------------------- +// ChildDNSRecord::nsIDNSRecord +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ChildDNSRecord::GetCanonicalName(nsACString &result) +{ + if (!(mFlags & nsHostResolver::RES_CANON_NAME)) { + return NS_ERROR_NOT_AVAILABLE; + } + + result = mCanonicalName; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) +{ + if (mCurrent >= mLength) { + return NS_ERROR_NOT_AVAILABLE; + } + + memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr)); + + // both Ipv4/6 use same bits for port, so safe to just use ipv4's field + addr->inet.port = htons(port); + + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSRecord::GetAddresses(nsTArray & aAddressArray) +{ + aAddressArray = mAddresses; + return NS_OK; +} + +// shamelessly copied from nsDNSRecord +NS_IMETHODIMP +ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result) +{ + NetAddr addr; + nsresult rv = GetNextAddr(port, &addr); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = new nsNetAddr(&addr)); + + return NS_OK; +} + +// also copied from nsDNSRecord +NS_IMETHODIMP +ChildDNSRecord::GetNextAddrAsString(nsACString &result) +{ + NetAddr addr; + nsresult rv = GetNextAddr(0, &addr); + if (NS_FAILED(rv)) { + return rv; + } + + char buf[kIPv6CStrBufSize]; + if (NetAddrToString(&addr, buf, sizeof(buf))) { + result.Assign(buf); + return NS_OK; + } + NS_ERROR("NetAddrToString failed unexpectedly"); + return NS_ERROR_FAILURE; // conversion failed for some reason +} + +NS_IMETHODIMP +ChildDNSRecord::HasMore(bool *result) +{ + *result = mCurrent < mLength; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSRecord::Rewind() +{ + mCurrent = 0; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSRecord::ReportUnusable(uint16_t aPort) +{ + // "We thank you for your feedback" == >/dev/null + // TODO: we could send info back to parent. + return NS_OK; +} + +//----------------------------------------------------------------------------- +// CancelDNSRequestEvent +//----------------------------------------------------------------------------- + +class CancelDNSRequestEvent : public Runnable +{ +public: + CancelDNSRequestEvent(DNSRequestChild* aDnsReq, nsresult aReason) + : mDnsRequest(aDnsReq) + , mReasonForCancel(aReason) + {} + + NS_IMETHOD Run() override + { + if (mDnsRequest->mIPCOpen) { + // Send request to Parent process. + mDnsRequest->SendCancelDNSRequest(mDnsRequest->mHost, mDnsRequest->mFlags, + mDnsRequest->mNetworkInterface, + mReasonForCancel); + } + return NS_OK; + } +private: + RefPtr mDnsRequest; + nsresult mReasonForCancel; +}; + +//----------------------------------------------------------------------------- +// DNSRequestChild +//----------------------------------------------------------------------------- + +DNSRequestChild::DNSRequestChild(const nsCString& aHost, + const uint32_t& aFlags, + const nsCString& aNetworkInterface, + nsIDNSListener *aListener, + nsIEventTarget *target) + : mListener(aListener) + , mTarget(target) + , mResultStatus(NS_OK) + , mHost(aHost) + , mFlags(aFlags) + , mNetworkInterface(aNetworkInterface) + , mIPCOpen(false) +{ +} + +void +DNSRequestChild::StartRequest() +{ + // we can only do IPDL on the main thread + if (!NS_IsMainThread()) { + NS_DispatchToMainThread( + NewRunnableMethod(this, &DNSRequestChild::StartRequest)); + return; + } + + // Send request to Parent process. + gNeckoChild->SendPDNSRequestConstructor(this, mHost, mFlags, + mNetworkInterface); + mIPCOpen = true; + + // IPDL holds a reference until IPDL channel gets destroyed + AddIPDLReference(); +} + +void +DNSRequestChild::CallOnLookupComplete() +{ + MOZ_ASSERT(mListener); + mListener->OnLookupComplete(this, mResultRecord, mResultStatus); +} + +bool +DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply) +{ + mIPCOpen = false; + MOZ_ASSERT(mListener); + + switch (reply.type()) { + case DNSRequestResponse::TDNSRecord: { + mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags); + break; + } + case DNSRequestResponse::Tnsresult: { + mResultStatus = reply.get_nsresult(); + break; + } + default: + NS_NOTREACHED("unknown type"); + return false; + } + + MOZ_ASSERT(NS_IsMainThread()); + + bool targetIsMain = false; + if (!mTarget) { + targetIsMain = true; + } else { + mTarget->IsOnCurrentThread(&targetIsMain); + } + + if (targetIsMain) { + CallOnLookupComplete(); + } else { + nsCOMPtr event = + NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete); + mTarget->Dispatch(event, NS_DISPATCH_NORMAL); + } + + Unused << Send__delete__(this); + + return true; +} + +void +DNSRequestChild::ReleaseIPDLReference() +{ + // Request is done or destroyed. Remove it from the hash table. + RefPtr dnsServiceChild = + dont_AddRef(ChildDNSService::GetSingleton()); + dnsServiceChild->NotifyRequestDone(this); + + Release(); +} + +void +DNSRequestChild::ActorDestroy(ActorDestroyReason why) +{ + mIPCOpen = false; +} + +//----------------------------------------------------------------------------- +// DNSRequestChild::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS(DNSRequestChild, + nsICancelable) + +//----------------------------------------------------------------------------- +// DNSRequestChild::nsICancelable +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +DNSRequestChild::Cancel(nsresult reason) +{ + if(mIPCOpen) { + // We can only do IPDL on the main thread + NS_DispatchToMainThread( + new CancelDNSRequestEvent(this, reason)); + } + return NS_OK; +} + +//------------------------------------------------------------------------------ +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/DNSRequestChild.h b/netwerk/dns/DNSRequestChild.h new file mode 100644 index 000000000..26d4ff98d --- /dev/null +++ b/netwerk/dns/DNSRequestChild.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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 mozilla_net_DNSRequestChild_h +#define mozilla_net_DNSRequestChild_h + +#include "mozilla/net/PDNSRequestChild.h" +#include "nsICancelable.h" +#include "nsIDNSRecord.h" +#include "nsIDNSListener.h" +#include "nsIEventTarget.h" + +namespace mozilla { +namespace net { + +class DNSRequestChild final + : public PDNSRequestChild + , public nsICancelable +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSICANCELABLE + + DNSRequestChild(const nsCString& aHost, const uint32_t& aFlags, + const nsCString& aNetworkInterface, + nsIDNSListener *aListener, nsIEventTarget *target); + + void AddIPDLReference() { + AddRef(); + } + void ReleaseIPDLReference(); + + // Sends IPDL request to parent + void StartRequest(); + void CallOnLookupComplete(); + +protected: + friend class CancelDNSRequestEvent; + friend class ChildDNSService; + virtual ~DNSRequestChild() {} + + virtual bool RecvLookupCompleted(const DNSRequestResponse& reply) override; + virtual void ActorDestroy(ActorDestroyReason why) override; + + nsCOMPtr mListener; + nsCOMPtr mTarget; + nsCOMPtr mResultRecord; + nsresult mResultStatus; + nsCString mHost; + uint16_t mFlags; + nsCString mNetworkInterface; + bool mIPCOpen; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_DNSRequestChild_h diff --git a/netwerk/dns/DNSRequestParent.cpp b/netwerk/dns/DNSRequestParent.cpp new file mode 100644 index 000000000..a5c95a812 --- /dev/null +++ b/netwerk/dns/DNSRequestParent.cpp @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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/. */ + +#include "mozilla/net/DNSRequestParent.h" +#include "nsIDNSService.h" +#include "nsNetCID.h" +#include "nsThreadUtils.h" +#include "nsIServiceManager.h" +#include "nsICancelable.h" +#include "nsIDNSRecord.h" +#include "nsHostResolver.h" +#include "mozilla/Unused.h" + +using namespace mozilla::ipc; + +namespace mozilla { +namespace net { + +DNSRequestParent::DNSRequestParent() + : mFlags(0) + , mIPCClosed(false) +{ + +} + +DNSRequestParent::~DNSRequestParent() +{ + +} + +void +DNSRequestParent::DoAsyncResolve(const nsACString &hostname, uint32_t flags, + const nsACString &networkInterface) +{ + nsresult rv; + mFlags = flags; + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr mainThread = do_GetMainThread(); + nsCOMPtr unused; + rv = dns->AsyncResolveExtended(hostname, flags, networkInterface, this, + mainThread, getter_AddRefs(unused)); + } + + if (NS_FAILED(rv) && !mIPCClosed) { + mIPCClosed = true; + Unused << SendLookupCompleted(DNSRequestResponse(rv)); + } +} + +bool +DNSRequestParent::RecvCancelDNSRequest(const nsCString& hostName, + const uint32_t& flags, + const nsCString& networkInterface, + const nsresult& reason) +{ + nsresult rv; + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + rv = dns->CancelAsyncResolveExtended(hostName, flags, networkInterface, + this, reason); + } + return true; +} + +bool +DNSRequestParent::Recv__delete__() +{ + mIPCClosed = true; + return true; +} + +void +DNSRequestParent::ActorDestroy(ActorDestroyReason why) +{ + // We may still have refcount>0 if DNS hasn't called our OnLookupComplete + // yet, but child process has crashed. We must not send any more msgs + // to child, or IPDL will kill chrome process, too. + mIPCClosed = true; +} +//----------------------------------------------------------------------------- +// DNSRequestParent::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS(DNSRequestParent, + nsIDNSListener) + +//----------------------------------------------------------------------------- +// nsIDNSListener functions +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +DNSRequestParent::OnLookupComplete(nsICancelable *request, + nsIDNSRecord *rec, + nsresult status) +{ + if (mIPCClosed) { + // nothing to do: child probably crashed + return NS_OK; + } + + if (NS_SUCCEEDED(status)) { + MOZ_ASSERT(rec); + + nsAutoCString cname; + if (mFlags & nsHostResolver::RES_CANON_NAME) { + rec->GetCanonicalName(cname); + } + + // Get IP addresses for hostname (use port 80 as dummy value for NetAddr) + NetAddrArray array; + NetAddr addr; + while (NS_SUCCEEDED(rec->GetNextAddr(80, &addr))) { + array.AppendElement(addr); + } + + Unused << SendLookupCompleted(DNSRequestResponse(DNSRecord(cname, array))); + } else { + Unused << SendLookupCompleted(DNSRequestResponse(status)); + } + + mIPCClosed = true; + return NS_OK; +} + + + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/DNSRequestParent.h b/netwerk/dns/DNSRequestParent.h new file mode 100644 index 000000000..d217dbd4f --- /dev/null +++ b/netwerk/dns/DNSRequestParent.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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 mozilla_net_DNSRequestParent_h +#define mozilla_net_DNSRequestParent_h + +#include "mozilla/net/PDNSRequestParent.h" +#include "nsIDNSService.h" +#include "nsIDNSListener.h" + +namespace mozilla { +namespace net { + +class DNSRequestParent + : public PDNSRequestParent + , public nsIDNSListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSLISTENER + + DNSRequestParent(); + + void DoAsyncResolve(const nsACString &hostname, uint32_t flags, + const nsACString &networkInterface); + + // Pass args here rather than storing them in the parent; they are only + // needed if the request is to be canceled. + bool RecvCancelDNSRequest(const nsCString& hostName, + const uint32_t& flags, + const nsCString& networkInterface, + const nsresult& reason) override; + bool Recv__delete__() override; + +protected: + virtual void ActorDestroy(ActorDestroyReason why) override; +private: + virtual ~DNSRequestParent(); + + uint32_t mFlags; + bool mIPCClosed; // true if IPDL channel has been closed (child crash) +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_DNSRequestParent_h diff --git a/netwerk/dns/GetAddrInfo.cpp b/netwerk/dns/GetAddrInfo.cpp new file mode 100644 index 000000000..3c177ec53 --- /dev/null +++ b/netwerk/dns/GetAddrInfo.cpp @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "GetAddrInfo.h" +#include "mozilla/net/DNS.h" +#include "prnetdb.h" +#include "nsHostResolver.h" +#include "nsError.h" +#include "mozilla/Mutex.h" +#include "nsAutoPtr.h" +#include "mozilla/StaticPtr.h" +#include "MainThreadUtils.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/net/DNS.h" +#include +#include "prerror.h" + +#include "mozilla/Logging.h" + +#if DNSQUERY_AVAILABLE +// There is a bug in windns.h where the type of parameter ppQueryResultsSet for +// DnsQuery_A is dependent on UNICODE being set. It should *always* be +// PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this +// we make sure that UNICODE is unset. +#undef UNICODE +#include +#undef GetAddrInfo +#include +#endif + +namespace mozilla { +namespace net { + +static LazyLogModule gGetAddrInfoLog("GetAddrInfo"); +#define LOG(msg, ...) \ + MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__)) +#define LOG_WARNING(msg, ...) \ + MOZ_LOG(gGetAddrInfoLog, LogLevel::Warning, ("[DNS]: " msg, ##__VA_ARGS__)) + +#if DNSQUERY_AVAILABLE +//////////////////////////// +// WINDOWS IMPLEMENTATION // +//////////////////////////// + +// Ensure consistency of PR_* and AF_* constants to allow for legacy usage of +// PR_* constants with this API. +static_assert(PR_AF_INET == AF_INET && PR_AF_INET6 == AF_INET6 + && PR_AF_UNSPEC == AF_UNSPEC, "PR_AF_* must match AF_*"); + +// We intentionally leak this mutex. This is because we can run into a +// situation where the worker threads are still running until the process +// is actually fully shut down, and at any time one of those worker +// threads can access gDnsapiInfoLock. +static OffTheBooksMutex* gDnsapiInfoLock = nullptr; + +struct DnsapiInfo +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DnsapiInfo); + + HMODULE mLibrary; + decltype(&DnsQuery_A) mDnsQueryFunc; + decltype(&DnsFree) mDnsFreeFunc; + +private: + // This will either be called during shutdown of the GetAddrInfo module, or + // when a worker thread is done doing a lookup (ie: within + // _GetAddrInfo_Windows). Note that the lock must be held when this is + // called. + ~DnsapiInfo() + { + if (gDnsapiInfoLock) { + gDnsapiInfoLock->AssertCurrentThreadOwns(); + } else { + MOZ_ASSERT_UNREACHABLE("No mutex available during GetAddrInfo " + "shutdown."); + return; + } + + LOG("Freeing Dnsapi.dll"); + MOZ_ASSERT(mLibrary); + DebugOnly rv = FreeLibrary(mLibrary); + NS_WARNING_ASSERTION(rv, "Failed to free Dnsapi.dll."); + } +}; + +static StaticRefPtr gDnsapiInfo; + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfoInit_Windows() +{ + // This is necessary to ensure strict thread safety because if two threads + // run this function at the same time they can potentially create two + // mutexes. + MOZ_ASSERT(NS_IsMainThread(), + "Do not initialize GetAddrInfo off main thread!"); + + if (!gDnsapiInfoLock) { + gDnsapiInfoLock = new OffTheBooksMutex("GetAddrInfo.cpp::gDnsapiInfoLock"); + } + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + + if (gDnsapiInfo) { + MOZ_ASSERT_UNREACHABLE("GetAddrInfo is being initialized multiple times!"); + return NS_ERROR_ALREADY_INITIALIZED; + } + + HMODULE library = LoadLibraryA("Dnsapi.dll"); + if (NS_WARN_IF(!library)) { + return NS_ERROR_FAILURE; + } + + FARPROC dnsQueryFunc = GetProcAddress(library, "DnsQuery_A"); + FARPROC dnsFreeFunc = GetProcAddress(library, "DnsFree"); + if (NS_WARN_IF(!dnsQueryFunc) || NS_WARN_IF(!dnsFreeFunc)) { + DebugOnly rv = FreeLibrary(library); + NS_WARNING_ASSERTION(rv, "Failed to free Dnsapi.dll."); + return NS_ERROR_FAILURE; + } + + DnsapiInfo* info = new DnsapiInfo; + info->mLibrary = library; + info->mDnsQueryFunc = (decltype(info->mDnsQueryFunc)) dnsQueryFunc; + info->mDnsFreeFunc = (decltype(info->mDnsFreeFunc)) dnsFreeFunc; + gDnsapiInfo = info; + + return NS_OK; +} + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfoShutdown_Windows() +{ + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + + if (NS_WARN_IF(!gDnsapiInfo) || NS_WARN_IF(!gDnsapiInfoLock)) { + MOZ_ASSERT_UNREACHABLE("GetAddrInfo not initialized!"); + return NS_ERROR_NOT_INITIALIZED; + } + + gDnsapiInfo = nullptr; + + return NS_OK; +} + +// If successful, returns in aResult a TTL value that is smaller or +// equal with the one already there. Gets the TTL value by calling +// to dnsapi->mDnsQueryFunc and iterating through the returned +// records to find the one with the smallest TTL value. +static MOZ_ALWAYS_INLINE nsresult +_GetMinTTLForRequestType_Windows(DnsapiInfo * dnsapi, const char* aHost, + uint16_t aRequestType, unsigned int* aResult) +{ + MOZ_ASSERT(dnsapi); + MOZ_ASSERT(aHost); + MOZ_ASSERT(aResult); + + PDNS_RECORDA dnsData = nullptr; + DNS_STATUS status = dnsapi->mDnsQueryFunc( + aHost, + aRequestType, + (DNS_QUERY_STANDARD | DNS_QUERY_NO_NETBT | DNS_QUERY_NO_HOSTS_FILE + | DNS_QUERY_NO_MULTICAST | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE + | DNS_QUERY_DONT_RESET_TTL_VALUES), + nullptr, + &dnsData, + nullptr); + if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR + || !dnsData) { + LOG("No DNS records found for %s. status=%X. aRequestType = %X\n", + aHost, status, aRequestType); + return NS_ERROR_FAILURE; + } else if (status != NOERROR) { + LOG_WARNING("DnsQuery_A failed with status %X.\n", status); + return NS_ERROR_UNEXPECTED; + } + + for (PDNS_RECORDA curRecord = dnsData; curRecord; curRecord = curRecord->pNext) { + // Only records in the answer section are important + if (curRecord->Flags.S.Section != DnsSectionAnswer) { + continue; + } + + if (curRecord->wType == aRequestType) { + *aResult = std::min(*aResult, curRecord->dwTtl); + } else { + LOG("Received unexpected record type %u in response for %s.\n", + curRecord->wType, aHost); + } + } + + dnsapi->mDnsFreeFunc(dnsData, DNS_FREE_TYPE::DnsFreeRecordList); + return NS_OK; +} + +static MOZ_ALWAYS_INLINE nsresult +_GetTTLData_Windows(const char* aHost, uint16_t* aResult, uint16_t aAddressFamily) +{ + MOZ_ASSERT(aHost); + MOZ_ASSERT(aResult); + if (aAddressFamily != PR_AF_UNSPEC && + aAddressFamily != PR_AF_INET && + aAddressFamily != PR_AF_INET6) { + return NS_ERROR_UNEXPECTED; + } + + RefPtr dnsapi = nullptr; + { + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + dnsapi = gDnsapiInfo; + } + + if (!dnsapi) { + LOG_WARNING("GetAddrInfo has been shutdown or has not been initialized."); + return NS_ERROR_NOT_INITIALIZED; + } + + // In order to avoid using ANY records which are not always implemented as a + // "Gimme what you have" request in hostname resolvers, we should send A + // and/or AAAA requests, based on the address family requested. + unsigned int ttl = -1; + if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET) { + _GetMinTTLForRequestType_Windows(dnsapi, aHost, DNS_TYPE_A, &ttl); + } + if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET6) { + _GetMinTTLForRequestType_Windows(dnsapi, aHost, DNS_TYPE_AAAA, &ttl); + } + + { + // dnsapi's destructor is not thread-safe, so we release explicitly here + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + dnsapi = nullptr; + } + + if (ttl == -1) { + LOG("No useable TTL found."); + return NS_ERROR_FAILURE; + } + + *aResult = ttl; + return NS_OK; +} +#endif + +//////////////////////////////////// +// PORTABLE RUNTIME IMPLEMENTATION// +//////////////////////////////////// + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfo_Portable(const char* aCanonHost, uint16_t aAddressFamily, + uint16_t aFlags, const char* aNetworkInterface, + AddrInfo** aAddrInfo) +{ + MOZ_ASSERT(aCanonHost); + MOZ_ASSERT(aAddrInfo); + + // We accept the same aFlags that nsHostResolver::ResolveHost accepts, but we + // need to translate the aFlags into a form that PR_GetAddrInfoByName + // accepts. + int prFlags = PR_AI_ADDRCONFIG; + if (!(aFlags & nsHostResolver::RES_CANON_NAME)) { + prFlags |= PR_AI_NOCANONNAME; + } + + // We need to remove IPv4 records manually because PR_GetAddrInfoByName + // doesn't support PR_AF_INET6. + bool disableIPv4 = aAddressFamily == PR_AF_INET6; + if (disableIPv4) { + aAddressFamily = PR_AF_UNSPEC; + } + + PRAddrInfo* prai = PR_GetAddrInfoByName(aCanonHost, aAddressFamily, prFlags); + + if (!prai) { + return NS_ERROR_UNKNOWN_HOST; + } + + const char* canonName = nullptr; + if (aFlags & nsHostResolver::RES_CANON_NAME) { + canonName = PR_GetCanonNameFromAddrInfo(prai); + } + + bool filterNameCollision = !(aFlags & nsHostResolver::RES_ALLOW_NAME_COLLISION); + nsAutoPtr ai(new AddrInfo(aCanonHost, prai, disableIPv4, + filterNameCollision, canonName)); + PR_FreeAddrInfo(prai); + if (ai->mAddresses.isEmpty()) { + return NS_ERROR_UNKNOWN_HOST; + } + + *aAddrInfo = ai.forget(); + + return NS_OK; +} + +////////////////////////////////////// +// COMMON/PLATFORM INDEPENDENT CODE // +////////////////////////////////////// +nsresult +GetAddrInfoInit() { + LOG("Initializing GetAddrInfo.\n"); + +#if DNSQUERY_AVAILABLE + return _GetAddrInfoInit_Windows(); +#else + return NS_OK; +#endif +} + +nsresult +GetAddrInfoShutdown() { + LOG("Shutting down GetAddrInfo.\n"); + +#if DNSQUERY_AVAILABLE + return _GetAddrInfoShutdown_Windows(); +#else + return NS_OK; +#endif +} + +nsresult +GetAddrInfo(const char* aHost, uint16_t aAddressFamily, uint16_t aFlags, + const char* aNetworkInterface, AddrInfo** aAddrInfo, bool aGetTtl) +{ + if (NS_WARN_IF(!aHost) || NS_WARN_IF(!aAddrInfo)) { + return NS_ERROR_NULL_POINTER; + } + +#if DNSQUERY_AVAILABLE + // The GetTTLData needs the canonical name to function properly + if (aGetTtl) { + aFlags |= nsHostResolver::RES_CANON_NAME; + } +#endif + + *aAddrInfo = nullptr; + nsresult rv = _GetAddrInfo_Portable(aHost, aAddressFamily, aFlags, + aNetworkInterface, aAddrInfo); + +#if DNSQUERY_AVAILABLE + if (aGetTtl && NS_SUCCEEDED(rv)) { + // Figure out the canonical name, or if that fails, just use the host name + // we have. + const char *name = nullptr; + if (*aAddrInfo != nullptr && (*aAddrInfo)->mCanonicalName) { + name = (*aAddrInfo)->mCanonicalName; + } else { + name = aHost; + } + + LOG("Getting TTL for %s (cname = %s).", aHost, name); + uint16_t ttl = 0; + nsresult ttlRv = _GetTTLData_Windows(name, &ttl, aAddressFamily); + if (NS_SUCCEEDED(ttlRv)) { + (*aAddrInfo)->ttl = ttl; + LOG("Got TTL %u for %s (name = %s).", ttl, aHost, name); + } else { + LOG_WARNING("Could not get TTL for %s (cname = %s).", aHost, name); + } + } +#endif + + return rv; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/GetAddrInfo.h b/netwerk/dns/GetAddrInfo.h new file mode 100644 index 000000000..57c008dd5 --- /dev/null +++ b/netwerk/dns/GetAddrInfo.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 netwerk_dns_GetAddrInfo_h +#define netwerk_dns_GetAddrInfo_h + +#include "nsError.h" +#include "nscore.h" + +#if defined(XP_WIN) +#define DNSQUERY_AVAILABLE 1 +#define TTL_AVAILABLE 1 +#else +#define DNSQUERY_AVAILABLE 0 +#define TTL_AVAILABLE 0 +#endif + +namespace mozilla { +namespace net { + +class AddrInfo; + +/** + * Look up a host by name. Mostly equivalent to getaddrinfo(host, NULL, ...) of + * RFC 3493. + * + * @param aHost[in] Character string defining the host name of interest + * @param aAddressFamily[in] May be AF_INET, AF_INET6, or AF_UNSPEC. + * @param aFlags[in] May be either PR_AI_ADDRCONFIG or + * PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include PR_AI_NOCANONNAME to + * suppress the determination of the canonical name corresponding to + * hostname (PR_AI_NOCANONNAME will be ignored if the TTL is retrieved). + * @param aAddrInfo[out] Will point to the results of the host lookup, or be + * null if the lookup failed. + * @param aGetTtl[in] If true, and TTL_AVAILABLE is truthy, the TTL will be + * retrieved if DNS provides the answers.. + */ +nsresult +GetAddrInfo(const char* aHost, uint16_t aAddressFamily, uint16_t aFlags, + const char* aNetworkInterface, AddrInfo** aAddrInfo, bool aGetTtl); + +/** + * Initialize the GetAddrInfo module. + * + * GetAddrInfoShutdown() should be called for every time this function is + * called. + */ +nsresult +GetAddrInfoInit(); + +/** + * Shutdown the GetAddrInfo module. + * + * This function should be called for every time GetAddrInfoInit() is called. + * An assertion may throw (but is not guarenteed) if this function is called + * too many times. + */ +nsresult +GetAddrInfoShutdown(); + +} // namespace net +} // namespace mozilla + +#endif // netwerk_dns_GetAddrInfo_h diff --git a/netwerk/dns/PDNSParams.h b/netwerk/dns/PDNSParams.h new file mode 100644 index 000000000..e5e668164 --- /dev/null +++ b/netwerk/dns/PDNSParams.h @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 ft=c: */ + +/* 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 PDNSParams_h +#define PDNSParams_h + +#include "DNS.h" +#include "nsTArray.h" + +namespace mozilla { +namespace net { + +// Need to define typedef in .h file--can't seem to in ipdl.h file? +typedef nsTArray NetAddrArray; + +} // namespace net +} // namespace mozilla + +#endif // PDNSParams_h diff --git a/netwerk/dns/PDNSRequest.ipdl b/netwerk/dns/PDNSRequest.ipdl new file mode 100644 index 000000000..2288ab09e --- /dev/null +++ b/netwerk/dns/PDNSRequest.ipdl @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */ + +/* 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/. */ + +include protocol PNecko; + +include PDNSRequestParams; + +include "mozilla/net/NeckoMessageUtils.h"; + +namespace mozilla { +namespace net { + +async protocol PDNSRequest +{ + manager PNecko; + +parent: + // constructor in PNecko takes AsyncResolve args that initialize request + + // Pass args here rather than storing them in the parent; they are only + // needed if the request is to be canceled. + async CancelDNSRequest(nsCString hostName, uint32_t flags, + nsCString networkInterface, nsresult reason); + async __delete__(); + +child: + async LookupCompleted(DNSRequestResponse reply); + +}; + +} //namespace net +} //namespace mozilla diff --git a/netwerk/dns/PDNSRequestParams.ipdlh b/netwerk/dns/PDNSRequestParams.ipdlh new file mode 100644 index 000000000..d06f27cfa --- /dev/null +++ b/netwerk/dns/PDNSRequestParams.ipdlh @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */ + +/* 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/. */ + +using NetAddrArray from "mozilla/net/PDNSParams.h"; + +namespace mozilla { +namespace net { + +//----------------------------------------------------------------------------- +// DNS IPDL structs +//----------------------------------------------------------------------------- + +struct DNSRecord +{ + nsCString canonicalName; + NetAddrArray addrs; +}; + +union DNSRequestResponse +{ + DNSRecord; + nsresult; // if error +}; + + +} // namespace ipc +} // namespace mozilla diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat new file mode 100644 index 000000000..24165a090 --- /dev/null +++ b/netwerk/dns/effective_tld_names.dat @@ -0,0 +1,10834 @@ +// 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/. + +// ===BEGIN ICANN DOMAINS=== + +// ac : http://en.wikipedia.org/wiki/.ac +ac +com.ac +edu.ac +gov.ac +net.ac +mil.ac +org.ac + +// ad : http://en.wikipedia.org/wiki/.ad +ad +nom.ad + +// ae : http://en.wikipedia.org/wiki/.ae +// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php +ae +co.ae +net.ae +org.ae +sch.ae +ac.ae +gov.ae +mil.ae + +// aero : see http://www.information.aero/index.php?id=66 +aero +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +aircraft.aero +airline.aero +airport.aero +air-surveillance.aero +airtraffic.aero +air-traffic-control.aero +ambulance.aero +amusement.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +freight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +marketplace.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +taxi.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : http://www.nic.af/help.jsp +af +gov.af +com.af +org.af +net.af +edu.af + +// ag : http://www.nic.ag/prices.htm +ag +com.ag +org.ag +net.ag +co.ag +nom.ag + +// ai : http://nic.com.ai/ +ai +off.ai +com.ai +net.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : http://en.wikipedia.org/wiki/.am +am + +// an : http://www.una.an/an_domreg/default.asp +an +com.an +net.an +org.an +edu.an + +// ao : http://en.wikipedia.org/wiki/.ao +// http://www.dns.ao/REGISTR.DOC +ao +ed.ao +gv.ao +og.ao +co.ao +pb.ao +it.ao + +// aq : http://en.wikipedia.org/wiki/.aq +aq + +// ar : https://nic.ar/normativa-vigente.xhtml +ar +com.ar +edu.ar +gob.ar +gov.ar +int.ar +mil.ar +net.ar +org.ar +tur.ar + +// arpa : http://en.wikipedia.org/wiki/.arpa +// Confirmed by registry 2008-06-18 +arpa +e164.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : http://en.wikipedia.org/wiki/.as +as +gov.as + +// asia : http://en.wikipedia.org/wiki/.asia +asia + +// at : http://en.wikipedia.org/wiki/.at +// Confirmed by registry 2008-06-17 +at +ac.at +co.at +gv.at +or.at + +// au : http://en.wikipedia.org/wiki/.au +// http://www.auda.org.au/ +au +// 2LDs +com.au +net.au +org.au +edu.au +gov.au +asn.au +id.au +// Historic 2LDs (closed to new registration, but sites still exist) +info.au +conf.au +oz.au +// CGDNs - http://www.cgdn.org.au/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au +// 3LDs +act.edu.au +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +// act.gov.au Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au Bug 547985 - Removed at request of +// nt.gov.au Bug 940478 - Removed at request of Greg Connors +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au + +// aw : http://en.wikipedia.org/wiki/.aw +aw +com.aw + +// ax : http://en.wikipedia.org/wiki/.ax +ax + +// az : http://en.wikipedia.org/wiki/.az +az +com.az +net.az +int.az +gov.az +org.az +edu.az +info.az +pp.az +mil.az +name.az +pro.az +biz.az + +// ba : http://en.wikipedia.org/wiki/.ba +ba +org.ba +net.ba +edu.ba +gov.ba +mil.ba +unsa.ba +unbi.ba +co.ba +com.ba +rs.ba + +// bb : http://en.wikipedia.org/wiki/.bb +bb +biz.bb +co.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb +tv.bb + +// bd : http://en.wikipedia.org/wiki/.bd +*.bd + +// be : http://en.wikipedia.org/wiki/.be +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : http://en.wikipedia.org/wiki/.bf +bf +gov.bf + +// bg : http://en.wikipedia.org/wiki/.bg +// https://www.register.bg/user/static/rules/en/index.html +bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg + +// bh : http://en.wikipedia.org/wiki/.bh +bh +com.bh +edu.bh +net.bh +org.bh +gov.bh + +// bi : http://en.wikipedia.org/wiki/.bi +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : http://en.wikipedia.org/wiki/.biz +biz + +// bj : http://en.wikipedia.org/wiki/.bj +bj +asso.bj +barreau.bj +gouv.bj + +// bm : http://www.bermudanic.bm/dnr-text.txt +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : http://en.wikipedia.org/wiki/.bn +*.bn + +// bo : http://www.nic.bo/ +bo +com.bo +edu.bo +gov.bo +gob.bo +int.bo +org.bo +net.bo +mil.bo +tv.bo + +// br : http://registro.br/dominio/categoria.html +// Submitted by registry 2014-08-11 +br +adm.br +adv.br +agr.br +am.br +arq.br +art.br +ato.br +b.br +bio.br +blog.br +bmd.br +cim.br +cng.br +cnt.br +com.br +coop.br +ecn.br +eco.br +edu.br +emp.br +eng.br +esp.br +etc.br +eti.br +far.br +flog.br +fm.br +fnd.br +fot.br +fst.br +g12.br +ggf.br +gov.br +imb.br +ind.br +inf.br +jor.br +jus.br +leg.br +lel.br +mat.br +med.br +mil.br +mp.br +mus.br +net.br +*.nom.br +not.br +ntr.br +odo.br +org.br +ppg.br +pro.br +psc.br +psi.br +qsl.br +radio.br +rec.br +slg.br +srv.br +taxi.br +teo.br +tmp.br +trd.br +tur.br +tv.br +vet.br +vlog.br +wiki.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +net.bs +org.bs +edu.bs +gov.bs + +// bt : http://en.wikipedia.org/wiki/.bt +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry 2006-06-16 +bv + +// bw : http://en.wikipedia.org/wiki/.bw +// http://www.gobin.info/domainname/bw.doc +// list of other 2nd level tlds ? +bw +co.bw +org.bw + +// by : http://en.wikipedia.org/wiki/.by +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by + +// http://hoster.by/ +of.by + +// bz : http://en.wikipedia.org/wiki/.bz +// http://www.belizenic.bz/ +bz +com.bz +net.bz +org.bz +edu.bz +gov.bz + +// ca : http://en.wikipedia.org/wiki/.ca +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: http://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : http://en.wikipedia.org/wiki/.cat +cat + +// cc : http://en.wikipedia.org/wiki/.cc +cc + +// cd : http://en.wikipedia.org/wiki/.cd +// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +cd +gov.cd + +// cf : http://en.wikipedia.org/wiki/.cf +cf + +// cg : http://en.wikipedia.org/wiki/.cg +cg + +// ch : http://en.wikipedia.org/wiki/.ch +ch + +// ci : http://en.wikipedia.org/wiki/.ci +// http://www.nic.ci/index.php?page=charte +ci +org.ci +or.ci +com.ci +co.ci +edu.ci +ed.ci +ac.ci +net.ci +go.ci +asso.ci +aéroport.ci +int.ci +presse.ci +md.ci +gouv.ci + +// ck : http://en.wikipedia.org/wiki/.ck +*.ck +!www.ck + +// cl : http://en.wikipedia.org/wiki/.cl +cl +gov.cl +gob.cl +co.cl +mil.cl + +// cm : http://en.wikipedia.org/wiki/.cm plus bug 981927 +cm +co.cm +com.cm +gov.cm +net.cm + +// cn : http://en.wikipedia.org/wiki/.cn +// Submitted by registry 2008-06-11 +cn +ac.cn +com.cn +edu.cn +gov.cn +net.cn +org.cn +mil.cn +公司.cn +网络.cn +網絡.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gz.cn +gx.cn +ha.cn +hb.cn +he.cn +hi.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +xj.cn +xz.cn +yn.cn +zj.cn +hk.cn +mo.cn +tw.cn + +// co : http://en.wikipedia.org/wiki/.co +// Submitted by registry 2008-06-11 +co +arts.co +com.co +edu.co +firm.co +gov.co +info.co +int.co +mil.co +net.co +nom.co +org.co +rec.co +web.co + +// com : http://en.wikipedia.org/wiki/.com +com + +// coop : http://en.wikipedia.org/wiki/.coop +coop + +// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : http://en.wikipedia.org/wiki/.cu +cu +com.cu +edu.cu +org.cu +net.cu +gov.cu +inf.cu + +// cv : http://en.wikipedia.org/wiki/.cv +cv + +// cw : http://www.una.cw/cw_registry/ +// Confirmed by registry 2013-03-26 +cw +com.cw +edu.cw +net.cw +org.cw + +// cx : http://en.wikipedia.org/wiki/.cx +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://en.wikipedia.org/wiki/.cy +ac.cy +biz.cy +com.cy +ekloges.cy +gov.cy +ltd.cy +name.cy +net.cy +org.cy +parliament.cy +press.cy +pro.cy +tm.cy + +// cz : http://en.wikipedia.org/wiki/.cz +cz + +// de : http://en.wikipedia.org/wiki/.de +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : http://en.wikipedia.org/wiki/.dj +dj + +// dk : http://en.wikipedia.org/wiki/.dk +// Confirmed by registry 2008-06-17 +dk + +// dm : http://en.wikipedia.org/wiki/.dm +dm +com.dm +net.dm +org.dm +edu.dm +gov.dm + +// do : http://en.wikipedia.org/wiki/.do +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : http://en.wikipedia.org/wiki/.dz +dz +com.dz +org.dz +net.dz +gov.dz +edu.dz +asso.dz +pol.dz +art.dz + +// ec : http://www.nic.ec/reg/paso1.asp +// Submitted by registry 2008-07-04 +ec +com.ec +info.ec +net.ec +fin.ec +k12.ec +med.ec +pro.ec +org.ec +edu.ec +gov.ec +gob.ec +mil.ec + +// edu : http://en.wikipedia.org/wiki/.edu +edu + +// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +ee +edu.ee +gov.ee +riik.ee +lib.ee +med.ee +com.ee +pri.ee +aip.ee +org.ee +fie.ee + +// eg : http://en.wikipedia.org/wiki/.eg +eg +com.eg +edu.eg +eun.eg +gov.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg + +// er : http://en.wikipedia.org/wiki/.er +*.er + +// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +es +com.es +nom.es +org.es +gob.es +edu.es + +// et : http://en.wikipedia.org/wiki/.et +et +com.et +gov.et +org.et +edu.et +biz.et +name.et +info.et +net.et + +// eu : http://en.wikipedia.org/wiki/.eu +eu + +// fi : http://en.wikipedia.org/wiki/.fi +fi +// aland.fi : http://en.wikipedia.org/wiki/.ax +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +// TODO: Check for updates (expected to be phased out around Q1/2009) +aland.fi + +// fj : http://en.wikipedia.org/wiki/.fj +*.fj + +// fk : http://en.wikipedia.org/wiki/.fk +*.fk + +// fm : http://en.wikipedia.org/wiki/.fm +fm + +// fo : http://en.wikipedia.org/wiki/.fo +fo + +// fr : http://www.afnic.fr/ +// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs +fr +com.fr +asso.fr +nom.fr +prd.fr +presse.fr +tm.fr +// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels +aeroport.fr +assedic.fr +avocat.fr +avoues.fr +cci.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +geometre-expert.fr +gouv.fr +greta.fr +huissier-justice.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// ga : http://en.wikipedia.org/wiki/.ga +ga + +// gb : This registry is effectively dormant +// Submitted by registry 2008-06-12 +gb + +// gd : http://en.wikipedia.org/wiki/.gd +gd + +// ge : http://www.nic.net.ge/policy_en.pdf +ge +com.ge +edu.ge +gov.ge +org.ge +mil.ge +net.ge +pvt.ge + +// gf : http://en.wikipedia.org/wiki/.gf +gf + +// gg : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +gg +co.gg +net.gg +org.gg + +// gh : http://en.wikipedia.org/wiki/.gh +// see also: http://www.nic.gh/reg_now.php +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +com.gh +edu.gh +gov.gh +org.gh +mil.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +ltd.gi +gov.gi +mod.gi +edu.gi +org.gi + +// gl : http://en.wikipedia.org/wiki/.gl +// http://nic.gl +gl +co.gl +com.gl +edu.gl +net.gl +org.gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry 2008-06-17 +gn +ac.gn +com.gn +edu.gn +gov.gn +org.gn +net.gn + +// gov : http://en.wikipedia.org/wiki/.gov +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +com.gp +net.gp +mobi.gp +edu.gp +org.gp +asso.gp + +// gq : http://en.wikipedia.org/wiki/.gq +gq + +// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// Submitted by registry 2008-06-09 +gr +com.gr +edu.gr +net.gr +org.gr +gov.gr + +// gs : http://en.wikipedia.org/wiki/.gs +gs + +// gt : http://www.gt/politicas_de_registro.html +gt +com.gt +edu.gt +gob.gt +ind.gt +mil.gt +net.gt +org.gt + +// gu : http://gadao.gov.gu/registration.txt +*.gu + +// gw : http://en.wikipedia.org/wiki/.gw +gw + +// gy : http://en.wikipedia.org/wiki/.gy +// http://registry.gy/ +gy +co.gy +com.gy +net.gy + +// hk : https://www.hkdnr.hk +// Submitted by registry 2008-06-11 +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +公司.hk +教育.hk +敎育.hk +政府.hk +個人.hk +个人.hk +箇人.hk +網络.hk +网络.hk +组織.hk +網絡.hk +网絡.hk +组织.hk +組織.hk +組织.hk + +// hm : http://en.wikipedia.org/wiki/.hm +hm + +// hn : http://www.nic.hn/politicas/ps02,,05.html +hn +com.hn +edu.hn +org.hn +net.hn +mil.hn +gob.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +iz.hr +from.hr +name.hr +com.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +com.ht +shop.ht +firm.ht +info.ht +adult.ht +net.ht +pro.ht +org.ht +med.ht +art.ht +coop.ht +pol.ht +asso.ht +edu.ht +rel.ht +gouv.ht +perso.ht + +// hu : http://www.domain.hu/domain/English/sld.html +// Confirmed by registry 2008-06-12 +hu +co.hu +info.hu +org.hu +priv.hu +sport.hu +tm.hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +reklam.hu +sex.hu +shop.hu +suli.hu +szex.hu +tozsde.hu +utazas.hu +video.hu + +// id : https://register.pandi.or.id/ +id +ac.id +biz.id +co.id +desa.id +go.id +mil.id +my.id +net.id +or.id +sch.id +web.id + +// ie : http://en.wikipedia.org/wiki/.ie +ie +gov.ie + +// il : http://en.wikipedia.org/wiki/.il +*.il + +// im : https://www.nic.im/ +// Submitted by registry 2013-11-15 +im +ac.im +co.im +com.im +ltd.co.im +net.im +org.im +plc.co.im +tt.im +tv.im + +// in : http://en.wikipedia.org/wiki/.in +// see also: https://registry.in/Policies +// Please note, that nic.in is not an offical eTLD, but used by most +// government institutions. +in +co.in +firm.in +net.in +org.in +gen.in +ind.in +nic.in +ac.in +edu.in +res.in +gov.in +mil.in + +// info : http://en.wikipedia.org/wiki/.info +info + +// int : http://en.wikipedia.org/wiki/.int +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.html +// list of other 2nd level tlds ? +io +com.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +gov.iq +edu.iq +mil.iq +com.iq +org.iq +net.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2008-12-06 +is +net.is +com.is +edu.is +gov.is +org.is +int.is + +// it : http://en.wikipedia.org/wiki/.it +it +gov.it +edu.it +// Reserved geo-names: +// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf +// There is also a list of reserved geo-names corresponding to Italian municipalities +// http://www.nic.it/documenti/appendice-c.pdf, but it is not included here. +// Regions +abr.it +abruzzo.it +aosta-valley.it +aostavalley.it +bas.it +basilicata.it +cal.it +calabria.it +cam.it +campania.it +emilia-romagna.it +emiliaromagna.it +emr.it +friuli-v-giulia.it +friuli-ve-giulia.it +friuli-vegiulia.it +friuli-venezia-giulia.it +friuli-veneziagiulia.it +friuli-vgiulia.it +friuliv-giulia.it +friulive-giulia.it +friulivegiulia.it +friulivenezia-giulia.it +friuliveneziagiulia.it +friulivgiulia.it +fvg.it +laz.it +lazio.it +lig.it +liguria.it +lom.it +lombardia.it +lombardy.it +lucania.it +mar.it +marche.it +mol.it +molise.it +piedmont.it +piemonte.it +pmn.it +pug.it +puglia.it +sar.it +sardegna.it +sardinia.it +sic.it +sicilia.it +sicily.it +taa.it +tos.it +toscana.it +trentino-a-adige.it +trentino-aadige.it +trentino-alto-adige.it +trentino-altoadige.it +trentino-s-tirol.it +trentino-stirol.it +trentino-sud-tirol.it +trentino-sudtirol.it +trentino-sued-tirol.it +trentino-suedtirol.it +trentinoa-adige.it +trentinoaadige.it +trentinoalto-adige.it +trentinoaltoadige.it +trentinos-tirol.it +trentinostirol.it +trentinosud-tirol.it +trentinosudtirol.it +trentinosued-tirol.it +trentinosuedtirol.it +tuscany.it +umb.it +umbria.it +val-d-aosta.it +val-daosta.it +vald-aosta.it +valdaosta.it +valle-aosta.it +valle-d-aosta.it +valle-daosta.it +valleaosta.it +valled-aosta.it +valledaosta.it +vallee-aoste.it +valleeaoste.it +vao.it +vda.it +ven.it +veneto.it +// Provinces +ag.it +agrigento.it +al.it +alessandria.it +alto-adige.it +altoadige.it +an.it +ancona.it +andria-barletta-trani.it +andria-trani-barletta.it +andriabarlettatrani.it +andriatranibarletta.it +ao.it +aosta.it +aoste.it +ap.it +aq.it +aquila.it +ar.it +arezzo.it +ascoli-piceno.it +ascolipiceno.it +asti.it +at.it +av.it +avellino.it +ba.it +balsan.it +bari.it +barletta-trani-andria.it +barlettatraniandria.it +belluno.it +benevento.it +bergamo.it +bg.it +bi.it +biella.it +bl.it +bn.it +bo.it +bologna.it +bolzano.it +bozen.it +br.it +brescia.it +brindisi.it +bs.it +bt.it +bz.it +ca.it +cagliari.it +caltanissetta.it +campidano-medio.it +campidanomedio.it +campobasso.it +carbonia-iglesias.it +carboniaiglesias.it +carrara-massa.it +carraramassa.it +caserta.it +catania.it +catanzaro.it +cb.it +ce.it +cesena-forli.it +cesenaforli.it +ch.it +chieti.it +ci.it +cl.it +cn.it +co.it +como.it +cosenza.it +cr.it +cremona.it +crotone.it +cs.it +ct.it +cuneo.it +cz.it +dell-ogliastra.it +dellogliastra.it +en.it +enna.it +fc.it +fe.it +fermo.it +ferrara.it +fg.it +fi.it +firenze.it +florence.it +fm.it +foggia.it +forli-cesena.it +forlicesena.it +fr.it +frosinone.it +ge.it +genoa.it +genova.it +go.it +gorizia.it +gr.it +grosseto.it +iglesias-carbonia.it +iglesiascarbonia.it +im.it +imperia.it +is.it +isernia.it +kr.it +la-spezia.it +laquila.it +laspezia.it +latina.it +lc.it +le.it +lecce.it +lecco.it +li.it +livorno.it +lo.it +lodi.it +lt.it +lu.it +lucca.it +macerata.it +mantova.it +massa-carrara.it +massacarrara.it +matera.it +mb.it +mc.it +me.it +medio-campidano.it +mediocampidano.it +messina.it +mi.it +milan.it +milano.it +mn.it +mo.it +modena.it +monza-brianza.it +monza-e-della-brianza.it +monza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +ms.it +mt.it +na.it +naples.it +napoli.it +no.it +novara.it +nu.it +nuoro.it +og.it +ogliastra.it +olbia-tempio.it +olbiatempio.it +or.it +oristano.it +ot.it +pa.it +padova.it +padua.it +palermo.it +parma.it +pavia.it +pc.it +pd.it +pe.it +perugia.it +pesaro-urbino.it +pesarourbino.it +pescara.it +pg.it +pi.it +piacenza.it +pisa.it +pistoia.it +pn.it +po.it +pordenone.it +potenza.it +pr.it +prato.it +pt.it +pu.it +pv.it +pz.it +ra.it +ragusa.it +ravenna.it +rc.it +re.it +reggio-calabria.it +reggio-emilia.it +reggiocalabria.it +reggioemilia.it +rg.it +ri.it +rieti.it +rimini.it +rm.it +rn.it +ro.it +roma.it +rome.it +rovigo.it +sa.it +salerno.it +sassari.it +savona.it +si.it +siena.it +siracusa.it +so.it +sondrio.it +sp.it +sr.it +ss.it +suedtirol.it +sv.it +ta.it +taranto.it +te.it +tempio-olbia.it +tempioolbia.it +teramo.it +terni.it +tn.it +to.it +torino.it +tp.it +tr.it +trani-andria-barletta.it +trani-barletta-andria.it +traniandriabarletta.it +tranibarlettaandria.it +trapani.it +trentino.it +trento.it +treviso.it +trieste.it +ts.it +turin.it +tv.it +ud.it +udine.it +urbino-pesaro.it +urbinopesaro.it +va.it +varese.it +vb.it +vc.it +ve.it +venezia.it +venice.it +verbania.it +vercelli.it +verona.it +vi.it +vibo-valentia.it +vibovalentia.it +vicenza.it +viterbo.it +vr.it +vs.it +vt.it +vv.it + +// je : http://www.channelisles.net/register-domains/ +// Confirmed by registry 2013-11-28 +je +co.je +net.je +org.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : http://www.dns.jo/Registration_policy.aspx +jo +com.jo +org.jo +net.jo +edu.jo +sch.jo +gov.jo +mil.jo +name.jo + +// jobs : http://en.wikipedia.org/wiki/.jobs +jobs + +// jp : http://en.wikipedia.org/wiki/.jp +// http://jprs.co.jp/en/jpdomain.html +// Submitted by registry 2014-10-30 +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp prefecture type names +aichi.jp +akita.jp +aomori.jp +chiba.jp +ehime.jp +fukui.jp +fukuoka.jp +fukushima.jp +gifu.jp +gunma.jp +hiroshima.jp +hokkaido.jp +hyogo.jp +ibaraki.jp +ishikawa.jp +iwate.jp +kagawa.jp +kagoshima.jp +kanagawa.jp +kochi.jp +kumamoto.jp +kyoto.jp +mie.jp +miyagi.jp +miyazaki.jp +nagano.jp +nagasaki.jp +nara.jp +niigata.jp +oita.jp +okayama.jp +okinawa.jp +osaka.jp +saga.jp +saitama.jp +shiga.jp +shimane.jp +shizuoka.jp +tochigi.jp +tokushima.jp +tokyo.jp +tottori.jp +toyama.jp +wakayama.jp +yamagata.jp +yamaguchi.jp +yamanashi.jp +栃木.jp +愛知.jp +愛媛.jp +兵庫.jp +熊本.jp +茨城.jp +北海道.jp +千葉.jp +和歌山.jp +長崎.jp +長野.jp +新潟.jp +青森.jp +静岡.jp +東京.jp +石川.jp +埼玉.jp +三重.jp +京都.jp +佐賀.jp +大分.jp +大阪.jp +奈良.jp +宮城.jp +宮崎.jp +富山.jp +山口.jp +山形.jp +山梨.jp +岩手.jp +岐阜.jp +岡山.jp +島根.jp +広島.jp +徳島.jp +沖縄.jp +滋賀.jp +神奈川.jp +福井.jp +福岡.jp +福島.jp +秋田.jp +群馬.jp +香川.jp +高知.jp +鳥取.jp +鹿児島.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +*.kawasaki.jp +*.kitakyushu.jp +*.kobe.jp +*.nagoya.jp +*.sapporo.jp +*.sendai.jp +*.yokohama.jp +!city.kawasaki.jp +!city.kitakyushu.jp +!city.kobe.jp +!city.nagoya.jp +!city.sapporo.jp +!city.sendai.jp +!city.yokohama.jp +// 4th level registration +aisai.aichi.jp +ama.aichi.jp +anjo.aichi.jp +asuke.aichi.jp +chiryu.aichi.jp +chita.aichi.jp +fuso.aichi.jp +gamagori.aichi.jp +handa.aichi.jp +hazu.aichi.jp +hekinan.aichi.jp +higashiura.aichi.jp +ichinomiya.aichi.jp +inazawa.aichi.jp +inuyama.aichi.jp +isshiki.aichi.jp +iwakura.aichi.jp +kanie.aichi.jp +kariya.aichi.jp +kasugai.aichi.jp +kira.aichi.jp +kiyosu.aichi.jp +komaki.aichi.jp +konan.aichi.jp +kota.aichi.jp +mihama.aichi.jp +miyoshi.aichi.jp +nishio.aichi.jp +nisshin.aichi.jp +obu.aichi.jp +oguchi.aichi.jp +oharu.aichi.jp +okazaki.aichi.jp +owariasahi.aichi.jp +seto.aichi.jp +shikatsu.aichi.jp +shinshiro.aichi.jp +shitara.aichi.jp +tahara.aichi.jp +takahama.aichi.jp +tobishima.aichi.jp +toei.aichi.jp +togo.aichi.jp +tokai.aichi.jp +tokoname.aichi.jp +toyoake.aichi.jp +toyohashi.aichi.jp +toyokawa.aichi.jp +toyone.aichi.jp +toyota.aichi.jp +tsushima.aichi.jp +yatomi.aichi.jp +akita.akita.jp +daisen.akita.jp +fujisato.akita.jp +gojome.akita.jp +hachirogata.akita.jp +happou.akita.jp +higashinaruse.akita.jp +honjo.akita.jp +honjyo.akita.jp +ikawa.akita.jp +kamikoani.akita.jp +kamioka.akita.jp +katagami.akita.jp +kazuno.akita.jp +kitaakita.akita.jp +kosaka.akita.jp +kyowa.akita.jp +misato.akita.jp +mitane.akita.jp +moriyoshi.akita.jp +nikaho.akita.jp +noshiro.akita.jp +odate.akita.jp +oga.akita.jp +ogata.akita.jp +semboku.akita.jp +yokote.akita.jp +yurihonjo.akita.jp +aomori.aomori.jp +gonohe.aomori.jp +hachinohe.aomori.jp +hashikami.aomori.jp +hiranai.aomori.jp +hirosaki.aomori.jp +itayanagi.aomori.jp +kuroishi.aomori.jp +misawa.aomori.jp +mutsu.aomori.jp +nakadomari.aomori.jp +noheji.aomori.jp +oirase.aomori.jp +owani.aomori.jp +rokunohe.aomori.jp +sannohe.aomori.jp +shichinohe.aomori.jp +shingo.aomori.jp +takko.aomori.jp +towada.aomori.jp +tsugaru.aomori.jp +tsuruta.aomori.jp +abiko.chiba.jp +asahi.chiba.jp +chonan.chiba.jp +chosei.chiba.jp +choshi.chiba.jp +chuo.chiba.jp +funabashi.chiba.jp +futtsu.chiba.jp +hanamigawa.chiba.jp +ichihara.chiba.jp +ichikawa.chiba.jp +ichinomiya.chiba.jp +inzai.chiba.jp +isumi.chiba.jp +kamagaya.chiba.jp +kamogawa.chiba.jp +kashiwa.chiba.jp +katori.chiba.jp +katsuura.chiba.jp +kimitsu.chiba.jp +kisarazu.chiba.jp +kozaki.chiba.jp +kujukuri.chiba.jp +kyonan.chiba.jp +matsudo.chiba.jp +midori.chiba.jp +mihama.chiba.jp +minamiboso.chiba.jp +mobara.chiba.jp +mutsuzawa.chiba.jp +nagara.chiba.jp +nagareyama.chiba.jp +narashino.chiba.jp +narita.chiba.jp +noda.chiba.jp +oamishirasato.chiba.jp +omigawa.chiba.jp +onjuku.chiba.jp +otaki.chiba.jp +sakae.chiba.jp +sakura.chiba.jp +shimofusa.chiba.jp +shirako.chiba.jp +shiroi.chiba.jp +shisui.chiba.jp +sodegaura.chiba.jp +sosa.chiba.jp +tako.chiba.jp +tateyama.chiba.jp +togane.chiba.jp +tohnosho.chiba.jp +tomisato.chiba.jp +urayasu.chiba.jp +yachimata.chiba.jp +yachiyo.chiba.jp +yokaichiba.chiba.jp +yokoshibahikari.chiba.jp +yotsukaido.chiba.jp +ainan.ehime.jp +honai.ehime.jp +ikata.ehime.jp +imabari.ehime.jp +iyo.ehime.jp +kamijima.ehime.jp +kihoku.ehime.jp +kumakogen.ehime.jp +masaki.ehime.jp +matsuno.ehime.jp +matsuyama.ehime.jp +namikata.ehime.jp +niihama.ehime.jp +ozu.ehime.jp +saijo.ehime.jp +seiyo.ehime.jp +shikokuchuo.ehime.jp +tobe.ehime.jp +toon.ehime.jp +uchiko.ehime.jp +uwajima.ehime.jp +yawatahama.ehime.jp +echizen.fukui.jp +eiheiji.fukui.jp +fukui.fukui.jp +ikeda.fukui.jp +katsuyama.fukui.jp +mihama.fukui.jp +minamiechizen.fukui.jp +obama.fukui.jp +ohi.fukui.jp +ono.fukui.jp +sabae.fukui.jp +sakai.fukui.jp +takahama.fukui.jp +tsuruga.fukui.jp +wakasa.fukui.jp +ashiya.fukuoka.jp +buzen.fukuoka.jp +chikugo.fukuoka.jp +chikuho.fukuoka.jp +chikujo.fukuoka.jp +chikushino.fukuoka.jp +chikuzen.fukuoka.jp +chuo.fukuoka.jp +dazaifu.fukuoka.jp +fukuchi.fukuoka.jp +hakata.fukuoka.jp +higashi.fukuoka.jp +hirokawa.fukuoka.jp +hisayama.fukuoka.jp +iizuka.fukuoka.jp +inatsuki.fukuoka.jp +kaho.fukuoka.jp +kasuga.fukuoka.jp +kasuya.fukuoka.jp +kawara.fukuoka.jp +keisen.fukuoka.jp +koga.fukuoka.jp +kurate.fukuoka.jp +kurogi.fukuoka.jp +kurume.fukuoka.jp +minami.fukuoka.jp +miyako.fukuoka.jp +miyama.fukuoka.jp +miyawaka.fukuoka.jp +mizumaki.fukuoka.jp +munakata.fukuoka.jp +nakagawa.fukuoka.jp +nakama.fukuoka.jp +nishi.fukuoka.jp +nogata.fukuoka.jp +ogori.fukuoka.jp +okagaki.fukuoka.jp +okawa.fukuoka.jp +oki.fukuoka.jp +omuta.fukuoka.jp +onga.fukuoka.jp +onojo.fukuoka.jp +oto.fukuoka.jp +saigawa.fukuoka.jp +sasaguri.fukuoka.jp +shingu.fukuoka.jp +shinyoshitomi.fukuoka.jp +shonai.fukuoka.jp +soeda.fukuoka.jp +sue.fukuoka.jp +tachiarai.fukuoka.jp +tagawa.fukuoka.jp +takata.fukuoka.jp +toho.fukuoka.jp +toyotsu.fukuoka.jp +tsuiki.fukuoka.jp +ukiha.fukuoka.jp +umi.fukuoka.jp +usui.fukuoka.jp +yamada.fukuoka.jp +yame.fukuoka.jp +yanagawa.fukuoka.jp +yukuhashi.fukuoka.jp +aizubange.fukushima.jp +aizumisato.fukushima.jp +aizuwakamatsu.fukushima.jp +asakawa.fukushima.jp +bandai.fukushima.jp +date.fukushima.jp +fukushima.fukushima.jp +furudono.fukushima.jp +futaba.fukushima.jp +hanawa.fukushima.jp +higashi.fukushima.jp +hirata.fukushima.jp +hirono.fukushima.jp +iitate.fukushima.jp +inawashiro.fukushima.jp +ishikawa.fukushima.jp +iwaki.fukushima.jp +izumizaki.fukushima.jp +kagamiishi.fukushima.jp +kaneyama.fukushima.jp +kawamata.fukushima.jp +kitakata.fukushima.jp +kitashiobara.fukushima.jp +koori.fukushima.jp +koriyama.fukushima.jp +kunimi.fukushima.jp +miharu.fukushima.jp +mishima.fukushima.jp +namie.fukushima.jp +nango.fukushima.jp +nishiaizu.fukushima.jp +nishigo.fukushima.jp +okuma.fukushima.jp +omotego.fukushima.jp +ono.fukushima.jp +otama.fukushima.jp +samegawa.fukushima.jp +shimogo.fukushima.jp +shirakawa.fukushima.jp +showa.fukushima.jp +soma.fukushima.jp +sukagawa.fukushima.jp +taishin.fukushima.jp +tamakawa.fukushima.jp +tanagura.fukushima.jp +tenei.fukushima.jp +yabuki.fukushima.jp +yamato.fukushima.jp +yamatsuri.fukushima.jp +yanaizu.fukushima.jp +yugawa.fukushima.jp +anpachi.gifu.jp +ena.gifu.jp +gifu.gifu.jp +ginan.gifu.jp +godo.gifu.jp +gujo.gifu.jp +hashima.gifu.jp +hichiso.gifu.jp +hida.gifu.jp +higashishirakawa.gifu.jp +ibigawa.gifu.jp +ikeda.gifu.jp +kakamigahara.gifu.jp +kani.gifu.jp +kasahara.gifu.jp +kasamatsu.gifu.jp +kawaue.gifu.jp +kitagata.gifu.jp +mino.gifu.jp +minokamo.gifu.jp +mitake.gifu.jp +mizunami.gifu.jp +motosu.gifu.jp +nakatsugawa.gifu.jp +ogaki.gifu.jp +sakahogi.gifu.jp +seki.gifu.jp +sekigahara.gifu.jp +shirakawa.gifu.jp +tajimi.gifu.jp +takayama.gifu.jp +tarui.gifu.jp +toki.gifu.jp +tomika.gifu.jp +wanouchi.gifu.jp +yamagata.gifu.jp +yaotsu.gifu.jp +yoro.gifu.jp +annaka.gunma.jp +chiyoda.gunma.jp +fujioka.gunma.jp +higashiagatsuma.gunma.jp +isesaki.gunma.jp +itakura.gunma.jp +kanna.gunma.jp +kanra.gunma.jp +katashina.gunma.jp +kawaba.gunma.jp +kiryu.gunma.jp +kusatsu.gunma.jp +maebashi.gunma.jp +meiwa.gunma.jp +midori.gunma.jp +minakami.gunma.jp +naganohara.gunma.jp +nakanojo.gunma.jp +nanmoku.gunma.jp +numata.gunma.jp +oizumi.gunma.jp +ora.gunma.jp +ota.gunma.jp +shibukawa.gunma.jp +shimonita.gunma.jp +shinto.gunma.jp +showa.gunma.jp +takasaki.gunma.jp +takayama.gunma.jp +tamamura.gunma.jp +tatebayashi.gunma.jp +tomioka.gunma.jp +tsukiyono.gunma.jp +tsumagoi.gunma.jp +ueno.gunma.jp +yoshioka.gunma.jp +asaminami.hiroshima.jp +daiwa.hiroshima.jp +etajima.hiroshima.jp +fuchu.hiroshima.jp +fukuyama.hiroshima.jp +hatsukaichi.hiroshima.jp +higashihiroshima.hiroshima.jp +hongo.hiroshima.jp +jinsekikogen.hiroshima.jp +kaita.hiroshima.jp +kui.hiroshima.jp +kumano.hiroshima.jp +kure.hiroshima.jp +mihara.hiroshima.jp +miyoshi.hiroshima.jp +naka.hiroshima.jp +onomichi.hiroshima.jp +osakikamijima.hiroshima.jp +otake.hiroshima.jp +saka.hiroshima.jp +sera.hiroshima.jp +seranishi.hiroshima.jp +shinichi.hiroshima.jp +shobara.hiroshima.jp +takehara.hiroshima.jp +abashiri.hokkaido.jp +abira.hokkaido.jp +aibetsu.hokkaido.jp +akabira.hokkaido.jp +akkeshi.hokkaido.jp +asahikawa.hokkaido.jp +ashibetsu.hokkaido.jp +ashoro.hokkaido.jp +assabu.hokkaido.jp +atsuma.hokkaido.jp +bibai.hokkaido.jp +biei.hokkaido.jp +bifuka.hokkaido.jp +bihoro.hokkaido.jp +biratori.hokkaido.jp +chippubetsu.hokkaido.jp +chitose.hokkaido.jp +date.hokkaido.jp +ebetsu.hokkaido.jp +embetsu.hokkaido.jp +eniwa.hokkaido.jp +erimo.hokkaido.jp +esan.hokkaido.jp +esashi.hokkaido.jp +fukagawa.hokkaido.jp +fukushima.hokkaido.jp +furano.hokkaido.jp +furubira.hokkaido.jp +haboro.hokkaido.jp +hakodate.hokkaido.jp +hamatonbetsu.hokkaido.jp +hidaka.hokkaido.jp +higashikagura.hokkaido.jp +higashikawa.hokkaido.jp +hiroo.hokkaido.jp +hokuryu.hokkaido.jp +hokuto.hokkaido.jp +honbetsu.hokkaido.jp +horokanai.hokkaido.jp +horonobe.hokkaido.jp +ikeda.hokkaido.jp +imakane.hokkaido.jp +ishikari.hokkaido.jp +iwamizawa.hokkaido.jp +iwanai.hokkaido.jp +kamifurano.hokkaido.jp +kamikawa.hokkaido.jp +kamishihoro.hokkaido.jp +kamisunagawa.hokkaido.jp +kamoenai.hokkaido.jp +kayabe.hokkaido.jp +kembuchi.hokkaido.jp +kikonai.hokkaido.jp +kimobetsu.hokkaido.jp +kitahiroshima.hokkaido.jp +kitami.hokkaido.jp +kiyosato.hokkaido.jp +koshimizu.hokkaido.jp +kunneppu.hokkaido.jp +kuriyama.hokkaido.jp +kuromatsunai.hokkaido.jp +kushiro.hokkaido.jp +kutchan.hokkaido.jp +kyowa.hokkaido.jp +mashike.hokkaido.jp +matsumae.hokkaido.jp +mikasa.hokkaido.jp +minamifurano.hokkaido.jp +mombetsu.hokkaido.jp +moseushi.hokkaido.jp +mukawa.hokkaido.jp +muroran.hokkaido.jp +naie.hokkaido.jp +nakagawa.hokkaido.jp +nakasatsunai.hokkaido.jp +nakatombetsu.hokkaido.jp +nanae.hokkaido.jp +nanporo.hokkaido.jp +nayoro.hokkaido.jp +nemuro.hokkaido.jp +niikappu.hokkaido.jp +niki.hokkaido.jp +nishiokoppe.hokkaido.jp +noboribetsu.hokkaido.jp +numata.hokkaido.jp +obihiro.hokkaido.jp +obira.hokkaido.jp +oketo.hokkaido.jp +okoppe.hokkaido.jp +otaru.hokkaido.jp +otobe.hokkaido.jp +otofuke.hokkaido.jp +otoineppu.hokkaido.jp +oumu.hokkaido.jp +ozora.hokkaido.jp +pippu.hokkaido.jp +rankoshi.hokkaido.jp +rebun.hokkaido.jp +rikubetsu.hokkaido.jp +rishiri.hokkaido.jp +rishirifuji.hokkaido.jp +saroma.hokkaido.jp +sarufutsu.hokkaido.jp +shakotan.hokkaido.jp +shari.hokkaido.jp +shibecha.hokkaido.jp +shibetsu.hokkaido.jp +shikabe.hokkaido.jp +shikaoi.hokkaido.jp +shimamaki.hokkaido.jp +shimizu.hokkaido.jp +shimokawa.hokkaido.jp +shinshinotsu.hokkaido.jp +shintoku.hokkaido.jp +shiranuka.hokkaido.jp +shiraoi.hokkaido.jp +shiriuchi.hokkaido.jp +sobetsu.hokkaido.jp +sunagawa.hokkaido.jp +taiki.hokkaido.jp +takasu.hokkaido.jp +takikawa.hokkaido.jp +takinoue.hokkaido.jp +teshikaga.hokkaido.jp +tobetsu.hokkaido.jp +tohma.hokkaido.jp +tomakomai.hokkaido.jp +tomari.hokkaido.jp +toya.hokkaido.jp +toyako.hokkaido.jp +toyotomi.hokkaido.jp +toyoura.hokkaido.jp +tsubetsu.hokkaido.jp +tsukigata.hokkaido.jp +urakawa.hokkaido.jp +urausu.hokkaido.jp +uryu.hokkaido.jp +utashinai.hokkaido.jp +wakkanai.hokkaido.jp +wassamu.hokkaido.jp +yakumo.hokkaido.jp +yoichi.hokkaido.jp +aioi.hyogo.jp +akashi.hyogo.jp +ako.hyogo.jp +amagasaki.hyogo.jp +aogaki.hyogo.jp +asago.hyogo.jp +ashiya.hyogo.jp +awaji.hyogo.jp +fukusaki.hyogo.jp +goshiki.hyogo.jp +harima.hyogo.jp +himeji.hyogo.jp +ichikawa.hyogo.jp +inagawa.hyogo.jp +itami.hyogo.jp +kakogawa.hyogo.jp +kamigori.hyogo.jp +kamikawa.hyogo.jp +kasai.hyogo.jp +kasuga.hyogo.jp +kawanishi.hyogo.jp +miki.hyogo.jp +minamiawaji.hyogo.jp +nishinomiya.hyogo.jp +nishiwaki.hyogo.jp +ono.hyogo.jp +sanda.hyogo.jp +sannan.hyogo.jp +sasayama.hyogo.jp +sayo.hyogo.jp +shingu.hyogo.jp +shinonsen.hyogo.jp +shiso.hyogo.jp +sumoto.hyogo.jp +taishi.hyogo.jp +taka.hyogo.jp +takarazuka.hyogo.jp +takasago.hyogo.jp +takino.hyogo.jp +tamba.hyogo.jp +tatsuno.hyogo.jp +toyooka.hyogo.jp +yabu.hyogo.jp +yashiro.hyogo.jp +yoka.hyogo.jp +yokawa.hyogo.jp +ami.ibaraki.jp +asahi.ibaraki.jp +bando.ibaraki.jp +chikusei.ibaraki.jp +daigo.ibaraki.jp +fujishiro.ibaraki.jp +hitachi.ibaraki.jp +hitachinaka.ibaraki.jp +hitachiomiya.ibaraki.jp +hitachiota.ibaraki.jp +ibaraki.ibaraki.jp +ina.ibaraki.jp +inashiki.ibaraki.jp +itako.ibaraki.jp +iwama.ibaraki.jp +joso.ibaraki.jp +kamisu.ibaraki.jp +kasama.ibaraki.jp +kashima.ibaraki.jp +kasumigaura.ibaraki.jp +koga.ibaraki.jp +miho.ibaraki.jp +mito.ibaraki.jp +moriya.ibaraki.jp +naka.ibaraki.jp +namegata.ibaraki.jp +oarai.ibaraki.jp +ogawa.ibaraki.jp +omitama.ibaraki.jp +ryugasaki.ibaraki.jp +sakai.ibaraki.jp +sakuragawa.ibaraki.jp +shimodate.ibaraki.jp +shimotsuma.ibaraki.jp +shirosato.ibaraki.jp +sowa.ibaraki.jp +suifu.ibaraki.jp +takahagi.ibaraki.jp +tamatsukuri.ibaraki.jp +tokai.ibaraki.jp +tomobe.ibaraki.jp +tone.ibaraki.jp +toride.ibaraki.jp +tsuchiura.ibaraki.jp +tsukuba.ibaraki.jp +uchihara.ibaraki.jp +ushiku.ibaraki.jp +yachiyo.ibaraki.jp +yamagata.ibaraki.jp +yawara.ibaraki.jp +yuki.ibaraki.jp +anamizu.ishikawa.jp +hakui.ishikawa.jp +hakusan.ishikawa.jp +kaga.ishikawa.jp +kahoku.ishikawa.jp +kanazawa.ishikawa.jp +kawakita.ishikawa.jp +komatsu.ishikawa.jp +nakanoto.ishikawa.jp +nanao.ishikawa.jp +nomi.ishikawa.jp +nonoichi.ishikawa.jp +noto.ishikawa.jp +shika.ishikawa.jp +suzu.ishikawa.jp +tsubata.ishikawa.jp +tsurugi.ishikawa.jp +uchinada.ishikawa.jp +wajima.ishikawa.jp +fudai.iwate.jp +fujisawa.iwate.jp +hanamaki.iwate.jp +hiraizumi.iwate.jp +hirono.iwate.jp +ichinohe.iwate.jp +ichinoseki.iwate.jp +iwaizumi.iwate.jp +iwate.iwate.jp +joboji.iwate.jp +kamaishi.iwate.jp +kanegasaki.iwate.jp +karumai.iwate.jp +kawai.iwate.jp +kitakami.iwate.jp +kuji.iwate.jp +kunohe.iwate.jp +kuzumaki.iwate.jp +miyako.iwate.jp +mizusawa.iwate.jp +morioka.iwate.jp +ninohe.iwate.jp +noda.iwate.jp +ofunato.iwate.jp +oshu.iwate.jp +otsuchi.iwate.jp +rikuzentakata.iwate.jp +shiwa.iwate.jp +shizukuishi.iwate.jp +sumita.iwate.jp +tanohata.iwate.jp +tono.iwate.jp +yahaba.iwate.jp +yamada.iwate.jp +ayagawa.kagawa.jp +higashikagawa.kagawa.jp +kanonji.kagawa.jp +kotohira.kagawa.jp +manno.kagawa.jp +marugame.kagawa.jp +mitoyo.kagawa.jp +naoshima.kagawa.jp +sanuki.kagawa.jp +tadotsu.kagawa.jp +takamatsu.kagawa.jp +tonosho.kagawa.jp +uchinomi.kagawa.jp +utazu.kagawa.jp +zentsuji.kagawa.jp +akune.kagoshima.jp +amami.kagoshima.jp +hioki.kagoshima.jp +isa.kagoshima.jp +isen.kagoshima.jp +izumi.kagoshima.jp +kagoshima.kagoshima.jp +kanoya.kagoshima.jp +kawanabe.kagoshima.jp +kinko.kagoshima.jp +kouyama.kagoshima.jp +makurazaki.kagoshima.jp +matsumoto.kagoshima.jp +minamitane.kagoshima.jp +nakatane.kagoshima.jp +nishinoomote.kagoshima.jp +satsumasendai.kagoshima.jp +soo.kagoshima.jp +tarumizu.kagoshima.jp +yusui.kagoshima.jp +aikawa.kanagawa.jp +atsugi.kanagawa.jp +ayase.kanagawa.jp +chigasaki.kanagawa.jp +ebina.kanagawa.jp +fujisawa.kanagawa.jp +hadano.kanagawa.jp +hakone.kanagawa.jp +hiratsuka.kanagawa.jp +isehara.kanagawa.jp +kaisei.kanagawa.jp +kamakura.kanagawa.jp +kiyokawa.kanagawa.jp +matsuda.kanagawa.jp +minamiashigara.kanagawa.jp +miura.kanagawa.jp +nakai.kanagawa.jp +ninomiya.kanagawa.jp +odawara.kanagawa.jp +oi.kanagawa.jp +oiso.kanagawa.jp +sagamihara.kanagawa.jp +samukawa.kanagawa.jp +tsukui.kanagawa.jp +yamakita.kanagawa.jp +yamato.kanagawa.jp +yokosuka.kanagawa.jp +yugawara.kanagawa.jp +zama.kanagawa.jp +zushi.kanagawa.jp +aki.kochi.jp +geisei.kochi.jp +hidaka.kochi.jp +higashitsuno.kochi.jp +ino.kochi.jp +kagami.kochi.jp +kami.kochi.jp +kitagawa.kochi.jp +kochi.kochi.jp +mihara.kochi.jp +motoyama.kochi.jp +muroto.kochi.jp +nahari.kochi.jp +nakamura.kochi.jp +nankoku.kochi.jp +nishitosa.kochi.jp +niyodogawa.kochi.jp +ochi.kochi.jp +okawa.kochi.jp +otoyo.kochi.jp +otsuki.kochi.jp +sakawa.kochi.jp +sukumo.kochi.jp +susaki.kochi.jp +tosa.kochi.jp +tosashimizu.kochi.jp +toyo.kochi.jp +tsuno.kochi.jp +umaji.kochi.jp +yasuda.kochi.jp +yusuhara.kochi.jp +amakusa.kumamoto.jp +arao.kumamoto.jp +aso.kumamoto.jp +choyo.kumamoto.jp +gyokuto.kumamoto.jp +hitoyoshi.kumamoto.jp +kamiamakusa.kumamoto.jp +kashima.kumamoto.jp +kikuchi.kumamoto.jp +kosa.kumamoto.jp +kumamoto.kumamoto.jp +mashiki.kumamoto.jp +mifune.kumamoto.jp +minamata.kumamoto.jp +minamioguni.kumamoto.jp +nagasu.kumamoto.jp +nishihara.kumamoto.jp +oguni.kumamoto.jp +ozu.kumamoto.jp +sumoto.kumamoto.jp +takamori.kumamoto.jp +uki.kumamoto.jp +uto.kumamoto.jp +yamaga.kumamoto.jp +yamato.kumamoto.jp +yatsushiro.kumamoto.jp +ayabe.kyoto.jp +fukuchiyama.kyoto.jp +higashiyama.kyoto.jp +ide.kyoto.jp +ine.kyoto.jp +joyo.kyoto.jp +kameoka.kyoto.jp +kamo.kyoto.jp +kita.kyoto.jp +kizu.kyoto.jp +kumiyama.kyoto.jp +kyotamba.kyoto.jp +kyotanabe.kyoto.jp +kyotango.kyoto.jp +maizuru.kyoto.jp +minami.kyoto.jp +minamiyamashiro.kyoto.jp +miyazu.kyoto.jp +muko.kyoto.jp +nagaokakyo.kyoto.jp +nakagyo.kyoto.jp +nantan.kyoto.jp +oyamazaki.kyoto.jp +sakyo.kyoto.jp +seika.kyoto.jp +tanabe.kyoto.jp +uji.kyoto.jp +ujitawara.kyoto.jp +wazuka.kyoto.jp +yamashina.kyoto.jp +yawata.kyoto.jp +asahi.mie.jp +inabe.mie.jp +ise.mie.jp +kameyama.mie.jp +kawagoe.mie.jp +kiho.mie.jp +kisosaki.mie.jp +kiwa.mie.jp +komono.mie.jp +kumano.mie.jp +kuwana.mie.jp +matsusaka.mie.jp +meiwa.mie.jp +mihama.mie.jp +minamiise.mie.jp +misugi.mie.jp +miyama.mie.jp +nabari.mie.jp +shima.mie.jp +suzuka.mie.jp +tado.mie.jp +taiki.mie.jp +taki.mie.jp +tamaki.mie.jp +toba.mie.jp +tsu.mie.jp +udono.mie.jp +ureshino.mie.jp +watarai.mie.jp +yokkaichi.mie.jp +furukawa.miyagi.jp +higashimatsushima.miyagi.jp +ishinomaki.miyagi.jp +iwanuma.miyagi.jp +kakuda.miyagi.jp +kami.miyagi.jp +kawasaki.miyagi.jp +kesennuma.miyagi.jp +marumori.miyagi.jp +matsushima.miyagi.jp +minamisanriku.miyagi.jp +misato.miyagi.jp +murata.miyagi.jp +natori.miyagi.jp +ogawara.miyagi.jp +ohira.miyagi.jp +onagawa.miyagi.jp +osaki.miyagi.jp +rifu.miyagi.jp +semine.miyagi.jp +shibata.miyagi.jp +shichikashuku.miyagi.jp +shikama.miyagi.jp +shiogama.miyagi.jp +shiroishi.miyagi.jp +tagajo.miyagi.jp +taiwa.miyagi.jp +tome.miyagi.jp +tomiya.miyagi.jp +wakuya.miyagi.jp +watari.miyagi.jp +yamamoto.miyagi.jp +zao.miyagi.jp +aya.miyazaki.jp +ebino.miyazaki.jp +gokase.miyazaki.jp +hyuga.miyazaki.jp +kadogawa.miyazaki.jp +kawaminami.miyazaki.jp +kijo.miyazaki.jp +kitagawa.miyazaki.jp +kitakata.miyazaki.jp +kitaura.miyazaki.jp +kobayashi.miyazaki.jp +kunitomi.miyazaki.jp +kushima.miyazaki.jp +mimata.miyazaki.jp +miyakonojo.miyazaki.jp +miyazaki.miyazaki.jp +morotsuka.miyazaki.jp +nichinan.miyazaki.jp +nishimera.miyazaki.jp +nobeoka.miyazaki.jp +saito.miyazaki.jp +shiiba.miyazaki.jp +shintomi.miyazaki.jp +takaharu.miyazaki.jp +takanabe.miyazaki.jp +takazaki.miyazaki.jp +tsuno.miyazaki.jp +achi.nagano.jp +agematsu.nagano.jp +anan.nagano.jp +aoki.nagano.jp +asahi.nagano.jp +azumino.nagano.jp +chikuhoku.nagano.jp +chikuma.nagano.jp +chino.nagano.jp +fujimi.nagano.jp +hakuba.nagano.jp +hara.nagano.jp +hiraya.nagano.jp +iida.nagano.jp +iijima.nagano.jp +iiyama.nagano.jp +iizuna.nagano.jp +ikeda.nagano.jp +ikusaka.nagano.jp +ina.nagano.jp +karuizawa.nagano.jp +kawakami.nagano.jp +kiso.nagano.jp +kisofukushima.nagano.jp +kitaaiki.nagano.jp +komagane.nagano.jp +komoro.nagano.jp +matsukawa.nagano.jp +matsumoto.nagano.jp +miasa.nagano.jp +minamiaiki.nagano.jp +minamimaki.nagano.jp +minamiminowa.nagano.jp +minowa.nagano.jp +miyada.nagano.jp +miyota.nagano.jp +mochizuki.nagano.jp +nagano.nagano.jp +nagawa.nagano.jp +nagiso.nagano.jp +nakagawa.nagano.jp +nakano.nagano.jp +nozawaonsen.nagano.jp +obuse.nagano.jp +ogawa.nagano.jp +okaya.nagano.jp +omachi.nagano.jp +omi.nagano.jp +ookuwa.nagano.jp +ooshika.nagano.jp +otaki.nagano.jp +otari.nagano.jp +sakae.nagano.jp +sakaki.nagano.jp +saku.nagano.jp +sakuho.nagano.jp +shimosuwa.nagano.jp +shinanomachi.nagano.jp +shiojiri.nagano.jp +suwa.nagano.jp +suzaka.nagano.jp +takagi.nagano.jp +takamori.nagano.jp +takayama.nagano.jp +tateshina.nagano.jp +tatsuno.nagano.jp +togakushi.nagano.jp +togura.nagano.jp +tomi.nagano.jp +ueda.nagano.jp +wada.nagano.jp +yamagata.nagano.jp +yamanouchi.nagano.jp +yasaka.nagano.jp +yasuoka.nagano.jp +chijiwa.nagasaki.jp +futsu.nagasaki.jp +goto.nagasaki.jp +hasami.nagasaki.jp +hirado.nagasaki.jp +iki.nagasaki.jp +isahaya.nagasaki.jp +kawatana.nagasaki.jp +kuchinotsu.nagasaki.jp +matsuura.nagasaki.jp +nagasaki.nagasaki.jp +obama.nagasaki.jp +omura.nagasaki.jp +oseto.nagasaki.jp +saikai.nagasaki.jp +sasebo.nagasaki.jp +seihi.nagasaki.jp +shimabara.nagasaki.jp +shinkamigoto.nagasaki.jp +togitsu.nagasaki.jp +tsushima.nagasaki.jp +unzen.nagasaki.jp +ando.nara.jp +gose.nara.jp +heguri.nara.jp +higashiyoshino.nara.jp +ikaruga.nara.jp +ikoma.nara.jp +kamikitayama.nara.jp +kanmaki.nara.jp +kashiba.nara.jp +kashihara.nara.jp +katsuragi.nara.jp +kawai.nara.jp +kawakami.nara.jp +kawanishi.nara.jp +koryo.nara.jp +kurotaki.nara.jp +mitsue.nara.jp +miyake.nara.jp +nara.nara.jp +nosegawa.nara.jp +oji.nara.jp +ouda.nara.jp +oyodo.nara.jp +sakurai.nara.jp +sango.nara.jp +shimoichi.nara.jp +shimokitayama.nara.jp +shinjo.nara.jp +soni.nara.jp +takatori.nara.jp +tawaramoto.nara.jp +tenkawa.nara.jp +tenri.nara.jp +uda.nara.jp +yamatokoriyama.nara.jp +yamatotakada.nara.jp +yamazoe.nara.jp +yoshino.nara.jp +aga.niigata.jp +agano.niigata.jp +gosen.niigata.jp +itoigawa.niigata.jp +izumozaki.niigata.jp +joetsu.niigata.jp +kamo.niigata.jp +kariwa.niigata.jp +kashiwazaki.niigata.jp +minamiuonuma.niigata.jp +mitsuke.niigata.jp +muika.niigata.jp +murakami.niigata.jp +myoko.niigata.jp +nagaoka.niigata.jp +niigata.niigata.jp +ojiya.niigata.jp +omi.niigata.jp +sado.niigata.jp +sanjo.niigata.jp +seiro.niigata.jp +seirou.niigata.jp +sekikawa.niigata.jp +shibata.niigata.jp +tagami.niigata.jp +tainai.niigata.jp +tochio.niigata.jp +tokamachi.niigata.jp +tsubame.niigata.jp +tsunan.niigata.jp +uonuma.niigata.jp +yahiko.niigata.jp +yoita.niigata.jp +yuzawa.niigata.jp +beppu.oita.jp +bungoono.oita.jp +bungotakada.oita.jp +hasama.oita.jp +hiji.oita.jp +himeshima.oita.jp +hita.oita.jp +kamitsue.oita.jp +kokonoe.oita.jp +kuju.oita.jp +kunisaki.oita.jp +kusu.oita.jp +oita.oita.jp +saiki.oita.jp +taketa.oita.jp +tsukumi.oita.jp +usa.oita.jp +usuki.oita.jp +yufu.oita.jp +akaiwa.okayama.jp +asakuchi.okayama.jp +bizen.okayama.jp +hayashima.okayama.jp +ibara.okayama.jp +kagamino.okayama.jp +kasaoka.okayama.jp +kibichuo.okayama.jp +kumenan.okayama.jp +kurashiki.okayama.jp +maniwa.okayama.jp +misaki.okayama.jp +nagi.okayama.jp +niimi.okayama.jp +nishiawakura.okayama.jp +okayama.okayama.jp +satosho.okayama.jp +setouchi.okayama.jp +shinjo.okayama.jp +shoo.okayama.jp +soja.okayama.jp +takahashi.okayama.jp +tamano.okayama.jp +tsuyama.okayama.jp +wake.okayama.jp +yakage.okayama.jp +aguni.okinawa.jp +ginowan.okinawa.jp +ginoza.okinawa.jp +gushikami.okinawa.jp +haebaru.okinawa.jp +higashi.okinawa.jp +hirara.okinawa.jp +iheya.okinawa.jp +ishigaki.okinawa.jp +ishikawa.okinawa.jp +itoman.okinawa.jp +izena.okinawa.jp +kadena.okinawa.jp +kin.okinawa.jp +kitadaito.okinawa.jp +kitanakagusuku.okinawa.jp +kumejima.okinawa.jp +kunigami.okinawa.jp +minamidaito.okinawa.jp +motobu.okinawa.jp +nago.okinawa.jp +naha.okinawa.jp +nakagusuku.okinawa.jp +nakijin.okinawa.jp +nanjo.okinawa.jp +nishihara.okinawa.jp +ogimi.okinawa.jp +okinawa.okinawa.jp +onna.okinawa.jp +shimoji.okinawa.jp +taketomi.okinawa.jp +tarama.okinawa.jp +tokashiki.okinawa.jp +tomigusuku.okinawa.jp +tonaki.okinawa.jp +urasoe.okinawa.jp +uruma.okinawa.jp +yaese.okinawa.jp +yomitan.okinawa.jp +yonabaru.okinawa.jp +yonaguni.okinawa.jp +zamami.okinawa.jp +abeno.osaka.jp +chihayaakasaka.osaka.jp +chuo.osaka.jp +daito.osaka.jp +fujiidera.osaka.jp +habikino.osaka.jp +hannan.osaka.jp +higashiosaka.osaka.jp +higashisumiyoshi.osaka.jp +higashiyodogawa.osaka.jp +hirakata.osaka.jp +ibaraki.osaka.jp +ikeda.osaka.jp +izumi.osaka.jp +izumiotsu.osaka.jp +izumisano.osaka.jp +kadoma.osaka.jp +kaizuka.osaka.jp +kanan.osaka.jp +kashiwara.osaka.jp +katano.osaka.jp +kawachinagano.osaka.jp +kishiwada.osaka.jp +kita.osaka.jp +kumatori.osaka.jp +matsubara.osaka.jp +minato.osaka.jp +minoh.osaka.jp +misaki.osaka.jp +moriguchi.osaka.jp +neyagawa.osaka.jp +nishi.osaka.jp +nose.osaka.jp +osakasayama.osaka.jp +sakai.osaka.jp +sayama.osaka.jp +sennan.osaka.jp +settsu.osaka.jp +shijonawate.osaka.jp +shimamoto.osaka.jp +suita.osaka.jp +tadaoka.osaka.jp +taishi.osaka.jp +tajiri.osaka.jp +takaishi.osaka.jp +takatsuki.osaka.jp +tondabayashi.osaka.jp +toyonaka.osaka.jp +toyono.osaka.jp +yao.osaka.jp +ariake.saga.jp +arita.saga.jp +fukudomi.saga.jp +genkai.saga.jp +hamatama.saga.jp +hizen.saga.jp +imari.saga.jp +kamimine.saga.jp +kanzaki.saga.jp +karatsu.saga.jp +kashima.saga.jp +kitagata.saga.jp +kitahata.saga.jp +kiyama.saga.jp +kouhoku.saga.jp +kyuragi.saga.jp +nishiarita.saga.jp +ogi.saga.jp +omachi.saga.jp +ouchi.saga.jp +saga.saga.jp +shiroishi.saga.jp +taku.saga.jp +tara.saga.jp +tosu.saga.jp +yoshinogari.saga.jp +arakawa.saitama.jp +asaka.saitama.jp +chichibu.saitama.jp +fujimi.saitama.jp +fujimino.saitama.jp +fukaya.saitama.jp +hanno.saitama.jp +hanyu.saitama.jp +hasuda.saitama.jp +hatogaya.saitama.jp +hatoyama.saitama.jp +hidaka.saitama.jp +higashichichibu.saitama.jp +higashimatsuyama.saitama.jp +honjo.saitama.jp +ina.saitama.jp +iruma.saitama.jp +iwatsuki.saitama.jp +kamiizumi.saitama.jp +kamikawa.saitama.jp +kamisato.saitama.jp +kasukabe.saitama.jp +kawagoe.saitama.jp +kawaguchi.saitama.jp +kawajima.saitama.jp +kazo.saitama.jp +kitamoto.saitama.jp +koshigaya.saitama.jp +kounosu.saitama.jp +kuki.saitama.jp +kumagaya.saitama.jp +matsubushi.saitama.jp +minano.saitama.jp +misato.saitama.jp +miyashiro.saitama.jp +miyoshi.saitama.jp +moroyama.saitama.jp +nagatoro.saitama.jp +namegawa.saitama.jp +niiza.saitama.jp +ogano.saitama.jp +ogawa.saitama.jp +ogose.saitama.jp +okegawa.saitama.jp +omiya.saitama.jp +otaki.saitama.jp +ranzan.saitama.jp +ryokami.saitama.jp +saitama.saitama.jp +sakado.saitama.jp +satte.saitama.jp +sayama.saitama.jp +shiki.saitama.jp +shiraoka.saitama.jp +soka.saitama.jp +sugito.saitama.jp +toda.saitama.jp +tokigawa.saitama.jp +tokorozawa.saitama.jp +tsurugashima.saitama.jp +urawa.saitama.jp +warabi.saitama.jp +yashio.saitama.jp +yokoze.saitama.jp +yono.saitama.jp +yorii.saitama.jp +yoshida.saitama.jp +yoshikawa.saitama.jp +yoshimi.saitama.jp +aisho.shiga.jp +gamo.shiga.jp +higashiomi.shiga.jp +hikone.shiga.jp +koka.shiga.jp +konan.shiga.jp +kosei.shiga.jp +koto.shiga.jp +kusatsu.shiga.jp +maibara.shiga.jp +moriyama.shiga.jp +nagahama.shiga.jp +nishiazai.shiga.jp +notogawa.shiga.jp +omihachiman.shiga.jp +otsu.shiga.jp +ritto.shiga.jp +ryuoh.shiga.jp +takashima.shiga.jp +takatsuki.shiga.jp +torahime.shiga.jp +toyosato.shiga.jp +yasu.shiga.jp +akagi.shimane.jp +ama.shimane.jp +gotsu.shimane.jp +hamada.shimane.jp +higashiizumo.shimane.jp +hikawa.shimane.jp +hikimi.shimane.jp +izumo.shimane.jp +kakinoki.shimane.jp +masuda.shimane.jp +matsue.shimane.jp +misato.shimane.jp +nishinoshima.shimane.jp +ohda.shimane.jp +okinoshima.shimane.jp +okuizumo.shimane.jp +shimane.shimane.jp +tamayu.shimane.jp +tsuwano.shimane.jp +unnan.shimane.jp +yakumo.shimane.jp +yasugi.shimane.jp +yatsuka.shimane.jp +arai.shizuoka.jp +atami.shizuoka.jp +fuji.shizuoka.jp +fujieda.shizuoka.jp +fujikawa.shizuoka.jp +fujinomiya.shizuoka.jp +fukuroi.shizuoka.jp +gotemba.shizuoka.jp +haibara.shizuoka.jp +hamamatsu.shizuoka.jp +higashiizu.shizuoka.jp +ito.shizuoka.jp +iwata.shizuoka.jp +izu.shizuoka.jp +izunokuni.shizuoka.jp +kakegawa.shizuoka.jp +kannami.shizuoka.jp +kawanehon.shizuoka.jp +kawazu.shizuoka.jp +kikugawa.shizuoka.jp +kosai.shizuoka.jp +makinohara.shizuoka.jp +matsuzaki.shizuoka.jp +minamiizu.shizuoka.jp +mishima.shizuoka.jp +morimachi.shizuoka.jp +nishiizu.shizuoka.jp +numazu.shizuoka.jp +omaezaki.shizuoka.jp +shimada.shizuoka.jp +shimizu.shizuoka.jp +shimoda.shizuoka.jp +shizuoka.shizuoka.jp +susono.shizuoka.jp +yaizu.shizuoka.jp +yoshida.shizuoka.jp +ashikaga.tochigi.jp +bato.tochigi.jp +haga.tochigi.jp +ichikai.tochigi.jp +iwafune.tochigi.jp +kaminokawa.tochigi.jp +kanuma.tochigi.jp +karasuyama.tochigi.jp +kuroiso.tochigi.jp +mashiko.tochigi.jp +mibu.tochigi.jp +moka.tochigi.jp +motegi.tochigi.jp +nasu.tochigi.jp +nasushiobara.tochigi.jp +nikko.tochigi.jp +nishikata.tochigi.jp +nogi.tochigi.jp +ohira.tochigi.jp +ohtawara.tochigi.jp +oyama.tochigi.jp +sakura.tochigi.jp +sano.tochigi.jp +shimotsuke.tochigi.jp +shioya.tochigi.jp +takanezawa.tochigi.jp +tochigi.tochigi.jp +tsuga.tochigi.jp +ujiie.tochigi.jp +utsunomiya.tochigi.jp +yaita.tochigi.jp +aizumi.tokushima.jp +anan.tokushima.jp +ichiba.tokushima.jp +itano.tokushima.jp +kainan.tokushima.jp +komatsushima.tokushima.jp +matsushige.tokushima.jp +mima.tokushima.jp +minami.tokushima.jp +miyoshi.tokushima.jp +mugi.tokushima.jp +nakagawa.tokushima.jp +naruto.tokushima.jp +sanagochi.tokushima.jp +shishikui.tokushima.jp +tokushima.tokushima.jp +wajiki.tokushima.jp +adachi.tokyo.jp +akiruno.tokyo.jp +akishima.tokyo.jp +aogashima.tokyo.jp +arakawa.tokyo.jp +bunkyo.tokyo.jp +chiyoda.tokyo.jp +chofu.tokyo.jp +chuo.tokyo.jp +edogawa.tokyo.jp +fuchu.tokyo.jp +fussa.tokyo.jp +hachijo.tokyo.jp +hachioji.tokyo.jp +hamura.tokyo.jp +higashikurume.tokyo.jp +higashimurayama.tokyo.jp +higashiyamato.tokyo.jp +hino.tokyo.jp +hinode.tokyo.jp +hinohara.tokyo.jp +inagi.tokyo.jp +itabashi.tokyo.jp +katsushika.tokyo.jp +kita.tokyo.jp +kiyose.tokyo.jp +kodaira.tokyo.jp +koganei.tokyo.jp +kokubunji.tokyo.jp +komae.tokyo.jp +koto.tokyo.jp +kouzushima.tokyo.jp +kunitachi.tokyo.jp +machida.tokyo.jp +meguro.tokyo.jp +minato.tokyo.jp +mitaka.tokyo.jp +mizuho.tokyo.jp +musashimurayama.tokyo.jp +musashino.tokyo.jp +nakano.tokyo.jp +nerima.tokyo.jp +ogasawara.tokyo.jp +okutama.tokyo.jp +ome.tokyo.jp +oshima.tokyo.jp +ota.tokyo.jp +setagaya.tokyo.jp +shibuya.tokyo.jp +shinagawa.tokyo.jp +shinjuku.tokyo.jp +suginami.tokyo.jp +sumida.tokyo.jp +tachikawa.tokyo.jp +taito.tokyo.jp +tama.tokyo.jp +toshima.tokyo.jp +chizu.tottori.jp +hino.tottori.jp +kawahara.tottori.jp +koge.tottori.jp +kotoura.tottori.jp +misasa.tottori.jp +nanbu.tottori.jp +nichinan.tottori.jp +sakaiminato.tottori.jp +tottori.tottori.jp +wakasa.tottori.jp +yazu.tottori.jp +yonago.tottori.jp +asahi.toyama.jp +fuchu.toyama.jp +fukumitsu.toyama.jp +funahashi.toyama.jp +himi.toyama.jp +imizu.toyama.jp +inami.toyama.jp +johana.toyama.jp +kamiichi.toyama.jp +kurobe.toyama.jp +nakaniikawa.toyama.jp +namerikawa.toyama.jp +nanto.toyama.jp +nyuzen.toyama.jp +oyabe.toyama.jp +taira.toyama.jp +takaoka.toyama.jp +tateyama.toyama.jp +toga.toyama.jp +tonami.toyama.jp +toyama.toyama.jp +unazuki.toyama.jp +uozu.toyama.jp +yamada.toyama.jp +arida.wakayama.jp +aridagawa.wakayama.jp +gobo.wakayama.jp +hashimoto.wakayama.jp +hidaka.wakayama.jp +hirogawa.wakayama.jp +inami.wakayama.jp +iwade.wakayama.jp +kainan.wakayama.jp +kamitonda.wakayama.jp +katsuragi.wakayama.jp +kimino.wakayama.jp +kinokawa.wakayama.jp +kitayama.wakayama.jp +koya.wakayama.jp +koza.wakayama.jp +kozagawa.wakayama.jp +kudoyama.wakayama.jp +kushimoto.wakayama.jp +mihama.wakayama.jp +misato.wakayama.jp +nachikatsuura.wakayama.jp +shingu.wakayama.jp +shirahama.wakayama.jp +taiji.wakayama.jp +tanabe.wakayama.jp +wakayama.wakayama.jp +yuasa.wakayama.jp +yura.wakayama.jp +asahi.yamagata.jp +funagata.yamagata.jp +higashine.yamagata.jp +iide.yamagata.jp +kahoku.yamagata.jp +kaminoyama.yamagata.jp +kaneyama.yamagata.jp +kawanishi.yamagata.jp +mamurogawa.yamagata.jp +mikawa.yamagata.jp +murayama.yamagata.jp +nagai.yamagata.jp +nakayama.yamagata.jp +nanyo.yamagata.jp +nishikawa.yamagata.jp +obanazawa.yamagata.jp +oe.yamagata.jp +oguni.yamagata.jp +ohkura.yamagata.jp +oishida.yamagata.jp +sagae.yamagata.jp +sakata.yamagata.jp +sakegawa.yamagata.jp +shinjo.yamagata.jp +shirataka.yamagata.jp +shonai.yamagata.jp +takahata.yamagata.jp +tendo.yamagata.jp +tozawa.yamagata.jp +tsuruoka.yamagata.jp +yamagata.yamagata.jp +yamanobe.yamagata.jp +yonezawa.yamagata.jp +yuza.yamagata.jp +abu.yamaguchi.jp +hagi.yamaguchi.jp +hikari.yamaguchi.jp +hofu.yamaguchi.jp +iwakuni.yamaguchi.jp +kudamatsu.yamaguchi.jp +mitou.yamaguchi.jp +nagato.yamaguchi.jp +oshima.yamaguchi.jp +shimonoseki.yamaguchi.jp +shunan.yamaguchi.jp +tabuse.yamaguchi.jp +tokuyama.yamaguchi.jp +toyota.yamaguchi.jp +ube.yamaguchi.jp +yuu.yamaguchi.jp +chuo.yamanashi.jp +doshi.yamanashi.jp +fuefuki.yamanashi.jp +fujikawa.yamanashi.jp +fujikawaguchiko.yamanashi.jp +fujiyoshida.yamanashi.jp +hayakawa.yamanashi.jp +hokuto.yamanashi.jp +ichikawamisato.yamanashi.jp +kai.yamanashi.jp +kofu.yamanashi.jp +koshu.yamanashi.jp +kosuge.yamanashi.jp +minami-alps.yamanashi.jp +minobu.yamanashi.jp +nakamichi.yamanashi.jp +nanbu.yamanashi.jp +narusawa.yamanashi.jp +nirasaki.yamanashi.jp +nishikatsura.yamanashi.jp +oshino.yamanashi.jp +otsuki.yamanashi.jp +showa.yamanashi.jp +tabayama.yamanashi.jp +tsuru.yamanashi.jp +uenohara.yamanashi.jp +yamanakako.yamanashi.jp +yamanashi.yamanashi.jp + +// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145 +*.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +org.kg +net.kg +com.kg +edu.kg +gov.kg +mil.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : http://www.ki/dns/index.html +ki +edu.ki +biz.ki +net.ki +org.ki +gov.ki +info.ki +com.ki + +// km : http://en.wikipedia.org/wiki/.km +// http://www.domaine.km/documents/charte.doc +km +org.km +nom.km +gov.km +prd.km +tm.km +edu.km +mil.km +ass.km +com.km +// These are only mentioned as proposed suggestions at domaine.km, but +// http://en.wikipedia.org/wiki/.km says they're available for registration: +coop.km +asso.km +presse.km +medecin.km +notaires.km +pharmaciens.km +veterinaire.km +gouv.km + +// kn : http://en.wikipedia.org/wiki/.kn +// http://www.dot.kn/domainRules.html +kn +net.kn +org.kn +edu.kn +gov.kn + +// kp : http://www.kcce.kp/en_index.php +kp +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : http://en.wikipedia.org/wiki/.kr +// see also: http://domain.nida.or.kr/eng/registration.jsp +kr +ac.kr +co.kr +es.kr +go.kr +hs.kr +kg.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : http://en.wikipedia.org/wiki/.kw +*.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +edu.ky +gov.ky +com.ky +org.ky +net.ky + +// kz : http://en.wikipedia.org/wiki/.kz +// see also: http://www.nic.kz/rules/index.jsp +kz +org.kz +edu.kz +net.kz +gov.kz +mil.kz +com.kz + +// la : http://en.wikipedia.org/wiki/.la +// Submitted by registry 2008-06-10 +la +int.la +net.la +info.la +edu.la +gov.la +per.la +com.la +org.la + +// lb : http://en.wikipedia.org/wiki/.lb +// Submitted by registry 2008-06-17 +lb +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : http://en.wikipedia.org/wiki/.lc +// see also: http://www.nic.lc/rules.htm +lc +com.lc +net.lc +co.lc +org.lc +edu.lc +gov.lc + +// li : http://en.wikipedia.org/wiki/.li +li + +// lk : http://www.nic.lk/seclevpr.html +lk +gov.lk +sch.lk +net.lk +int.lk +com.lk +org.lk +edu.lk +ngo.lk +soc.lk +web.lk +ltd.lk +assn.lk +grp.lk +hotel.lk +ac.lk + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry 2008-06-17 +lr +com.lr +edu.lr +gov.lr +org.lr +net.lr + +// ls : http://en.wikipedia.org/wiki/.ls +ls +co.ls +org.ls + +// lt : http://en.wikipedia.org/wiki/.lt +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : http://www.nic.lv/DNS/En/generic.php +lv +com.lv +edu.lv +gov.lv +org.lv +mil.lv +id.lv +net.lv +asn.lv +conf.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +net.ly +gov.ly +plc.ly +edu.ly +sch.ly +med.ly +org.ly +id.ly + +// ma : http://en.wikipedia.org/wiki/.ma +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +co.ma +net.ma +gov.ma +org.ma +ac.ma +press.ma + +// mc : http://www.nic.mc/ +mc +tm.mc +asso.mc + +// md : http://en.wikipedia.org/wiki/.md +md + +// me : http://en.wikipedia.org/wiki/.me +me +co.me +net.me +org.me +edu.me +ac.me +gov.me +its.me +priv.me + +// mg : http://nic.mg/nicmg/?page_id=39 +mg +org.mg +nom.mg +gov.mg +prd.mg +tm.mg +edu.mg +mil.mg +com.mg +co.mg + +// mh : http://en.wikipedia.org/wiki/.mh +mh + +// mil : http://en.wikipedia.org/wiki/.mil +mil + +// mk : http://en.wikipedia.org/wiki/.mk +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +org.mk +net.mk +edu.mk +gov.mk +inf.mk +name.mk + +// ml : http://www.gobin.info/domainname/ml-template.doc +// see also: http://en.wikipedia.org/wiki/.ml +ml +com.ml +edu.ml +gouv.ml +gov.ml +net.ml +org.ml +presse.ml + +// mm : http://en.wikipedia.org/wiki/.mm +*.mm + +// mn : http://en.wikipedia.org/wiki/.mn +mn +gov.mn +edu.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +net.mo +org.mo +edu.mo +gov.mo + +// mobi : http://en.wikipedia.org/wiki/.mobi +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : http://en.wikipedia.org/wiki/.mq +mq + +// mr : http://en.wikipedia.org/wiki/.mr +mr +gov.mr + +// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf +ms +com.ms +edu.ms +gov.ms +net.ms +org.ms + +// mt : https://www.nic.org.mt/go/policy +// Submitted by registry 2013-11-19 +mt +com.mt +edu.mt +net.mt +org.mt + +// mu : http://en.wikipedia.org/wiki/.mu +mu +com.mu +net.mu +org.mu +gov.mu +ac.mu +co.mu +or.mu + +// museum : http://about.museum/naming/ +// http://index.museum/ +museum +academy.museum +agriculture.museum +air.museum +airguard.museum +alabama.museum +alaska.museum +amber.museum +ambulance.museum +american.museum +americana.museum +americanantiques.museum +americanart.museum +amsterdam.museum +and.museum +annefrank.museum +anthro.museum +anthropology.museum +antiques.museum +aquarium.museum +arboretum.museum +archaeological.museum +archaeology.museum +architecture.museum +art.museum +artanddesign.museum +artcenter.museum +artdeco.museum +arteducation.museum +artgallery.museum +arts.museum +artsandcrafts.museum +asmatart.museum +assassination.museum +assisi.museum +association.museum +astronomy.museum +atlanta.museum +austin.museum +australia.museum +automotive.museum +aviation.museum +axis.museum +badajoz.museum +baghdad.museum +bahn.museum +bale.museum +baltimore.museum +barcelona.museum +baseball.museum +basel.museum +baths.museum +bauern.museum +beauxarts.museum +beeldengeluid.museum +bellevue.museum +bergbau.museum +berkeley.museum +berlin.museum +bern.museum +bible.museum +bilbao.museum +bill.museum +birdart.museum +birthplace.museum +bonn.museum +boston.museum +botanical.museum +botanicalgarden.museum +botanicgarden.museum +botany.museum +brandywinevalley.museum +brasil.museum +bristol.museum +british.museum +britishcolumbia.museum +broadcast.museum +brunel.museum +brussel.museum +brussels.museum +bruxelles.museum +building.museum +burghof.museum +bus.museum +bushey.museum +cadaques.museum +california.museum +cambridge.museum +can.museum +canada.museum +capebreton.museum +carrier.museum +cartoonart.museum +casadelamoneda.museum +castle.museum +castres.museum +celtic.museum +center.museum +chattanooga.museum +cheltenham.museum +chesapeakebay.museum +chicago.museum +children.museum +childrens.museum +childrensgarden.museum +chiropractic.museum +chocolate.museum +christiansburg.museum +cincinnati.museum +cinema.museum +circus.museum +civilisation.museum +civilization.museum +civilwar.museum +clinton.museum +clock.museum +coal.museum +coastaldefence.museum +cody.museum +coldwar.museum +collection.museum +colonialwilliamsburg.museum +coloradoplateau.museum +columbia.museum +columbus.museum +communication.museum +communications.museum +community.museum +computer.museum +computerhistory.museum +comunicações.museum +contemporary.museum +contemporaryart.museum +convent.museum +copenhagen.museum +corporation.museum +correios-e-telecomunicações.museum +corvette.museum +costume.museum +countryestate.museum +county.museum +crafts.museum +cranbrook.museum +creation.museum +cultural.museum +culturalcenter.museum +culture.museum +cyber.museum +cymru.museum +dali.museum +dallas.museum +database.museum +ddr.museum +decorativearts.museum +delaware.museum +delmenhorst.museum +denmark.museum +depot.museum +design.museum +detroit.museum +dinosaur.museum +discovery.museum +dolls.museum +donostia.museum +durham.museum +eastafrica.museum +eastcoast.museum +education.museum +educational.museum +egyptian.museum +eisenbahn.museum +elburg.museum +elvendrell.museum +embroidery.museum +encyclopedic.museum +england.museum +entomology.museum +environment.museum +environmentalconservation.museum +epilepsy.museum +essex.museum +estate.museum +ethnology.museum +exeter.museum +exhibition.museum +family.museum +farm.museum +farmequipment.museum +farmers.museum +farmstead.museum +field.museum +figueres.museum +filatelia.museum +film.museum +fineart.museum +finearts.museum +finland.museum +flanders.museum +florida.museum +force.museum +fortmissoula.museum +fortworth.museum +foundation.museum +francaise.museum +frankfurt.museum +franziskaner.museum +freemasonry.museum +freiburg.museum +fribourg.museum +frog.museum +fundacio.museum +furniture.museum +gallery.museum +garden.museum +gateway.museum +geelvinck.museum +gemological.museum +geology.museum +georgia.museum +giessen.museum +glas.museum +glass.museum +gorge.museum +grandrapids.museum +graz.museum +guernsey.museum +halloffame.museum +hamburg.museum +handson.museum +harvestcelebration.museum +hawaii.museum +health.museum +heimatunduhren.museum +hellas.museum +helsinki.museum +hembygdsforbund.museum +heritage.museum +histoire.museum +historical.museum +historicalsociety.museum +historichouses.museum +historisch.museum +historisches.museum +history.museum +historyofscience.museum +horology.museum +house.museum +humanities.museum +illustration.museum +imageandsound.museum +indian.museum +indiana.museum +indianapolis.museum +indianmarket.museum +intelligence.museum +interactive.museum +iraq.museum +iron.museum +isleofman.museum +jamison.museum +jefferson.museum +jerusalem.museum +jewelry.museum +jewish.museum +jewishart.museum +jfk.museum +journalism.museum +judaica.museum +judygarland.museum +juedisches.museum +juif.museum +karate.museum +karikatur.museum +kids.museum +koebenhavn.museum +koeln.museum +kunst.museum +kunstsammlung.museum +kunstunddesign.museum +labor.museum +labour.museum +lajolla.museum +lancashire.museum +landes.museum +lans.museum +läns.museum +larsson.museum +lewismiller.museum +lincoln.museum +linz.museum +living.museum +livinghistory.museum +localhistory.museum +london.museum +losangeles.museum +louvre.museum +loyalist.museum +lucerne.museum +luxembourg.museum +luzern.museum +mad.museum +madrid.museum +mallorca.museum +manchester.museum +mansion.museum +mansions.museum +manx.museum +marburg.museum +maritime.museum +maritimo.museum +maryland.museum +marylhurst.museum +media.museum +medical.museum +medizinhistorisches.museum +meeres.museum +memorial.museum +mesaverde.museum +michigan.museum +midatlantic.museum +military.museum +mill.museum +miners.museum +mining.museum +minnesota.museum +missile.museum +missoula.museum +modern.museum +moma.museum +money.museum +monmouth.museum +monticello.museum +montreal.museum +moscow.museum +motorcycle.museum +muenchen.museum +muenster.museum +mulhouse.museum +muncie.museum +museet.museum +museumcenter.museum +museumvereniging.museum +music.museum +national.museum +nationalfirearms.museum +nationalheritage.museum +nativeamerican.museum +naturalhistory.museum +naturalhistorymuseum.museum +naturalsciences.museum +nature.museum +naturhistorisches.museum +natuurwetenschappen.museum +naumburg.museum +naval.museum +nebraska.museum +neues.museum +newhampshire.museum +newjersey.museum +newmexico.museum +newport.museum +newspaper.museum +newyork.museum +niepce.museum +norfolk.museum +north.museum +nrw.museum +nuernberg.museum +nuremberg.museum +nyc.museum +nyny.museum +oceanographic.museum +oceanographique.museum +omaha.museum +online.museum +ontario.museum +openair.museum +oregon.museum +oregontrail.museum +otago.museum +oxford.museum +pacific.museum +paderborn.museum +palace.museum +paleo.museum +palmsprings.museum +panama.museum +paris.museum +pasadena.museum +pharmacy.museum +philadelphia.museum +philadelphiaarea.museum +philately.museum +phoenix.museum +photography.museum +pilots.museum +pittsburgh.museum +planetarium.museum +plantation.museum +plants.museum +plaza.museum +portal.museum +portland.museum +portlligat.museum +posts-and-telecommunications.museum +preservation.museum +presidio.museum +press.museum +project.museum +public.museum +pubol.museum +quebec.museum +railroad.museum +railway.museum +research.museum +resistance.museum +riodejaneiro.museum +rochester.museum +rockart.museum +roma.museum +russia.museum +saintlouis.museum +salem.museum +salvadordali.museum +salzburg.museum +sandiego.museum +sanfrancisco.museum +santabarbara.museum +santacruz.museum +santafe.museum +saskatchewan.museum +satx.museum +savannahga.museum +schlesisches.museum +schoenbrunn.museum +schokoladen.museum +school.museum +schweiz.museum +science.museum +scienceandhistory.museum +scienceandindustry.museum +sciencecenter.museum +sciencecenters.museum +science-fiction.museum +sciencehistory.museum +sciences.museum +sciencesnaturelles.museum +scotland.museum +seaport.museum +settlement.museum +settlers.museum +shell.museum +sherbrooke.museum +sibenik.museum +silk.museum +ski.museum +skole.museum +society.museum +sologne.museum +soundandvision.museum +southcarolina.museum +southwest.museum +space.museum +spy.museum +square.museum +stadt.museum +stalbans.museum +starnberg.museum +state.museum +stateofdelaware.museum +station.museum +steam.museum +steiermark.museum +stjohn.museum +stockholm.museum +stpetersburg.museum +stuttgart.museum +suisse.museum +surgeonshall.museum +surrey.museum +svizzera.museum +sweden.museum +sydney.museum +tank.museum +tcm.museum +technology.museum +telekommunikation.museum +television.museum +texas.museum +textile.museum +theater.museum +time.museum +timekeeping.museum +topology.museum +torino.museum +touch.museum +town.museum +transport.museum +tree.museum +trolley.museum +trust.museum +trustee.museum +uhren.museum +ulm.museum +undersea.museum +university.museum +usa.museum +usantiques.museum +usarts.museum +uscountryestate.museum +usculture.museum +usdecorativearts.museum +usgarden.museum +ushistory.museum +ushuaia.museum +uslivinghistory.museum +utah.museum +uvic.museum +valley.museum +vantaa.museum +versailles.museum +viking.museum +village.museum +virginia.museum +virtual.museum +virtuel.museum +vlaanderen.museum +volkenkunde.museum +wales.museum +wallonie.museum +war.museum +washingtondc.museum +watchandclock.museum +watch-and-clock.museum +western.museum +westfalen.museum +whaling.museum +wildlife.museum +williamsburg.museum +windmill.museum +workshop.museum +york.museum +yorkshire.museum +yosemite.museum +youth.museum +zoological.museum +zoology.museum +ירושלים.museum +иком.museum + +// mv : http://en.wikipedia.org/wiki/.mv +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +museum.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry 2008-06-19 +mx +com.mx +org.mx +gob.mx +edu.mx +net.mx + +// my : http://www.mynic.net.my/ +my +com.my +net.my +org.my +gov.my +edu.my +mil.my +name.my + +// mz : http://www.gobin.info/domainname/mz-template.doc +*.mz +!teledata.mz + +// na : http://www.na-nic.com.na/ +// http://www.info.na/domain/ +na +info.na +pro.na +name.na +school.na +or.na +dr.na +us.na +mx.na +ca.na +in.na +cc.na +tv.na +ws.na +mobi.na +co.na +com.na +org.na + +// name : has 2nd-level tlds, but there's no list of them +name + +// nc : http://www.cctld.nc/ +nc +asso.nc + +// ne : http://en.wikipedia.org/wiki/.ne +ne + +// net : http://en.wikipedia.org/wiki/.net +net + +// nf : http://en.wikipedia.org/wiki/.nf +nf +com.nf +net.nf +per.nf +rec.nf +web.nf +arts.nf +firm.nf +info.nf +other.nf +store.nf + +// ng : http://psg.com/dns/ng/ +ng +com.ng +edu.ng +name.ng +net.ng +org.ng +sch.ng +gov.ng +mil.ng +mobi.ng + +// ni : http://www.nic.ni/dominios.htm +*.ni + +// nl : http://en.wikipedia.org/wiki/.nl +// https://www.sidn.nl/ +// ccTLD for the Netherlands +nl + +// BV.nl will be a registry for dutch BV's (besloten vennootschap) +bv.nl + +// no : http://www.norid.no/regelverk/index.en.html +// The Norwegian registry has declined to notify us of updates. The web pages +// referenced below are the official source of the data. There is also an +// announce mailing list: +// https://postlister.uninett.no/sympa/info/norid-diskusjon +no +// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html +fhs.no +vgs.no +fylkesbibl.no +folkebibl.no +museum.no +idrett.no +priv.no +// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html +mil.no +stat.no +dep.no +kommune.no +herad.no +// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +åkrehamn.no +algard.no +ålgård.no +arna.no +brumunddal.no +bryne.no +bronnoysund.no +brønnøysund.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevåg.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +råholt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +afjord.no +åfjord.no +agdenes.no +al.no +ål.no +alesund.no +ålesund.no +alstahaug.no +alta.no +áltá.no +alaheadju.no +álaheadju.no +alvdal.no +amli.no +åmli.no +amot.no +åmot.no +andebu.no +andoy.no +andøy.no +andasuolo.no +ardal.no +årdal.no +aremark.no +arendal.no +ås.no +aseral.no +åseral.no +asker.no +askim.no +askvoll.no +askoy.no +askøy.no +asnes.no +åsnes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +balestrand.no +ballangen.no +balat.no +bálát.no +balsfjord.no +bahccavuotna.no +báhccavuotna.no +bamble.no +bardu.no +beardu.no +beiarn.no +bajddar.no +bájddar.no +baidar.no +báidár.no +berg.no +bergen.no +berlevag.no +berlevåg.no +bearalvahki.no +bearalváhki.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +badaddja.no +bådåddjå.no +budejju.no +bokn.no +bremanger.no +bronnoy.no +brønnøy.no +bygland.no +bykle.no +barum.no +bærum.no +bo.telemark.no +bø.telemark.no +bo.nordland.no +bø.nordland.no +bievat.no +bievát.no +bomlo.no +bømlo.no +batsfjord.no +båtsfjord.no +bahcavuotna.no +báhcavuotna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +donna.no +dønna.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenes.no +evenassi.no +evenášši.no +evje-og-hornnes.no +farsund.no +fauske.no +fuossko.no +fuoisku.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +fla.no +flå.no +folldal.no +forsand.no +fosnes.no +frei.no +frogn.no +froland.no +frosta.no +frana.no +fræna.no +froya.no +frøya.no +fusa.no +fyresdal.no +forde.no +førde.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +gildeskal.no +gildeskål.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +kraanghke.no +kråanghke.no +grue.no +gulen.no +hadsel.no +halden.no +halsa.no +hamar.no +hamaroy.no +habmer.no +hábmer.no +hapmir.no +hápmir.no +hammerfest.no +hammarfeasta.no +hámmárfeasta.no +haram.no +hareid.no +harstad.no +hasvik.no +aknoluokta.no +ákŋoluokta.no +hattfjelldal.no +aarborte.no +haugesund.no +hemne.no +hemnes.no +hemsedal.no +heroy.more-og-romsdal.no +herøy.møre-og-romsdal.no +heroy.nordland.no +herøy.nordland.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtålen.no +hornindal.no +horten.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +hagebostad.no +hægebostad.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +ha.no +hå.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +jevnaker.no +jondal.no +jolster.no +jølster.no +karasjok.no +karasjohka.no +kárášjohka.no +karlsoy.no +galsa.no +gálsá.no +karmoy.no +karmøy.no +kautokeino.no +guovdageaidnu.no +klepp.no +klabu.no +klæbu.no +kongsberg.no +kongsvinger.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvalsund.no +rahkkeravju.no +ráhkkerávju.no +kvam.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +kvafjord.no +kvæfjord.no +giehtavuoatna.no +kvanangen.no +kvænangen.no +navuotna.no +návuotna.no +kafjord.no +kåfjord.no +gaivuotna.no +gáivuotna.no +larvik.no +lavangen.no +lavagis.no +loabat.no +loabát.no +lebesby.no +davvesiida.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +leangaviika.no +leaŋgaviika.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindesnes.no +lindas.no +lindås.no +lom.no +loppa.no +lahppi.no +láhppi.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +ivgu.no +lardal.no +lerdal.no +lærdal.no +lodingen.no +lødingen.no +lorenskog.no +lørenskog.no +loten.no +løten.no +malvik.no +masoy.no +måsøy.no +muosat.no +muosát.no +mandal.no +marker.no +marnardal.no +masfjorden.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +meråker.no +moareke.no +moåreke.no +midsund.no +midtre-gauldal.no +modalen.no +modum.no +molde.no +moskenes.no +moss.no +mosvik.no +malselv.no +målselv.no +malatvuopmi.no +málatvuopmi.no +namdalseid.no +aejrie.no +namsos.no +namsskogan.no +naamesjevuemie.no +nååmesjevuemie.no +laakesvuemie.no +nannestad.no +narvik.no +narviika.no +naustdal.no +nedre-eiker.no +nes.akershus.no +nes.buskerud.no +nesna.no +nesodden.no +nesseby.no +unjarga.no +unjárga.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +davvenjarga.no +davvenjárga.no +nordre-land.no +nordreisa.no +raisa.no +ráisa.no +nore-og-uvdal.no +notodden.no +naroy.no +nærøy.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +oppdal.no +oppegard.no +oppegård.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +os.hedmark.no +os.hordaland.no +osen.no +osteroy.no +osterøy.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +radoy.no +radøy.no +rakkestad.no +rana.no +ruovat.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +rissa.no +risor.no +risør.no +roan.no +rollag.no +rygge.no +ralingen.no +rælingen.no +rodoy.no +rødøy.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +rade.no +råde.no +salangen.no +siellak.no +saltdal.no +salat.no +sálát.no +sálat.no +samnanger.no +sande.more-og-romsdal.no +sande.møre-og-romsdal.no +sande.vestfold.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +sigdal.no +siljan.no +sirdal.no +skaun.no +skedsmo.no +ski.no +skien.no +skiptvet.no +skjervoy.no +skjervøy.no +skierva.no +skiervá.no +skjak.no +skjåk.no +skodje.no +skanland.no +skånland.no +skanit.no +skánit.no +smola.no +smøla.no +snillfjord.no +snasa.no +snåsa.no +snoasa.no +snaase.no +snåase.no +sogndal.no +sokndal.no +sola.no +solund.no +songdalen.no +sortland.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +omasvuotna.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +sogne.no +søgne.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +matta-varjjat.no +mátta-várjjat.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sorum.no +sørum.no +tana.no +deatnu.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +dielddanuorri.no +tjome.no +tjøme.no +tokke.no +tolga.no +torsken.no +tranoy.no +tranøy.no +tromso.no +tromsø.no +tromsa.no +romsa.no +trondheim.no +troandin.no +trysil.no +trana.no +træna.no +trogstad.no +trøgstad.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +divtasvuodna.no +divttasvuotna.no +tysnes.no +tysvar.no +tysvær.no +tonsberg.no +tønsberg.no +ullensaker.no +ullensvang.no +ulvik.no +utsira.no +vadso.no +vadsø.no +cahcesuolo.no +čáhcesuolo.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +vefsn.no +vaapste.no +vega.no +vegarshei.no +vegårshei.no +vennesla.no +verdal.no +verran.no +vestby.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvågøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +volda.no +voss.no +varoy.no +værøy.no +vagan.no +vågan.no +voagat.no +vagsoy.no +vågsøy.no +vaga.no +vågå.no +valer.ostfold.no +våler.østfold.no +valer.hedmark.no +våler.hedmark.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Confirmed by registry 2008-06-17 +nr +biz.nr +info.nr +gov.nr +edu.nr +org.nr +net.nr +com.nr + +// nu : http://en.wikipedia.org/wiki/.nu +nu + +// nz : http://en.wikipedia.org/wiki/.nz +// Confirmed by registry 2014-05-19 +nz +ac.nz +co.nz +cri.nz +geek.nz +gen.nz +govt.nz +health.nz +iwi.nz +kiwi.nz +maori.nz +mil.nz +māori.nz +net.nz +org.nz +parliament.nz +school.nz + +// om : http://en.wikipedia.org/wiki/.om +om +co.om +com.om +edu.om +gov.om +med.om +museum.om +net.om +org.om +pro.om + +// org : http://en.wikipedia.org/wiki/.org +org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +ac.pa +gob.pa +com.pa +org.pa +sld.pa +edu.pa +net.pa +ing.pa +abo.pa +med.pa +nom.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +edu.pe +gob.pe +nom.pe +mil.pe +org.pe +com.pe +net.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +org.pf +edu.pf + +// pg : http://en.wikipedia.org/wiki/.pg +*.pg + +// ph : http://www.domains.ph/FAQ2.asp +// Submitted by registry 2008-06-13 +ph +com.ph +net.ph +org.ph +gov.ph +edu.ph +ngo.ph +mil.ph +i.ph + +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +pk +com.pk +net.pk +edu.pk +org.pk +fam.pk +biz.pk +web.pk +gov.pk +gob.pk +gok.pk +gon.pk +gop.pk +gos.pk +info.pk + +// pl http://www.dns.pl/english/index.html +// updated by .PL registry on 2015-04-28 +pl +com.pl +net.pl +org.pl +// pl functional domains (http://www.dns.pl/english/index.html) +aid.pl +agro.pl +atm.pl +auto.pl +biz.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +miasta.pl +media.pl +mil.pl +nieruchomosci.pl +nom.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// Government domains +gov.pl +ap.gov.pl +ic.gov.pl +is.gov.pl +us.gov.pl +kmpsp.gov.pl +kppsp.gov.pl +kwpsp.gov.pl +psp.gov.pl +wskr.gov.pl +kwp.gov.pl +mw.gov.pl +ug.gov.pl +um.gov.pl +umig.gov.pl +ugim.gov.pl +upow.gov.pl +uw.gov.pl +starostwo.gov.pl +pa.gov.pl +po.gov.pl +psse.gov.pl +pup.gov.pl +rzgw.gov.pl +sa.gov.pl +so.gov.pl +sr.gov.pl +wsa.gov.pl +sko.gov.pl +uzs.gov.pl +wiih.gov.pl +winb.gov.pl +pinb.gov.pl +wios.gov.pl +witd.gov.pl +wzmiuw.gov.pl +piw.gov.pl +wiw.gov.pl +griw.gov.pl +wif.gov.pl +oum.gov.pl +sdn.gov.pl +zp.gov.pl +uppo.gov.pl +mup.gov.pl +wuoz.gov.pl +konsulat.gov.pl +oirm.gov.pl +// pl regional domains (http://www.dns.pl/english/index.html) +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +kazimierz-dolny.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorze.pl +pomorskie.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +skoczow.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl + +// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +pm + +// pn : http://www.government.pn/PnRegistry/policies.htm +pn +gov.pn +co.pn +org.pn +edu.pn +net.pn + +// post : http://en.wikipedia.org/wiki/.post +post + +// pr : http://www.nic.pr/index.asp?f=1 +pr +com.pr +net.pr +org.pr +gov.pr +edu.pr +isla.pr +pro.pr +biz.pr +info.pr +name.pr +// these aren't mentioned on nic.pr, but on http://en.wikipedia.org/wiki/.pr +est.pr +prof.pr +ac.pr + +// pro : http://www.nic.pro/support_faq.htm +pro +aca.pro +bar.pro +cpa.pro +jur.pro +law.pro +med.pro +eng.pro + +// ps : http://en.wikipedia.org/wiki/.ps +// http://www.nic.ps/registration/policy.html#reg +ps +edu.ps +gov.ps +sec.ps +plo.ps +com.ps +org.ps +net.ps + +// pt : http://online.dns.pt/dns/start_dns +pt +net.pt +gov.pt +org.pt +edu.pt +int.pt +publ.pt +com.pt +nome.pt + +// pw : http://en.wikipedia.org/wiki/.pw +pw +co.pw +ne.pw +or.pw +ed.pw +go.pw +belau.pw + +// py : http://www.nic.py/pautas.html#seccion_9 +// Confirmed by registry 2012-10-03 +py +com.py +coop.py +edu.py +gov.py +mil.py +net.py +org.py + +// qa : http://domains.qa/en/ +qa +com.qa +edu.qa +gov.qa +mil.qa +name.qa +net.qa +org.qa +sch.qa + +// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +re +com.re +asso.re +nom.re + +// ro : http://www.rotld.ro/ +ro +com.ro +org.ro +tm.ro +nt.ro +nom.ro +info.ro +rec.ro +arts.ro +firm.ro +store.ro +www.ro + +// rs : http://en.wikipedia.org/wiki/.rs +rs +co.rs +org.rs +edu.rs +ac.rs +gov.rs +in.rs + +// ru : http://www.cctld.ru/ru/docs/aktiv_8.php +// Industry domains +ru +ac.ru +com.ru +edu.ru +int.ru +net.ru +org.ru +pp.ru +// Geographical domains +adygeya.ru +altai.ru +amur.ru +arkhangelsk.ru +astrakhan.ru +bashkiria.ru +belgorod.ru +bir.ru +bryansk.ru +buryatia.ru +cbg.ru +chel.ru +chelyabinsk.ru +chita.ru +chukotka.ru +chuvashia.ru +dagestan.ru +dudinka.ru +e-burg.ru +grozny.ru +irkutsk.ru +ivanovo.ru +izhevsk.ru +jar.ru +joshkar-ola.ru +kalmykia.ru +kaluga.ru +kamchatka.ru +karelia.ru +kazan.ru +kchr.ru +kemerovo.ru +khabarovsk.ru +khakassia.ru +khv.ru +kirov.ru +koenig.ru +komi.ru +kostroma.ru +krasnoyarsk.ru +kuban.ru +kurgan.ru +kursk.ru +lipetsk.ru +magadan.ru +mari.ru +mari-el.ru +marine.ru +mordovia.ru +// mosreg.ru Bug 1090800 - removed at request of Aleksey Konstantinov +msk.ru +murmansk.ru +nalchik.ru +nnov.ru +nov.ru +novosibirsk.ru +nsk.ru +omsk.ru +orenburg.ru +oryol.ru +palana.ru +penza.ru +perm.ru +ptz.ru +rnd.ru +ryazan.ru +sakhalin.ru +samara.ru +saratov.ru +simbirsk.ru +smolensk.ru +spb.ru +stavropol.ru +stv.ru +surgut.ru +tambov.ru +tatarstan.ru +tom.ru +tomsk.ru +tsaritsyn.ru +tsk.ru +tula.ru +tuva.ru +tver.ru +tyumen.ru +udm.ru +udmurtia.ru +ulan-ude.ru +vladikavkaz.ru +vladimir.ru +vladivostok.ru +volgograd.ru +vologda.ru +voronezh.ru +vrn.ru +vyatka.ru +yakutia.ru +yamal.ru +yaroslavl.ru +yekaterinburg.ru +yuzhno-sakhalinsk.ru +// More geographical domains +amursk.ru +baikal.ru +cmw.ru +fareast.ru +jamal.ru +kms.ru +k-uralsk.ru +kustanai.ru +kuzbass.ru +magnitka.ru +mytis.ru +nakhodka.ru +nkz.ru +norilsk.ru +oskol.ru +pyatigorsk.ru +rubtsovsk.ru +snz.ru +syzran.ru +vdonsk.ru +zgrad.ru +// State domains +gov.ru +mil.ru +// Technical domains +test.ru + +// rw : http://www.nic.rw/cgi-bin/policy.pl +rw +gov.rw +net.rw +edu.rw +ac.rw +com.rw +co.rw +int.rw +mil.rw +gouv.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +net.sa +org.sa +gov.sa +med.sa +pub.sa +edu.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry 2008-06-08 +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +gov.sc +net.sc +org.sc +edu.sc + +// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// Submitted by registry 2008-06-17 +sd +com.sd +net.sd +org.sd +edu.sd +med.sd +tv.sd +gov.sd +info.sd + +// se : http://en.wikipedia.org/wiki/.se +// Submitted by registry 2014-03-18 +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +sg +com.sg +net.sg +org.sg +gov.sg +edu.sg +per.sg + +// sh : http://www.nic.sh/registrar.html +sh +com.sh +net.sh +gov.sh +org.sh +mil.sh + +// si : http://en.wikipedia.org/wiki/.si +si + +// sj : No registrations at this time. +// Submitted by registry 2008-06-16 +sj + +// sk : http://en.wikipedia.org/wiki/.sk +// list of 2nd level domains ? +sk + +// sl : http://www.nic.sl +// Submitted by registry 2008-06-12 +sl +com.sl +net.sl +edu.sl +gov.sl +org.sl + +// sm : http://en.wikipedia.org/wiki/.sm +sm + +// sn : http://en.wikipedia.org/wiki/.sn +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://www.soregistry.com/ +so +com.so +net.so +org.so + +// sr : http://en.wikipedia.org/wiki/.sr +sr + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +gov.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : http://en.wikipedia.org/wiki/.su +su +adygeya.su +arkhangelsk.su +balashov.su +bashkiria.su +bryansk.su +dagestan.su +grozny.su +ivanovo.su +kalmykia.su +kaluga.su +karelia.su +khakassia.su +krasnodar.su +kurgan.su +lenug.su +mordovia.su +msk.su +murmansk.su +nalchik.su +nov.su +obninsk.su +penza.su +pokrovsk.su +sochi.su +spb.su +togliatti.su +troitsk.su +tula.su +tuva.su +vladikavkaz.su +vladimir.su +vologda.su + +// sv : http://www.svnet.org.sv/niveldos.pdf +sv +com.sv +edu.sv +gob.sv +org.sv +red.sv + +// sx : http://en.wikipedia.org/wiki/.sx +// Confirmed by registry 2012-05-31 +sx +gov.sx + +// sy : http://en.wikipedia.org/wiki/.sy +// see also: http://www.gobin.info/domainname/sy.doc +sy +edu.sy +gov.sy +net.sy +mil.sy +com.sy +org.sy + +// sz : http://en.wikipedia.org/wiki/.sz +// http://www.sispa.org.sz/ +sz +co.sz +ac.sz +org.sz + +// tc : http://en.wikipedia.org/wiki/.tc +tc + +// td : http://en.wikipedia.org/wiki/.td +td + +// tel: http://en.wikipedia.org/wiki/.tel +// http://www.telnic.org/ +tel + +// tf : http://en.wikipedia.org/wiki/.tf +tf + +// tg : http://en.wikipedia.org/wiki/.tg +// http://www.nic.tg/ +tg + +// th : http://en.wikipedia.org/wiki/.th +// Submitted by registry 2008-06-17 +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.html +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : http://en.wikipedia.org/wiki/.tk +tk + +// tl : http://en.wikipedia.org/wiki/.tl +tl +gov.tl + +// tm : http://www.nic.tm/local.html +tm +com.tm +co.tm +org.tm +net.tm +nom.tm +gov.tm +mil.tm +edu.tm + +// tn : http://en.wikipedia.org/wiki/.tn +// http://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +intl.tn +nat.tn +net.tn +org.tn +info.tn +perso.tn +tourism.tn +edunet.tn +rnrt.tn +rns.tn +rnu.tn +mincom.tn +agrinet.tn +defense.tn +turen.tn + +// to : http://en.wikipedia.org/wiki/.to +// Submitted by registry 2008-06-17 +to +com.to +gov.to +net.to +org.to +edu.to +mil.to + +// tp : No registrations at this time. +// Submitted by Ryan Sleevi 2014-01-03 +tp + +// subTLDs: https://www.nic.tr/forms/eng/policies.pdf +// and: https://www.nic.tr/forms/politikalar.pdf +// Submitted by 2014-07-19 +tr +com.tr +info.tr +biz.tr +net.tr +org.tr +web.tr +gen.tr +tv.tr +av.tr +dr.tr +bbs.tr +name.tr +tel.tr +gov.tr +bel.tr +pol.tr +mil.tr +k12.tr +edu.tr +kep.tr + +// Used by Northern Cyprus +nc.tr + +// Used by government agencies of Northern Cyprus +gov.nc.tr + +// travel : http://en.wikipedia.org/wiki/.travel +travel + +// tt : http://www.nic.tt/ +tt +co.tt +com.tt +org.tt +net.tt +biz.tt +info.tt +pro.tt +int.tt +coop.tt +jobs.tt +mobi.tt +travel.tt +museum.tt +aero.tt +name.tt +gov.tt +edu.tt + +// tv : http://en.wikipedia.org/wiki/.tv +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : http://en.wikipedia.org/wiki/.tw +tw +edu.tw +gov.tw +mil.tw +com.tw +net.tw +org.tw +idv.tw +game.tw +ebiz.tw +club.tw +網路.tw +組織.tw +商業.tw + +// tz : http://www.tznic.or.tz/index.php/domains +// Confirmed by registry 2013-01-22 +tz +ac.tz +co.tz +go.tz +hotel.tz +info.tz +me.tz +mil.tz +mobi.tz +ne.tz +or.tz +sc.tz +tv.tz + +// ua : https://hostmaster.ua/policy/?ua +// Submitted by registry 2012-04-27 +ua +// ua 2LD +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geographic names +// https://hostmaster.ua/2ld/ +cherkassy.ua +cherkasy.ua +chernigov.ua +chernihiv.ua +chernivtsi.ua +chernovtsy.ua +ck.ua +cn.ua +cr.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +dnipropetrovsk.ua +dominic.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkiv.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +khmelnytskyi.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +krym.ua +ks.ua +kv.ua +kyiv.ua +lg.ua +lt.ua +lugansk.ua +lutsk.ua +lv.ua +lviv.ua +mk.ua +mykolaiv.ua +nikolaev.ua +od.ua +odesa.ua +odessa.ua +pl.ua +poltava.ua +rivne.ua +rovno.ua +rv.ua +sb.ua +sebastopol.ua +sevastopol.ua +sm.ua +sumy.ua +te.ua +ternopil.ua +uz.ua +uzhgorod.ua +vinnica.ua +vinnytsia.ua +vn.ua +volyn.ua +yalta.ua +zaporizhzhe.ua +zaporizhzhia.ua +zhitomir.ua +zhytomyr.ua +zp.ua +zt.ua + +// Private registries in .ua +co.ua +pp.ua + +// ug : https://www.registry.co.ug/ +ug +co.ug +or.ug +ac.ug +sc.ug +go.ug +ne.ug +com.ug +org.ug + +// uk : http://en.wikipedia.org/wiki/.uk +// Submitted by registry +uk +ac.uk +co.uk +gov.uk +ltd.uk +me.uk +net.uk +nhs.uk +org.uk +plc.uk +police.uk +*.sch.uk + +// us : http://en.wikipedia.org/wiki/.us +us +dni.us +fed.us +isa.us +kids.us +nsn.us +// us geographic names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +vi.us +vt.us +va.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.de.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +k12.ri.us +k12.sc.us +// k12.sd.us Bug 934131 - Removed at request of James Booze +k12.tn.us +k12.tx.us +k12.ut.us +k12.vi.us +k12.vt.us +k12.va.us +k12.wa.us +k12.wi.us +// k12.wv.us Bug 947705 - Removed at request of Verne Britton +k12.wy.us +cc.ak.us +cc.al.us +cc.ar.us +cc.as.us +cc.az.us +cc.ca.us +cc.co.us +cc.ct.us +cc.dc.us +cc.de.us +cc.fl.us +cc.ga.us +cc.gu.us +cc.hi.us +cc.ia.us +cc.id.us +cc.il.us +cc.in.us +cc.ks.us +cc.ky.us +cc.la.us +cc.ma.us +cc.md.us +cc.me.us +cc.mi.us +cc.mn.us +cc.mo.us +cc.ms.us +cc.mt.us +cc.nc.us +cc.nd.us +cc.ne.us +cc.nh.us +cc.nj.us +cc.nm.us +cc.nv.us +cc.ny.us +cc.oh.us +cc.ok.us +cc.or.us +cc.pa.us +cc.pr.us +cc.ri.us +cc.sc.us +cc.sd.us +cc.tn.us +cc.tx.us +cc.ut.us +cc.vi.us +cc.vt.us +cc.va.us +cc.wa.us +cc.wi.us +cc.wv.us +cc.wy.us +lib.ak.us +lib.al.us +lib.ar.us +lib.as.us +lib.az.us +lib.ca.us +lib.co.us +lib.ct.us +lib.dc.us +lib.de.us +lib.fl.us +lib.ga.us +lib.gu.us +lib.hi.us +lib.ia.us +lib.id.us +lib.il.us +lib.in.us +lib.ks.us +lib.ky.us +lib.la.us +lib.ma.us +lib.md.us +lib.me.us +lib.mi.us +lib.mn.us +lib.mo.us +lib.ms.us +lib.mt.us +lib.nc.us +lib.nd.us +lib.ne.us +lib.nh.us +lib.nj.us +lib.nm.us +lib.nv.us +lib.ny.us +lib.oh.us +lib.ok.us +lib.or.us +lib.pa.us +lib.pr.us +lib.ri.us +lib.sc.us +lib.sd.us +lib.tn.us +lib.tx.us +lib.ut.us +lib.vi.us +lib.vt.us +lib.va.us +lib.wa.us +lib.wi.us +// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold +lib.wy.us +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed indepedently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated dorectly to the +// 5LD operators. +pvt.k12.ma.us +chtr.k12.ma.us +paroch.k12.ma.us + +// uy : http://www.nic.org.uy/ +uy +com.uy +edu.uy +gub.uy +mil.uy +net.uy +org.uy + +// uz : http://www.reg.uz/ +uz +co.uz +com.uz +net.uz +org.uz + +// va : http://en.wikipedia.org/wiki/.va +va + +// vc : http://en.wikipedia.org/wiki/.vc +// Submitted by registry 2008-06-13 +vc +com.vc +net.vc +org.vc +gov.vc +mil.vc +edu.vc + +// ve : https://registro.nic.ve/ +// Confirmed by registry 2012-10-04 +// Updated 2014-05-20 - Bug 940478 +ve +arts.ve +co.ve +com.ve +e12.ve +edu.ve +firm.ve +gob.ve +gov.ve +info.ve +int.ve +mil.ve +net.ve +org.ve +rec.ve +store.ve +tec.ve +web.ve + +// vg : http://en.wikipedia.org/wiki/.vg +vg + +// vi : http://www.nic.vi/newdomainform.htm +// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other +// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they +// are available for registration (which they do not seem to be). +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +vn +com.vn +net.vn +org.vn +edu.vn +gov.vn +int.vn +ac.vn +biz.vn +info.vn +name.vn +pro.vn +health.vn + +// vu : http://en.wikipedia.org/wiki/.vu +// http://www.vunic.vu/ +vu +com.vu +edu.vu +net.vu +org.vu + +// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +wf + +// ws : http://en.wikipedia.org/wiki/.ws +// http://samoanic.ws/index.dhtml +ws +com.ws +net.ws +org.ws +gov.ws +edu.ws + +// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +yt + +// IDN ccTLDs +// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then +// U-label, and follow this format: +// // A-Label ("", [, variant info]) : +// // [sponsoring org] +// U-Label + +// xn--mgbaam7a8h ("Emerat", Arabic) : AE +// http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--y9a3aq ("hye", Armenian) : AM +// ISOC AM (operated by .am Registry) +հայ + +// xn--54b7fta0cc ("Bangla", Bangla) : BD +বাংলা + +// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY +// Operated by .by registry +бел + +// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中国 + +// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中國 + +// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt/Masr", Arabic) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--node ("ge", Georgian Mkhedruli) : GE +გე + +// xn--qxam ("el", Greek) : GR +// Hellenic Ministry of Infrastructure, Transport, and Networks +ελ + +// xn--j6w193g ("Hong Kong", Chinese) : HK +// https://www2.hkirc.hk/register/rules.jsp +香港 + +// xn--h2brj9c ("Bharat", Devanagari) : IN +// India +भारत + +// xn--mgbbh1a71e ("Bharat", Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat", Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat", Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat", Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat", Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India", Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran", Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran", Arabic) : IR +ايران + +// xn--mgbtx2b ("Iraq", Arabic) : IQ +// Communications and Media Commission +عراق + +// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO +// National Information Technology Center (NITC) +// Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea", Hangul) : KR +한국 + +// xn--80ao21a ("Kaz", Kazakh) : KZ +қаз + +// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK +// http://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK +// http://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA +المغرب + +// xn--d1alf ("mkd", Macedonian) : MK +// MARnet +мкд + +// xn--l1acc ("mon", Mongolian) : MN +мон + +// xn--mix891f ("Macao", Chinese, Traditional) : MO +// MONIC / HNET Asia (Registry Operator for .mo) +澳門 + +// xn--mix082f ("Macao", Chinese, Simplified) : MO +澳门 + +// xn--mgbx4cd0ab ("Malaysia", Malay) : MY +مليسيا + +// xn--mgb9awbf ("Oman", Arabic) : OM +عمان + +// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK +پاکستان + +// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK +پاكستان + +// xn--ygbi2ammx ("Falasteen", Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb", Cyrillic) : RS +// http://www.rnids.rs/en/the-.срб-domain +срб +пр.срб +орг.срб +обр.срб +од.срб +упр.срб +ак.срб + +// xn--p1ai ("rf", Russian-Cyrillic) : RU +// http://www.cctld.ru/en/docs/rulesrf.php +рф + +// xn--wgbl6a ("Qatar", Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA +السعوديه + +// xn--mgbpl2fh ("sudan", Arabic) : SD +// Operated by .sd registry +سودان + +// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG +சிங்கப்பூர் + +// xn--ogbpf8fl ("Syria", Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria", Arabic, variant) : SY +سوريا + +// xn--o3cw4h ("Thai", Thai) : TH +// http://www.thnic.co.th +ไทย + +// xn--pgbs0dh ("Tunisia", Arabic) : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台灣 + +// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan", Chinese, variant) : TW +臺灣 + +// xn--j1amh ("ukr", Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen", Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +*.ye + +// za : http://www.zadna.org.za/content/page/domain-information +ac.za +agrica.za +alt.za +co.za +edu.za +gov.za +grondar.za +law.za +mil.za +net.za +ngo.za +nis.za +nom.za +org.za +school.za +tm.za +web.za + +// zm : http://en.wikipedia.org/wiki/.zm +*.zm + +// zw : http://en.wikipedia.org/wiki/.zw +*.zw + + +// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-07-27T22:08:32Z + +// aaa : 2015-02-26 American Automobile Association, Inc. +aaa + +// aarp : 2015-05-21 AARP +aarp + +// abb : 2014-10-24 ABB Ltd +abb + +// abbott : 2014-07-24 Abbott Laboratories, Inc. +abbott + +// able : 2015-06-25 Able Inc. +able + +// abogado : 2014-04-24 Top Level Domain Holdings Limited +abogado + +// academy : 2013-11-07 Half Oaks, LLC +academy + +// accenture : 2014-08-15 Accenture plc +accenture + +// accountant : 2014-11-20 dot Accountant Limited +accountant + +// accountants : 2014-03-20 Knob Town, LLC +accountants + +// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +aco + +// active : 2014-05-01 The Active Network, Inc +active + +// actor : 2013-12-12 United TLD Holdco Ltd. +actor + +// adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC) +adac + +// ads : 2014-12-04 Charleston Road Registry Inc. +ads + +// adult : 2014-10-16 ICM Registry AD LLC +adult + +// aeg : 2015-03-19 Aktiebolaget Electrolux +aeg + +// aetna : 2015-05-21 Aetna Life Insurance Company +aetna + +// afamilycompany : 2015-07-23 Johnson Shareholdings, Inc. +afamilycompany + +// afl : 2014-10-02 Australian Football League +afl + +// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +africa + +// africamagic : 2015-03-05 Electronic Media Network (Pty) Ltd +africamagic + +// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +agakhan + +// agency : 2013-11-14 Steel Falls, LLC +agency + +// aig : 2014-12-18 American International Group, Inc. +aig + +// airforce : 2014-03-06 United TLD Holdco Ltd. +airforce + +// airtel : 2014-10-24 Bharti Airtel Limited +airtel + +// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +akdn + +// alibaba : 2015-01-15 Alibaba Group Holding Limited +alibaba + +// alipay : 2015-01-15 Alibaba Group Holding Limited +alipay + +// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +allfinanz + +// ally : 2015-06-18 Ally Financial Inc. +ally + +// alsace : 2014-07-02 REGION D ALSACE +alsace + +// americanfamily : 2015-07-23 AmFam, Inc. +americanfamily + +// amfam : 2015-07-23 AmFam, Inc. +amfam + +// amica : 2015-05-28 Amica Mutual Insurance Company +amica + +// amsterdam : 2014-07-24 Gemeente Amsterdam +amsterdam + +// analytics : 2014-12-18 Campus IP LLC +analytics + +// android : 2014-08-07 Charleston Road Registry Inc. +android + +// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +anquan + +// apartments : 2014-12-11 June Maple, LLC +apartments + +// app : 2015-05-14 Charleston Road Registry Inc. +app + +// apple : 2015-05-14 Apple Inc. +apple + +// aquarelle : 2014-07-24 Aquarelle.com +aquarelle + +// aramco : 2014-11-20 Aramco Services Company +aramco + +// archi : 2014-02-06 STARTING DOT LIMITED +archi + +// army : 2014-03-06 United TLD Holdco Ltd. +army + +// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +arte + +// associates : 2014-03-06 Baxter Hill, LLC +associates + +// attorney : 2014-03-20 +attorney + +// auction : 2014-03-20 +auction + +// audi : 2015-05-21 AUDI Aktiengesellschaft +audi + +// audible : 2015-06-25 Amazon EU S.à r.l. +audible + +// audio : 2014-03-20 Uniregistry, Corp. +audio + +// author : 2014-12-18 Amazon EU S.à r.l. +author + +// auto : 2014-11-13 +auto + +// autos : 2014-01-09 DERAutos, LLC +autos + +// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca +avianca + +// aws : 2015-06-25 Amazon EU S.à r.l. +aws + +// axa : 2013-12-19 AXA SA +axa + +// azure : 2014-12-18 Microsoft Corporation +azure + +// baby : 2015-04-09 Johnson & Johnson Services, Inc. +baby + +// baidu : 2015-01-08 Baidu, Inc. +baidu + +// band : 2014-06-12 +band + +// bank : 2014-09-25 fTLD Registry Services LLC +bank + +// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +bar + +// barcelona : 2014-07-24 Municipi de Barcelona +barcelona + +// barclaycard : 2014-11-20 Barclays Bank PLC +barclaycard + +// barclays : 2014-11-20 Barclays Bank PLC +barclays + +// barefoot : 2015-06-11 Gallo Vineyards, Inc. +barefoot + +// bargains : 2013-11-14 Half Hallow, LLC +bargains + +// bauhaus : 2014-04-17 Werkhaus GmbH +bauhaus + +// bayern : 2014-01-23 Bayern Connect GmbH +bayern + +// bbc : 2014-12-18 British Broadcasting Corporation +bbc + +// bbt : 2015-07-23 BB&T Corporation +bbt + +// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +bbva + +// bcg : 2015-04-02 The Boston Consulting Group, Inc. +bcg + +// bcn : 2014-07-24 Municipi de Barcelona +bcn + +// beats : 2015-05-14 Beats Electronics, LLC +beats + +// beer : 2014-01-09 Top Level Domain Holdings Limited +beer + +// bentley : 2014-12-18 Bentley Motors Limited +bentley + +// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +berlin + +// best : 2013-12-19 BestTLD Pty Ltd +best + +// bet : 2015-05-07 Afilias plc +bet + +// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +bharti + +// bible : 2014-06-19 American Bible Society +bible + +// bid : 2013-12-19 dot Bid Limited +bid + +// bike : 2013-08-27 Grand Hollow, LLC +bike + +// bing : 2014-12-18 Microsoft Corporation +bing + +// bingo : 2014-12-04 Sand Cedar, LLC +bingo + +// bio : 2014-03-06 STARTING DOT LIMITED +bio + +// black : 2014-01-16 Afilias Limited +black + +// blackfriday : 2014-01-16 Uniregistry, Corp. +blackfriday + +// blanco : 2015-07-16 BLANCO GmbH + Co KG +blanco + +// blog : 2015-05-14 PRIMER NIVEL S.A. +blog + +// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +bloomberg + +// blue : 2013-11-07 Afilias Limited +blue + +// bms : 2014-10-30 Bristol-Myers Squibb Company +bms + +// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +bmw + +// bnl : 2014-07-24 Banca Nazionale del Lavoro +bnl + +// bnpparibas : 2014-05-29 BNP Paribas +bnpparibas + +// boats : 2014-12-04 DERBoats, LLC +boats + +// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH +boehringer + +// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +bom + +// bond : 2014-06-05 Bond University Limited +bond + +// boo : 2014-01-30 Charleston Road Registry Inc. +boo + +// booking : 2015-07-16 Booking.com B.V. +booking + +// boots : 2015-01-08 THE BOOTS COMPANY PLC +boots + +// bosch : 2015-06-18 Robert Bosch GMBH +bosch + +// bostik : 2015-05-28 Bostik SA +bostik + +// bot : 2014-12-18 Amazon EU S.à r.l. +bot + +// boutique : 2013-11-14 Over Galley, LLC +boutique + +// bradesco : 2014-12-18 Banco Bradesco S.A. +bradesco + +// bridgestone : 2014-12-18 Bridgestone Corporation +bridgestone + +// broadway : 2014-12-22 Celebrate Broadway, Inc. +broadway + +// broker : 2014-12-11 IG Group Holdings PLC +broker + +// brother : 2015-01-29 Brother Industries, Ltd. +brother + +// brussels : 2014-02-06 DNS.be vzw +brussels + +// budapest : 2013-11-21 Top Level Domain Holdings Limited +budapest + +// bugatti : 2015-07-23 Bugatti International SA +bugatti + +// build : 2013-11-07 Plan Bee LLC +build + +// builders : 2013-11-07 Atomic Madison, LLC +builders + +// business : 2013-11-07 Spring Cross, LLC +business + +// buy : 2014-12-18 Amazon EU S.à r.l. +buy + +// buzz : 2013-10-02 DOTSTRATEGY CO. +buzz + +// bzh : 2014-02-27 Association www.bzh +bzh + +// cab : 2013-10-24 Half Sunset, LLC +cab + +// cafe : 2015-02-11 Pioneer Canyon, LLC +cafe + +// cal : 2014-07-24 Charleston Road Registry Inc. +cal + +// call : 2014-12-18 Amazon EU S.à r.l. +call + +// camera : 2013-08-27 Atomic Maple, LLC +camera + +// camp : 2013-11-07 Delta Dynamite, LLC +camp + +// cancerresearch : 2014-05-15 Australian Cancer Research Foundation +cancerresearch + +// canon : 2014-09-12 Canon Inc. +canon + +// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +capetown + +// capital : 2014-03-06 Delta Mill, LLC +capital + +// car : 2015-01-22 +car + +// caravan : 2013-12-12 Caravan International, Inc. +caravan + +// cards : 2013-12-05 Foggy Hollow, LLC +cards + +// care : 2014-03-06 Goose Cross +care + +// career : 2013-10-09 dotCareer LLC +career + +// careers : 2013-10-02 Wild Corner, LLC +careers + +// cars : 2014-11-13 +cars + +// cartier : 2014-06-23 Richemont DNS Inc. +cartier + +// casa : 2013-11-21 Top Level Domain Holdings Limited +casa + +// cash : 2014-03-06 Delta Lake, LLC +cash + +// casino : 2014-12-18 Binky Sky, LLC +casino + +// catering : 2013-12-05 New Falls. LLC +catering + +// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +cba + +// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +cbn + +// cbre : 2015-07-02 CBRE, Inc. +cbre + +// ceb : 2015-04-09 The Corporate Executive Board Company +ceb + +// center : 2013-11-07 Tin Mill, LLC +center + +// ceo : 2013-11-07 CEOTLD Pty Ltd +ceo + +// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +cern + +// cfa : 2014-08-28 CFA Institute +cfa + +// cfd : 2014-12-11 IG Group Holdings PLC +cfd + +// chanel : 2015-04-09 Chanel International B.V. +chanel + +// channel : 2014-05-08 Charleston Road Registry Inc. +channel + +// chase : 2015-04-30 JPMorgan Chase & Co. +chase + +// chat : 2014-12-04 Sand Fields, LLC +chat + +// cheap : 2013-11-14 Sand Cover, LLC +cheap + +// chintai : 2015-06-11 CHINTAI Corporation +chintai + +// chloe : 2014-10-16 Richemont DNS Inc. +chloe + +// christmas : 2013-11-21 Uniregistry, Corp. +christmas + +// chrome : 2014-07-24 Charleston Road Registry Inc. +chrome + +// church : 2014-02-06 Holly Fields, LLC +church + +// cipriani : 2015-02-19 Hotel Cipriani Srl +cipriani + +// circle : 2014-12-18 Amazon EU S.à r.l. +circle + +// cisco : 2014-12-22 Cisco Technology, Inc. +cisco + +// citadel : 2015-07-23 Citadel Domain LLC +citadel + +// citic : 2014-01-09 CITIC Group Corporation +citic + +// city : 2014-05-29 Snow Sky, LLC +city + +// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. +cityeats + +// claims : 2014-03-20 Black Corner, LLC +claims + +// cleaning : 2013-12-05 Fox Shadow, LLC +cleaning + +// click : 2014-06-05 Uniregistry, Corp. +click + +// clinic : 2014-03-20 Goose Park, LLC +clinic + +// clothing : 2013-08-27 Steel Lake, LLC +clothing + +// cloud : 2015-04-16 ARUBA S.p.A. +cloud + +// club : 2013-11-08 .CLUB DOMAINS, LLC +club + +// clubmed : 2015-06-25 Club Méditerranée S.A. +clubmed + +// coach : 2014-10-09 Koko Island, LLC +coach + +// codes : 2013-10-31 Puff Willow, LLC +codes + +// coffee : 2013-10-17 Trixy Cover, LLC +coffee + +// college : 2014-01-16 XYZ.COM LLC +college + +// cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH +cologne + +// comcast : 2015-07-23 Comcast IP Holdings I, LLC +comcast + +// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +commbank + +// community : 2013-12-05 Fox Orchard, LLC +community + +// company : 2013-11-07 Silver Avenue, LLC +company + +// computer : 2013-10-24 Pine Mill, LLC +computer + +// comsec : 2015-01-08 VeriSign, Inc. +comsec + +// condos : 2013-12-05 Pine House, LLC +condos + +// construction : 2013-09-16 Fox Dynamite, LLC +construction + +// consulting : 2013-12-05 +consulting + +// contact : 2015-01-08 Top Level Spectrum, Inc. +contact + +// contractors : 2013-09-10 Magic Woods, LLC +contractors + +// cooking : 2013-11-21 Top Level Domain Holdings Limited +cooking + +// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +cookingchannel + +// cool : 2013-11-14 Koko Lake, LLC +cool + +// corsica : 2014-09-25 Collectivité Territoriale de Corse +corsica + +// country : 2013-12-19 Top Level Domain Holdings Limited +country + +// coupon : 2015-02-26 Amazon EU S.à r.l. +coupon + +// coupons : 2015-03-26 Black Island, LLC +coupons + +// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD +courses + +// credit : 2014-03-20 Snow Shadow, LLC +credit + +// creditcard : 2014-03-20 Binky Frostbite, LLC +creditcard + +// creditunion : 2015-01-22 CUNA Performance Resources, LLC +creditunion + +// cricket : 2014-10-09 dot Cricket Limited +cricket + +// crown : 2014-10-24 Crown Equipment Corporation +crown + +// crs : 2014-04-03 Federated Co-operatives Limited +crs + +// cruises : 2013-12-05 Spring Way, LLC +cruises + +// csc : 2014-09-25 Alliance-One Services, Inc. +csc + +// cuisinella : 2014-04-03 SALM S.A.S. +cuisinella + +// cymru : 2014-05-08 Nominet UK +cymru + +// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd. +cyou + +// dabur : 2014-02-06 Dabur India Limited +dabur + +// dad : 2014-01-23 Charleston Road Registry Inc. +dad + +// dance : 2013-10-24 United TLD Holdco Ltd. +dance + +// date : 2014-11-20 dot Date Limited +date + +// dating : 2013-12-05 Pine Fest, LLC +dating + +// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +datsun + +// day : 2014-01-30 Charleston Road Registry Inc. +day + +// dclk : 2014-11-20 Charleston Road Registry Inc. +dclk + +// dds : 2015-05-07 Top Level Domain Holdings Limited +dds + +// deal : 2015-06-25 Amazon EU S.à r.l. +deal + +// dealer : 2014-12-22 Dealer Dot Com, Inc. +dealer + +// deals : 2014-05-22 Sand Sunset, LLC +deals + +// degree : 2014-03-06 +degree + +// delivery : 2014-09-11 Steel Station, LLC +delivery + +// dell : 2014-10-24 Dell Inc. +dell + +// delta : 2015-02-19 Delta Air Lines, Inc. +delta + +// democrat : 2013-10-24 United TLD Holdco Ltd. +democrat + +// dental : 2014-03-20 Tin Birch, LLC +dental + +// dentist : 2014-03-20 +dentist + +// desi : 2013-11-14 Desi Networks LLC +desi + +// design : 2014-11-07 Top Level Design, LLC +design + +// dev : 2014-10-16 Charleston Road Registry Inc. +dev + +// dhl : 2015-07-23 Deutsche Post AG +dhl + +// diamonds : 2013-09-22 John Edge, LLC +diamonds + +// diet : 2014-06-26 Uniregistry, Corp. +diet + +// digital : 2014-03-06 Dash Park, LLC +digital + +// direct : 2014-04-10 Half Trail, LLC +direct + +// directory : 2013-09-20 Extra Madison, LLC +directory + +// discount : 2014-03-06 Holly Hill, LLC +discount + +// discover : 2015-07-23 Discover Financial Services +discover + +// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +dnp + +// docs : 2014-10-16 Charleston Road Registry Inc. +docs + +// dog : 2014-12-04 Koko Mill, LLC +dog + +// doha : 2014-09-18 Communications Regulatory Authority (CRA) +doha + +// domains : 2013-10-17 Sugar Cross, LLC +domains + +// doosan : 2014-04-03 Doosan Corporation +doosan + +// dot : 2015-05-21 Dish DBS Corporation +dot + +// download : 2014-11-20 dot Support Limited +download + +// drive : 2015-03-05 Charleston Road Registry Inc. +drive + +// dstv : 2015-03-12 MultiChoice (Proprietary) Limited +dstv + +// dtv : 2015-06-04 Dish DBS Corporation +dtv + +// dubai : 2015-01-01 Dubai Smart Government Department +dubai + +// duck : 2015-07-23 Johnson Shareholdings, Inc. +duck + +// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company +dunlop + +// dupont : 2015-06-25 E.I. du Pont de Nemours and Company +dupont + +// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +durban + +// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +dvag + +// dwg : 2015-07-23 Autodesk, Inc. +dwg + +// earth : 2014-12-04 Interlink Co., Ltd. +earth + +// eat : 2014-01-23 Charleston Road Registry Inc. +eat + +// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +edeka + +// education : 2013-11-07 Brice Way, LLC +education + +// email : 2013-10-31 Spring Madison, LLC +email + +// emerck : 2014-04-03 Merck KGaA +emerck + +// emerson : 2015-07-23 Emerson Electric Co. +emerson + +// energy : 2014-09-11 Binky Birch, LLC +energy + +// engineer : 2014-03-06 United TLD Holdco Ltd. +engineer + +// engineering : 2014-03-06 Romeo Canyon +engineering + +// enterprises : 2013-09-20 Snow Oaks, LLC +enterprises + +// epost : 2015-07-23 Deutsche Post AG +epost + +// epson : 2014-12-04 Seiko Epson Corporation +epson + +// equipment : 2013-08-27 Corn Station, LLC +equipment + +// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson +ericsson + +// erni : 2014-04-03 ERNI Group Holding AG +erni + +// esq : 2014-05-08 Charleston Road Registry Inc. +esq + +// estate : 2013-08-27 Trixy Park, LLC +estate + +// esurance : 2015-07-23 Esurance Insurance Company +esurance + +// eurovision : 2014-04-24 European Broadcasting Union (EBU) +eurovision + +// eus : 2013-12-12 Puntueus Fundazioa +eus + +// events : 2013-12-05 Pioneer Maple, LLC +events + +// everbank : 2014-05-15 EverBank +everbank + +// exchange : 2014-03-06 Spring Falls, LLC +exchange + +// expert : 2013-11-21 Magic Pass, LLC +expert + +// exposed : 2013-12-05 Victor Beach, LLC +exposed + +// express : 2015-02-11 Sea Sunset, LLC +express + +// extraspace : 2015-05-14 Extra Space Storage LLC +extraspace + +// fage : 2014-12-18 Fage International S.A. +fage + +// fail : 2014-03-06 Atomic Pipe, LLC +fail + +// fairwinds : 2014-11-13 FairWinds Partners, LLC +fairwinds + +// faith : 2014-11-20 dot Faith Limited +faith + +// family : 2015-04-02 +family + +// fan : 2014-03-06 +fan + +// fans : 2014-11-07 Asiamix Digital Limited +fans + +// farm : 2013-11-07 Just Maple, LLC +farm + +// farmers : 2015-07-09 Farmers Insurance Exchange +farmers + +// fashion : 2014-07-03 Top Level Domain Holdings Limited +fashion + +// fast : 2014-12-18 Amazon EU S.à r.l. +fast + +// feedback : 2013-12-19 Top Level Spectrum, Inc. +feedback + +// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +ferrero + +// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +film + +// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +final + +// finance : 2014-03-20 Cotton Cypress, LLC +finance + +// financial : 2014-03-06 Just Cover, LLC +financial + +// fire : 2015-06-25 Amazon EU S.à r.l. +fire + +// firestone : 2014-12-18 Bridgestone Corporation +firestone + +// firmdale : 2014-03-27 Firmdale Holdings Limited +firmdale + +// fish : 2013-12-12 Fox Woods, LLC +fish + +// fishing : 2013-11-21 Top Level Domain Holdings Limited +fishing + +// fit : 2014-11-07 Top Level Domain Holdings Limited +fit + +// fitness : 2014-03-06 Brice Orchard, LLC +fitness + +// flickr : 2015-04-02 Yahoo! Domain Services Inc. +flickr + +// flights : 2013-12-05 Fox Station, LLC +flights + +// flir : 2015-07-23 FLIR Systems, Inc. +flir + +// florist : 2013-11-07 Half Cypress, LLC +florist + +// flowers : 2014-10-09 Uniregistry, Corp. +flowers + +// flsmidth : 2014-07-24 FLSmidth A/S +flsmidth + +// fly : 2014-05-08 Charleston Road Registry Inc. +fly + +// foo : 2014-01-23 Charleston Road Registry Inc. +foo + +// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. +foodnetwork + +// football : 2014-12-18 Foggy Farms, LLC +football + +// ford : 2014-11-13 Ford Motor Company +ford + +// forex : 2014-12-11 IG Group Holdings PLC +forex + +// forsale : 2014-05-22 +forsale + +// forum : 2015-04-02 Fegistry, LLC +forum + +// foundation : 2013-12-05 John Dale, LLC +foundation + +// frl : 2014-05-15 FRLregistry B.V. +frl + +// frogans : 2013-12-19 OP3FT +frogans + +// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. +frontdoor + +// frontier : 2015-02-05 Frontier Communications Corporation +frontier + +// ftr : 2015-07-16 Frontier Communications Corporation +ftr + +// fujixerox : 2015-07-23 Xerox DNHC LLC +fujixerox + +// fund : 2014-03-20 John Castle, LLC +fund + +// furniture : 2014-03-20 Lone Fields, LLC +furniture + +// futbol : 2013-09-20 +futbol + +// fyi : 2015-04-02 Silver Tigers, LLC +fyi + +// gal : 2013-11-07 Asociación puntoGAL +gal + +// gallery : 2013-09-13 Sugar House, LLC +gallery + +// gallo : 2015-06-11 Gallo Vineyards, Inc. +gallo + +// gallup : 2015-02-19 Gallup, Inc. +gallup + +// game : 2015-05-28 Uniregistry, Corp. +game + +// games : 2015-05-28 Foggy Beach, LLC +games + +// garden : 2014-06-26 Top Level Domain Holdings Limited +garden + +// gbiz : 2014-07-17 Charleston Road Registry Inc. +gbiz + +// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +gdn + +// gea : 2014-12-04 GEA Group Aktiengesellschaft +gea + +// gent : 2014-01-23 COMBELL GROUP NV/SA +gent + +// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +genting + +// ggee : 2014-01-09 GMO Internet, Inc. +ggee + +// gift : 2013-10-17 Uniregistry, Corp. +gift + +// gifts : 2014-07-03 Goose Sky, LLC +gifts + +// gives : 2014-03-06 United TLD Holdco Ltd. +gives + +// giving : 2014-11-13 Giving Limited +giving + +// glade : 2015-07-23 Johnson Shareholdings, Inc. +glade + +// glass : 2013-11-07 Black Cover, LLC +glass + +// gle : 2014-07-24 Charleston Road Registry Inc. +gle + +// global : 2014-04-17 Dot GLOBAL AS +global + +// globo : 2013-12-19 Globo Comunicação e Participações S.A +globo + +// gmail : 2014-05-01 Charleston Road Registry Inc. +gmail + +// gmo : 2014-01-09 GMO Internet, Inc. +gmo + +// gmx : 2014-04-24 1&1 Mail & Media GmbH +gmx + +// godaddy : 2015-07-23 Go Daddy East, LLC +godaddy + +// gold : 2015-01-22 June Edge, LLC +gold + +// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +goldpoint + +// golf : 2014-12-18 Lone falls, LLC +golf + +// goo : 2014-12-18 NTT Resonant Inc. +goo + +// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company +goodyear + +// goog : 2014-11-20 Charleston Road Registry Inc. +goog + +// google : 2014-07-24 Charleston Road Registry Inc. +google + +// gop : 2014-01-16 Republican State Leadership Committee, Inc. +gop + +// got : 2014-12-18 Amazon EU S.à r.l. +got + +// gotv : 2015-03-12 MultiChoice (Proprietary) Limited +gotv + +// grainger : 2015-05-07 Grainger Registry Services, LLC +grainger + +// graphics : 2013-09-13 Over Madison, LLC +graphics + +// gratis : 2014-03-20 Pioneer Tigers, LLC +gratis + +// green : 2014-05-08 Afilias Limited +green + +// gripe : 2014-03-06 Corn Sunset, LLC +gripe + +// group : 2014-08-15 Romeo Town, LLC +group + +// gucci : 2014-11-13 Guccio Gucci S.p.a. +gucci + +// guge : 2014-08-28 Charleston Road Registry Inc. +guge + +// guide : 2013-09-13 Snow Moon, LLC +guide + +// guitars : 2013-11-14 Uniregistry, Corp. +guitars + +// guru : 2013-08-27 Pioneer Cypress, LLC +guru + +// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +hamburg + +// hangout : 2014-11-13 Charleston Road Registry Inc. +hangout + +// haus : 2013-12-05 +haus + +// hdfcbank : 2015-02-12 HDFC Bank Limited +hdfcbank + +// health : 2015-02-11 DotHealth, LLC +health + +// healthcare : 2014-06-12 Silver Glen, LLC +healthcare + +// help : 2014-06-26 Uniregistry, Corp. +help + +// helsinki : 2015-02-05 City of Helsinki +helsinki + +// here : 2014-02-06 Charleston Road Registry Inc. +here + +// hermes : 2014-07-10 HERMES INTERNATIONAL +hermes + +// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. +hgtv + +// hiphop : 2014-03-06 Uniregistry, Corp. +hiphop + +// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. +hisamitsu + +// hitachi : 2014-10-31 Hitachi, Ltd. +hitachi + +// hiv : 2014-03-13 dotHIV gemeinnuetziger e.V. +hiv + +// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited +hkt + +// hockey : 2015-03-19 Half Willow, LLC +hockey + +// holdings : 2013-08-27 John Madison, LLC +holdings + +// holiday : 2013-11-07 Goose Woods, LLC +holiday + +// homedepot : 2015-04-02 Homer TLC, Inc. +homedepot + +// homegoods : 2015-07-16 The TJX Companies, Inc. +homegoods + +// homes : 2014-01-09 DERHomes, LLC +homes + +// homesense : 2015-07-16 The TJX Companies, Inc. +homesense + +// honda : 2014-12-18 Honda Motor Co., Ltd. +honda + +// honeywell : 2015-07-23 Honeywell GTLD LLC +honeywell + +// horse : 2013-11-21 Top Level Domain Holdings Limited +horse + +// host : 2014-04-17 DotHost Inc. +host + +// hosting : 2014-05-29 Uniregistry, Corp. +hosting + +// hoteles : 2015-03-05 Travel Reservations SRL +hoteles + +// hotmail : 2014-12-18 Microsoft Corporation +hotmail + +// house : 2013-11-07 Sugar Park, LLC +house + +// how : 2014-01-23 Charleston Road Registry Inc. +how + +// hsbc : 2014-10-24 HSBC Holdings PLC +hsbc + +// htc : 2015-04-02 HTC corporation +htc + +// hyundai : 2015-07-09 Hyundai Motor Company +hyundai + +// ibm : 2014-07-31 International Business Machines Corporation +ibm + +// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +icbc + +// ice : 2014-10-30 IntercontinentalExchange, Inc. +ice + +// icu : 2015-01-08 One.com A/S +icu + +// ieee : 2015-07-23 IEEE Global LLC +ieee + +// ifm : 2014-01-30 ifm electronic gmbh +ifm + +// iinet : 2014-07-03 Connect West Pty. Ltd. +iinet + +// ikano : 2015-07-09 Ikano S.A. +ikano + +// imdb : 2015-06-25 Amazon EU S.à r.l. +imdb + +// immo : 2014-07-10 Auburn Bloom, LLC +immo + +// immobilien : 2013-11-07 United TLD Holdco Ltd. +immobilien + +// industries : 2013-12-05 Outer House, LLC +industries + +// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +infiniti + +// ing : 2014-01-23 Charleston Road Registry Inc. +ing + +// ink : 2013-12-05 Top Level Design, LLC +ink + +// institute : 2013-11-07 Outer Maple, LLC +institute + +// insurance : 2015-02-19 fTLD Registry Services LLC +insurance + +// insure : 2014-03-20 Pioneer Willow, LLC +insure + +// international : 2013-11-07 Wild Way, LLC +international + +// investments : 2014-03-20 Holly Glen, LLC +investments + +// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +ipiranga + +// irish : 2014-08-07 Dot-Irish LLC +irish + +// iselect : 2015-02-11 iSelect Ltd +iselect + +// ist : 2014-08-28 Istanbul Metropolitan Municipality +ist + +// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +istanbul + +// itau : 2014-10-02 Itau Unibanco Holding S.A. +itau + +// itv : 2015-07-09 ITV Services Limited +itv + +// iwc : 2014-06-23 Richemont DNS Inc. +iwc + +// jaguar : 2014-11-13 Jaguar Land Rover Ltd +jaguar + +// java : 2014-06-19 Oracle Corporation +java + +// jcb : 2014-11-20 JCB Co., Ltd. +jcb + +// jcp : 2015-04-23 JCP Media, Inc. +jcp + +// jetzt : 2014-01-09 New TLD Company AB +jetzt + +// jewelry : 2015-03-05 Wild Bloom, LLC +jewelry + +// jio : 2015-04-02 Affinity Names, Inc. +jio + +// jlc : 2014-12-04 Richemont DNS Inc. +jlc + +// jll : 2015-04-02 Jones Lang LaSalle Incorporated +jll + +// jmp : 2015-03-26 Matrix IP LLC +jmp + +// jnj : 2015-06-18 Johnson & Johnson Services, Inc. +jnj + +// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +joburg + +// jot : 2014-12-18 Amazon EU S.à r.l. +jot + +// joy : 2014-12-18 Amazon EU S.à r.l. +joy + +// jpmorgan : 2015-04-30 JPMorgan Chase & Co. +jpmorgan + +// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +jprs + +// juegos : 2014-03-20 Uniregistry, Corp. +juegos + +// kaufen : 2013-11-07 United TLD Holdco Ltd. +kaufen + +// kddi : 2014-09-12 KDDI CORPORATION +kddi + +// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +kerryhotels + +// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +kerrylogistics + +// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +kerryproperties + +// kfh : 2014-12-04 Kuwait Finance House +kfh + +// kia : 2015-07-09 KIA MOTORS CORPORATION +kia + +// kim : 2013-09-23 Afilias Limited +kim + +// kinder : 2014-11-07 Ferrero Trading Lux S.A. +kinder + +// kindle : 2015-06-25 Amazon EU S.à r.l. +kindle + +// kitchen : 2013-09-20 Just Goodbye, LLC +kitchen + +// kiwi : 2013-09-20 DOT KIWI LIMITED +kiwi + +// koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH +koeln + +// komatsu : 2015-01-08 Komatsu Ltd. +komatsu + +// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +kpmg + +// kpn : 2015-01-08 Koninklijke KPN N.V. +kpn + +// krd : 2013-12-05 KRG Department of Information Technology +krd + +// kred : 2013-12-19 KredTLD Pty Ltd +kred + +// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +kuokgroup + +// kyknet : 2015-03-05 Electronic Media Network (Pty) Ltd +kyknet + +// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +kyoto + +// lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA +lacaixa + +// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. +lamborghini + +// lancaster : 2015-02-12 LANCASTER +lancaster + +// lancome : 2015-07-23 L'Oréal +lancome + +// land : 2013-09-10 Pine Moon, LLC +land + +// landrover : 2014-11-13 Jaguar Land Rover Ltd +landrover + +// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +lasalle + +// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico +lat + +// latrobe : 2014-06-16 La Trobe University +latrobe + +// law : 2015-01-22 Minds + Machines Group Limited +law + +// lawyer : 2014-03-20 +lawyer + +// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant") +lds + +// lease : 2014-03-06 Victor Trail, LLC +lease + +// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +leclerc + +// lefrak : 2015-07-16 LeFrak Organization, Inc. +lefrak + +// legal : 2014-10-16 Blue Falls, LLC +legal + +// lego : 2015-07-16 LEGO Juris A/S +lego + +// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +lexus + +// lgbt : 2014-05-08 Afilias Limited +lgbt + +// liaison : 2014-10-02 Liaison Technologies, Incorporated +liaison + +// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +lidl + +// life : 2014-02-06 Trixy Oaks, LLC +life + +// lifeinsurance : 2015-01-15 American Council of Life Insurers +lifeinsurance + +// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +lifestyle + +// lighting : 2013-08-27 John McCook, LLC +lighting + +// like : 2014-12-18 Amazon EU S.à r.l. +like + +// limited : 2014-03-06 Big Fest, LLC +limited + +// limo : 2013-10-17 Hidden Frostbite, LLC +limo + +// lincoln : 2014-11-13 Ford Motor Company +lincoln + +// linde : 2014-12-04 Linde Aktiengesellschaft +linde + +// link : 2013-11-14 Uniregistry, Corp. +link + +// lipsy : 2015-06-25 Lipsy Ltd +lipsy + +// live : 2014-12-04 +live + +// lixil : 2015-03-19 LIXIL Group Corporation +lixil + +// loan : 2014-11-20 dot Loan Limited +loan + +// loans : 2014-03-20 June Woods, LLC +loans + +// locker : 2015-06-04 Dish DBS Corporation +locker + +// locus : 2015-06-25 Locus Analytics LLC +locus + +// lol : 2015-01-30 Uniregistry, Corp. +lol + +// london : 2013-11-14 Dot London Domains Limited +london + +// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +lotte + +// lotto : 2014-04-10 Afilias Limited +lotto + +// love : 2014-12-22 Merchant Law Group LLP +love + +// ltd : 2014-09-25 Over Corner, LLC +ltd + +// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA +ltda + +// lupin : 2014-11-07 LUPIN LIMITED +lupin + +// luxe : 2014-01-09 Top Level Domain Holdings Limited +luxe + +// luxury : 2013-10-17 Luxury Partners, LLC +luxury + +// madrid : 2014-05-01 Comunidad de Madrid +madrid + +// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +maif + +// maison : 2013-12-05 Victor Frostbite, LLC +maison + +// makeup : 2015-01-15 L'Oréal +makeup + +// man : 2014-12-04 MAN SE +man + +// management : 2013-11-07 John Goodbye, LLC +management + +// mango : 2013-10-24 PUNTO FA S.L. +mango + +// market : 2014-03-06 +market + +// marketing : 2013-11-07 Fern Pass, LLC +marketing + +// markets : 2014-12-11 IG Group Holdings PLC +markets + +// marriott : 2014-10-09 Marriott Worldwide Corporation +marriott + +// marshalls : 2015-07-16 The TJX Companies, Inc. +marshalls + +// mba : 2015-04-02 Lone Hollow, LLC +mba + +// media : 2014-03-06 Grand Glen, LLC +media + +// meet : 2014-01-16 +meet + +// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +melbourne + +// meme : 2014-01-30 Charleston Road Registry Inc. +meme + +// memorial : 2014-10-16 Dog Beach, LLC +memorial + +// men : 2015-02-26 Exclusive Registry Limited +men + +// menu : 2013-09-11 Wedding TLD2, LLC +menu + +// meo : 2014-11-07 PT Comunicacoes S.A. +meo + +// metlife : 2015-05-07 MetLife Services and Solutions, LLC +metlife + +// miami : 2013-12-19 Top Level Domain Holdings Limited +miami + +// microsoft : 2014-12-18 Microsoft Corporation +microsoft + +// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +mini + +// mit : 2015-07-02 Massachusetts Institute of Technology +mit + +// mitsubishi : 2015-07-23 Mitsubishi Corporation +mitsubishi + +// mlb : 2015-05-21 MLB Advanced Media DH, LLC +mlb + +// mls : 2015-04-23 The Canadian Real Estate Association +mls + +// mma : 2014-11-07 MMA IARD +mma + +// mnet : 2015-03-05 Electronic Media Network (Pty) Ltd +mnet + +// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L. +mobily + +// moda : 2013-11-07 United TLD Holdco Ltd. +moda + +// moe : 2013-11-13 Interlink Co., Ltd. +moe + +// moi : 2014-12-18 Amazon EU S.à r.l. +moi + +// mom : 2015-04-16 Uniregistry, Corp. +mom + +// monash : 2013-09-30 Monash University +monash + +// money : 2014-10-16 Outer McCook, LLC +money + +// montblanc : 2014-06-23 Richemont DNS Inc. +montblanc + +// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant") +mormon + +// mortgage : 2014-03-20 +mortgage + +// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +moscow + +// moto : 2015-06-04 Charleston Road Registry Inc. +moto + +// motorcycles : 2014-01-09 DERMotorcycles, LLC +motorcycles + +// mov : 2014-01-30 Charleston Road Registry Inc. +mov + +// movie : 2015-02-05 New Frostbite, LLC +movie + +// movistar : 2014-10-16 Telefónica S.A. +movistar + +// msd : 2015-07-23 MSD Registry Holdings, Inc. +msd + +// mtn : 2014-12-04 MTN Dubai Limited +mtn + +// mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation +mtpc + +// mtr : 2015-03-12 MTR Corporation Limited +mtr + +// multichoice : 2015-03-12 MultiChoice (Proprietary) Limited +multichoice + +// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC +mutual + +// mutuelle : 2015-06-18 Fédération Nationale de la Mutualité Française +mutuelle + +// mzansimagic : 2015-03-05 Electronic Media Network (Pty) Ltd +mzansimagic + +// nadex : 2014-12-11 IG Group Holdings PLC +nadex + +// nagoya : 2013-10-24 GMO Registry, Inc. +nagoya + +// naspers : 2015-02-12 Intelprop (Proprietary) Limited +naspers + +// nationwide : 2015-07-23 Nationwide Mutual Insurance Company +nationwide + +// natura : 2015-03-12 NATURA COSMÉTICOS S.A. +natura + +// navy : 2014-03-06 United TLD Holdco Ltd. +navy + +// nec : 2015-01-08 NEC Corporation +nec + +// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +netbank + +// netflix : 2015-06-18 Netflix, Inc. +netflix + +// network : 2013-11-14 Trixy Manor, LLC +network + +// neustar : 2013-12-05 NeuStar, Inc. +neustar + +// new : 2014-01-30 Charleston Road Registry Inc. +new + +// news : 2014-12-18 +news + +// next : 2015-06-18 Next plc +next + +// nextdirect : 2015-06-18 Next plc +nextdirect + +// nexus : 2014-07-24 Charleston Road Registry Inc. +nexus + +// nfl : 2015-07-23 NFL Reg Ops LLC +nfl + +// ngo : 2014-03-06 Public Interest Registry +ngo + +// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +nhk + +// nico : 2014-12-04 DWANGO Co., Ltd. +nico + +// nike : 2015-07-23 NIKE, Inc. +nike + +// nikon : 2015-05-21 NIKON CORPORATION +nikon + +// ninja : 2013-11-07 United TLD Holdco Ltd. +ninja + +// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +nissan + +// nokia : 2015-01-08 Nokia Corporation +nokia + +// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC +northwesternmutual + +// norton : 2014-12-04 Symantec Corporation +norton + +// now : 2015-06-25 Amazon EU S.à r.l. +now + +// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +nowruz + +// nowtv : 2015-05-14 Starbucks (HK) Limited +nowtv + +// nra : 2014-05-22 NRA Holdings Company, INC. +nra + +// nrw : 2013-11-21 Minds + Machines GmbH +nrw + +// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +ntt + +// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +nyc + +// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +obi + +// observer : 2015-04-30 Guardian News and Media Limited +observer + +// off : 2015-07-23 Johnson Shareholdings, Inc. +off + +// office : 2015-03-12 Microsoft Corporation +office + +// okinawa : 2013-12-05 BusinessRalliart Inc. +okinawa + +// olayan : 2015-05-14 Crescent Holding GmbH +olayan + +// olayangroup : 2015-05-14 Crescent Holding GmbH +olayangroup + +// ollo : 2015-06-04 Dish DBS Corporation +ollo + +// omega : 2015-01-08 The Swatch Group Ltd +omega + +// one : 2014-11-07 One.com A/S +one + +// ong : 2014-03-06 Public Interest Registry +ong + +// onl : 2013-09-16 I-Registry Ltd. +onl + +// online : 2015-01-15 DotOnline Inc. +online + +// onyourside : 2015-07-23 Nationwide Mutual Insurance Company +onyourside + +// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED +ooo + +// oracle : 2014-06-19 Oracle Corporation +oracle + +// orange : 2015-03-12 Orange Brand Services Limited +orange + +// organic : 2014-03-27 Afilias Limited +organic + +// orientexpress : 2015-02-05 Belmond Ltd. +orientexpress + +// osaka : 2014-09-04 Interlink Co., Ltd. +osaka + +// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +otsuka + +// ott : 2015-06-04 Dish DBS Corporation +ott + +// ovh : 2014-01-16 OVH SAS +ovh + +// page : 2014-12-04 Charleston Road Registry Inc. +page + +// pamperedchef : 2015-02-05 The Pampered Chef, Ltd. +pamperedchef + +// panerai : 2014-11-07 Richemont DNS Inc. +panerai + +// paris : 2014-01-30 City of Paris +paris + +// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +pars + +// partners : 2013-12-05 Magic Glen, LLC +partners + +// parts : 2013-12-05 Sea Goodbye, LLC +parts + +// party : 2014-09-11 Blue Sky Registry Limited +party + +// passagens : 2015-03-05 Travel Reservations SRL +passagens + +// payu : 2015-02-12 MIH PayU B.V. +payu + +// pccw : 2015-05-14 PCCW Enterprises Limited +pccw + +// pet : 2015-05-07 Afilias plc +pet + +// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +pharmacy + +// philips : 2014-11-07 Koninklijke Philips N.V. +philips + +// photo : 2013-11-14 Uniregistry, Corp. +photo + +// photography : 2013-09-20 Sugar Glen, LLC +photography + +// photos : 2013-10-17 Sea Corner, LLC +photos + +// physio : 2014-05-01 PhysBiz Pty Ltd +physio + +// piaget : 2014-10-16 Richemont DNS Inc. +piaget + +// pics : 2013-11-14 Uniregistry, Corp. +pics + +// pictet : 2014-06-26 Pictet Europe S.A. +pictet + +// pictures : 2014-03-06 Foggy Sky, LLC +pictures + +// pid : 2015-01-08 Top Level Spectrum, Inc. +pid + +// pin : 2014-12-18 Amazon EU S.à r.l. +pin + +// ping : 2015-06-11 Ping Registry Provider, Inc. +ping + +// pink : 2013-10-01 Afilias Limited +pink + +// pioneer : 2015-07-16 Pioneer Corporation +pioneer + +// pizza : 2014-06-26 Foggy Moon, LLC +pizza + +// place : 2014-04-24 Snow Galley, LLC +place + +// play : 2015-03-05 Charleston Road Registry Inc. +play + +// playstation : 2015-07-02 Sony Computer Entertainment Inc. +playstation + +// plumbing : 2013-09-10 Spring Tigers, LLC +plumbing + +// plus : 2015-02-05 Sugar Mill, LLC +plus + +// pnc : 2015-07-02 PNC Domain Co., LLC +pnc + +// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +pohl + +// poker : 2014-07-03 Afilias Domains No. 5 Limited +poker + +// porn : 2014-10-16 ICM Registry PN LLC +porn + +// praxi : 2013-12-05 Praxi S.p.A. +praxi + +// press : 2014-04-03 DotPress Inc. +press + +// prime : 2015-06-25 Amazon EU S.à r.l. +prime + +// prod : 2014-01-23 Charleston Road Registry Inc. +prod + +// productions : 2013-12-05 Magic Birch, LLC +productions + +// prof : 2014-07-24 Charleston Road Registry Inc. +prof + +// progressive : 2015-07-23 Progressive Casualty Insurance Company +progressive + +// promo : 2014-12-18 Play.PROMO Oy +promo + +// properties : 2013-12-05 Big Pass, LLC +properties + +// property : 2014-05-22 Uniregistry, Corp. +property + +// protection : 2015-04-23 +protection + +// pub : 2013-12-12 United TLD Holdco Ltd. +pub + +// qpon : 2013-11-14 dotCOOL, Inc. +qpon + +// quebec : 2013-12-19 PointQuébec Inc +quebec + +// quest : 2015-03-26 Quest ION Limited +quest + +// racing : 2014-12-04 Premier Registry Limited +racing + +// raid : 2015-07-23 Johnson Shareholdings, Inc. +raid + +// read : 2014-12-18 Amazon EU S.à r.l. +read + +// realtor : 2014-05-29 Real Estate Domains LLC +realtor + +// realty : 2015-03-19 Fegistry, LLC +realty + +// recipes : 2013-10-17 Grand Island, LLC +recipes + +// red : 2013-11-07 Afilias Limited +red + +// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +redstone + +// redumbrella : 2015-03-26 Travelers TLD, LLC +redumbrella + +// rehab : 2014-03-06 United TLD Holdco Ltd. +rehab + +// reise : 2014-03-13 +reise + +// reisen : 2014-03-06 New Cypress, LLC +reisen + +// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +reit + +// reliance : 2015-04-02 Reliance Industries Limited +reliance + +// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd. +ren + +// rent : 2014-12-04 DERRent, LLC +rent + +// rentals : 2013-12-05 Big Hollow,LLC +rentals + +// repair : 2013-11-07 Lone Sunset, LLC +repair + +// report : 2013-12-05 Binky Glen, LLC +report + +// republican : 2014-03-20 United TLD Holdco Ltd. +republican + +// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +rest + +// restaurant : 2014-07-03 Snow Avenue, LLC +restaurant + +// review : 2014-11-20 dot Review Limited +review + +// reviews : 2013-09-13 +reviews + +// rexroth : 2015-06-18 Robert Bosch GMBH +rexroth + +// rich : 2013-11-21 I-Registry Ltd. +rich + +// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited +richardli + +// ricoh : 2014-11-20 Ricoh Company, Ltd. +ricoh + +// rightathome : 2015-07-23 Johnson Shareholdings, Inc. +rightathome + +// ril : 2015-04-02 Reliance Industries Limited +ril + +// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +rio + +// rip : 2014-07-10 United TLD Holdco Ltd. +rip + +// rocher : 2014-12-18 Ferrero Trading Lux S.A. +rocher + +// rocks : 2013-11-14 +rocks + +// rodeo : 2013-12-19 Top Level Domain Holdings Limited +rodeo + +// room : 2014-12-18 Amazon EU S.à r.l. +room + +// rsvp : 2014-05-08 Charleston Road Registry Inc. +rsvp + +// ruhr : 2013-10-02 regiodot GmbH & Co. KG +ruhr + +// run : 2015-03-19 Snow Park, LLC +run + +// rwe : 2015-04-02 RWE AG +rwe + +// ryukyu : 2014-01-09 BusinessRalliart Inc. +ryukyu + +// saarland : 2013-12-12 dotSaarland GmbH +saarland + +// safe : 2014-12-18 Amazon EU S.à r.l. +safe + +// safety : 2015-01-08 Safety Registry Services, LLC. +safety + +// sakura : 2014-12-18 SAKURA Internet Inc. +sakura + +// sale : 2014-10-16 +sale + +// salon : 2014-12-11 Outer Orchard, LLC +salon + +// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +samsung + +// sandvik : 2014-11-13 Sandvik AB +sandvik + +// sandvikcoromant : 2014-11-07 Sandvik AB +sandvikcoromant + +// sanofi : 2014-10-09 Sanofi +sanofi + +// sap : 2014-03-27 SAP AG +sap + +// sapo : 2014-11-07 PT Comunicacoes S.A. +sapo + +// sarl : 2014-07-03 Delta Orchard, LLC +sarl + +// sas : 2015-04-02 Research IP LLC +sas + +// save : 2015-06-25 Amazon EU S.à r.l. +save + +// saxo : 2014-10-31 Saxo Bank A/S +saxo + +// sbi : 2015-03-12 STATE BANK OF INDIA +sbi + +// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION +sbs + +// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) +sca + +// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +scb + +// schmidt : 2014-04-03 SALM S.A.S. +schmidt + +// scholarships : 2014-04-24 Scholarships.com, LLC +scholarships + +// school : 2014-12-18 Little Galley, LLC +school + +// schule : 2014-03-06 Outer Moon, LLC +schule + +// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +schwarz + +// science : 2014-09-11 dot Science Limited +science + +// scjohnson : 2015-07-23 Johnson Shareholdings, Inc. +scjohnson + +// scor : 2014-10-31 SCOR SE +scor + +// scot : 2014-01-23 Dot Scot Registry Limited +scot + +// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +seat + +// security : 2015-05-14 +security + +// seek : 2014-12-04 Seek Limited +seek + +// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +sener + +// services : 2014-02-27 Fox Castle, LLC +services + +// ses : 2015-07-23 SES +ses + +// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +sew + +// sex : 2014-11-13 ICM Registry SX LLC +sex + +// sexy : 2013-09-11 Uniregistry, Corp. +sexy + +// sharp : 2014-05-01 Sharp Corporation +sharp + +// shaw : 2015-04-23 Shaw Cablesystems G.P. +shaw + +// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +shia + +// shiksha : 2013-11-14 Afilias Limited +shiksha + +// shoes : 2013-10-02 Binky Galley, LLC +shoes + +// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +shouji + +// show : 2015-03-05 Snow Beach, LLC +show + +// shriram : 2014-01-23 Shriram Capital Ltd. +shriram + +// silk : 2015-06-25 Amazon EU S.à r.l. +silk + +// sina : 2015-03-12 Sina Corporation +sina + +// singles : 2013-08-27 Fern Madison, LLC +singles + +// site : 2015-01-15 DotSite Inc. +site + +// ski : 2015-04-09 STARTING DOT LIMITED +ski + +// skin : 2015-01-15 L'Oréal +skin + +// sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch +sky + +// skype : 2014-12-18 Microsoft Corporation +skype + +// smart : 2015-07-09 Smart Communications, Inc. (SMART) +smart + +// smile : 2014-12-18 Amazon EU S.à r.l. +smile + +// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F +sncf + +// soccer : 2015-03-26 Foggy Shadow, LLC +soccer + +// social : 2013-11-07 United TLD Holdco Ltd. +social + +// softbank : 2015-07-02 SoftBank Corp. +softbank + +// software : 2014-03-20 +software + +// sohu : 2013-12-19 Sohu.com Limited +sohu + +// solar : 2013-11-07 Ruby Town, LLC +solar + +// solutions : 2013-11-07 Silver Cover, LLC +solutions + +// song : 2015-02-26 Amazon EU S.à r.l. +song + +// sony : 2015-01-08 Sony Corporation +sony + +// soy : 2014-01-23 Charleston Road Registry Inc. +soy + +// space : 2014-04-03 DotSpace Inc. +space + +// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG +spiegel + +// spot : 2015-02-26 Amazon EU S.à r.l. +spot + +// spreadbetting : 2014-12-11 IG Group Holdings PLC +spreadbetting + +// srl : 2015-05-07 mySRL GmbH +srl + +// stada : 2014-11-13 STADA Arzneimittel AG +stada + +// star : 2015-01-08 Star India Private Limited +star + +// starhub : 2015-02-05 StarHub Limited +starhub + +// statebank : 2015-03-12 STATE BANK OF INDIA +statebank + +// statoil : 2014-12-04 Statoil ASA +statoil + +// stc : 2014-10-09 Saudi Telecom Company +stc + +// stcgroup : 2014-10-09 Saudi Telecom Company +stcgroup + +// stockholm : 2014-12-18 Stockholms kommun +stockholm + +// storage : 2014-12-22 Self Storage Company LLC +storage + +// store : 2015-04-09 DotStore Inc. +store + +// studio : 2015-02-11 +studio + +// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD +study + +// style : 2014-12-04 Binky Moon, LLC +style + +// sucks : 2014-12-22 Vox Populi Registry Inc. +sucks + +// supersport : 2015-03-05 SuperSport International Holdings Proprietary Limited +supersport + +// supplies : 2013-12-19 Atomic Fields, LLC +supplies + +// supply : 2013-12-19 Half Falls, LLC +supply + +// support : 2013-10-24 Grand Orchard, LLC +support + +// surf : 2014-01-09 Top Level Domain Holdings Limited +surf + +// surgery : 2014-03-20 Tin Avenue, LLC +surgery + +// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +suzuki + +// swatch : 2015-01-08 The Swatch Group Ltd +swatch + +// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited +swiftcover + +// swiss : 2014-10-16 Swiss Confederation +swiss + +// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +sydney + +// symantec : 2014-12-04 Symantec Corporation +symantec + +// systems : 2013-11-07 Dash Cypress, LLC +systems + +// tab : 2014-12-04 Tabcorp Holdings Limited +tab + +// taipei : 2014-07-10 Taipei City Government +taipei + +// talk : 2015-04-09 Amazon EU S.à r.l. +talk + +// taobao : 2015-01-15 Alibaba Group Holding Limited +taobao + +// tatamotors : 2015-03-12 Tata Motors Ltd +tatamotors + +// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +tatar + +// tattoo : 2013-08-30 Uniregistry, Corp. +tattoo + +// tax : 2014-03-20 Storm Orchard, LLC +tax + +// taxi : 2015-03-19 Pine Falls, LLC +taxi + +// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +tci + +// tdk : 2015-06-11 TDK Corporation +tdk + +// team : 2015-03-05 Atomic Lake, LLC +team + +// tech : 2015-01-30 Dot Tech LLC +tech + +// technology : 2013-09-13 Auburn Falls +technology + +// telecity : 2015-02-19 TelecityGroup International Limited +telecity + +// telefonica : 2014-10-16 Telefónica S.A. +telefonica + +// temasek : 2014-08-07 Temasek Holdings (Private) Limited +temasek + +// tennis : 2014-12-04 Cotton Bloom, LLC +tennis + +// teva : 2015-07-02 Teva Pharmaceutical Industries Limited +teva + +// thd : 2015-04-02 Homer TLC, Inc. +thd + +// theater : 2015-03-19 Blue Tigers, LLC +theater + +// theatre : 2015-05-07 +theatre + +// theguardian : 2015-04-30 Guardian News and Media Limited +theguardian + +// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America +tiaa + +// tickets : 2015-02-05 Accent Media Limited +tickets + +// tienda : 2013-11-14 Victor Manor, LLC +tienda + +// tiffany : 2015-01-30 Tiffany and Company +tiffany + +// tips : 2013-09-20 Corn Willow, LLC +tips + +// tires : 2014-11-07 Dog Edge, LLC +tires + +// tirol : 2014-04-24 punkt Tirol GmbH +tirol + +// tjmaxx : 2015-07-16 The TJX Companies, Inc. +tjmaxx + +// tjx : 2015-07-16 The TJX Companies, Inc. +tjx + +// tkmaxx : 2015-07-16 The TJX Companies, Inc. +tkmaxx + +// tmall : 2015-01-15 Alibaba Group Holding Limited +tmall + +// today : 2013-09-20 Pearl Woods, LLC +today + +// tokyo : 2013-11-13 GMO Registry, Inc. +tokyo + +// tools : 2013-11-21 Pioneer North, LLC +tools + +// top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd. +top + +// toray : 2014-12-18 Toray Industries, Inc. +toray + +// toshiba : 2014-04-10 TOSHIBA Corporation +toshiba + +// tours : 2015-01-22 Sugar Station, LLC +tours + +// town : 2014-03-06 Koko Moon, LLC +town + +// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +toyota + +// toys : 2014-03-06 Pioneer Orchard, LLC +toys + +// trade : 2014-01-23 Elite Registry Limited +trade + +// trading : 2014-12-11 IG Group Holdings PLC +trading + +// training : 2013-11-07 Wild Willow, LLC +training + +// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. +travelchannel + +// travelers : 2015-03-26 Travelers TLD, LLC +travelers + +// travelersinsurance : 2015-03-26 Travelers TLD, LLC +travelersinsurance + +// trust : 2014-10-16 +trust + +// trv : 2015-03-26 Travelers TLD, LLC +trv + +// tube : 2015-06-11 Latin American Telecom LLC +tube + +// tui : 2014-07-03 TUI AG +tui + +// tunes : 2015-02-26 Amazon EU S.à r.l. +tunes + +// tushu : 2014-12-18 Amazon EU S.à r.l. +tushu + +// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +tvs + +// ubs : 2014-12-11 UBS AG +ubs + +// university : 2014-03-06 Little Station, LLC +university + +// uno : 2013-09-11 Dot Latin LLC +uno + +// uol : 2014-05-01 UBN INTERNET LTDA. +uol + +// ups : 2015-06-25 UPS Market Driver, Inc. +ups + +// vacations : 2013-12-05 Atomic Tigers, LLC +vacations + +// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +vana + +// vegas : 2014-01-16 Dot Vegas, Inc. +vegas + +// ventures : 2013-08-27 Binky Lake, LLC +ventures + +// versicherung : 2014-03-20 dotversicherung-registry GmbH +versicherung + +// vet : 2014-03-06 +vet + +// viajes : 2013-10-17 Black Madison, LLC +viajes + +// video : 2014-10-16 +video + +// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +vig + +// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +viking + +// villas : 2013-12-05 New Sky, LLC +villas + +// vin : 2015-06-18 Holly Shadow, LLC +vin + +// vip : 2015-01-22 Minds + Machines Group Limited +vip + +// virgin : 2014-09-25 Virgin Enterprises Limited +virgin + +// vision : 2013-12-05 Koko Station, LLC +vision + +// vista : 2014-09-18 Vistaprint Limited +vista + +// vistaprint : 2014-09-18 Vistaprint Limited +vistaprint + +// viva : 2014-11-07 Saudi Telecom Company +viva + +// vlaanderen : 2014-02-06 DNS.be vzw +vlaanderen + +// vodka : 2013-12-19 Top Level Domain Holdings Limited +vodka + +// volkswagen : 2015-05-14 Volkswagen Group of America Inc. +volkswagen + +// vote : 2013-11-21 Monolith Registry LLC +vote + +// voting : 2013-11-13 Valuetainment Corp. +voting + +// voto : 2013-11-21 Monolith Registry LLC +voto + +// voyage : 2013-08-27 Ruby House, LLC +voyage + +// vuelos : 2015-03-05 Travel Reservations SRL +vuelos + +// wales : 2014-05-08 Nominet UK +wales + +// walter : 2014-11-13 Sandvik AB +walter + +// wang : 2013-10-24 Zodiac Leo Limited +wang + +// wanggou : 2014-12-18 Amazon EU S.à r.l. +wanggou + +// warman : 2015-06-18 Weir Group IP Limited +warman + +// watch : 2013-11-14 Sand Shadow, LLC +watch + +// watches : 2014-12-22 Richemont DNS Inc. +watches + +// weather : 2015-01-08 The Weather Channel, LLC +weather + +// weatherchannel : 2015-03-12 The Weather Channel, LLC +weatherchannel + +// webcam : 2014-01-23 dot Webcam Limited +webcam + +// weber : 2015-06-04 Saint-Gobain Weber SA +weber + +// website : 2014-04-03 DotWebsite Inc. +website + +// wed : 2013-10-01 Atgron, Inc. +wed + +// wedding : 2014-04-24 Top Level Domain Holdings Limited +wedding + +// weibo : 2015-03-05 Sina Corporation +weibo + +// weir : 2015-01-29 Weir Group IP Limited +weir + +// whoswho : 2014-02-20 Who's Who Registry +whoswho + +// wien : 2013-10-28 punkt.wien GmbH +wien + +// wiki : 2013-11-07 Top Level Design, LLC +wiki + +// williamhill : 2014-03-13 William Hill Organization Limited +williamhill + +// win : 2014-11-20 First Registry Limited +win + +// windows : 2014-12-18 Microsoft Corporation +windows + +// wine : 2015-06-18 June Station, LLC +wine + +// winners : 2015-07-16 The TJX Companies, Inc. +winners + +// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +wme + +// woodside : 2015-07-09 Woodside Petroleum Limited +woodside + +// work : 2013-12-19 Top Level Domain Holdings Limited +work + +// works : 2013-11-14 Little Dynamite, LLC +works + +// world : 2014-06-12 Bitter Fields, LLC +world + +// wtc : 2013-12-19 World Trade Centers Association, Inc. +wtc + +// wtf : 2014-03-06 Hidden Way, LLC +wtf + +// xbox : 2014-12-18 Microsoft Corporation +xbox + +// xerox : 2014-10-24 Xerox DNHC LLC +xerox + +// xfinity : 2015-07-09 Comcast IP Holdings I, LLC +xfinity + +// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +xihuan + +// xin : 2014-12-11 Elegant Leader Limited +xin + +// xn--11b4c3d : 2015-01-15 VeriSign Sarl +कॉम + +// xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l. +セール + +// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +佛山 + +// xn--30rr7y : 2014-06-12 Excellent First Limited +慈善 + +// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +集团 + +// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED +在线 + +// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd. +大众汽车 + +// xn--3pxu8k : 2015-01-15 VeriSign Sarl +点看 + +// xn--42c2d9a : 2015-01-15 VeriSign Sarl +คอม + +// xn--45q11c : 2013-11-21 Zodiac Scorpio Limited +八卦 + +// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment +موقع + +// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +公益 + +// xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) +公司 + +// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +网站 + +// xn--6frz82g : 2013-09-23 Afilias Limited +移动 + +// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +我爱你 + +// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +москва + +// xn--80asehdb : 2013-07-14 CORE Association +онлайн + +// xn--80aswg : 2013-07-14 CORE Association +сайт + +// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +联通 + +// xn--9dbq2a : 2015-01-15 VeriSign Sarl +קום + +// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +时尚 + +// xn--9krt00a : 2015-03-12 Sina Corporation +微博 + +// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +淡马锡 + +// xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l. +ファッション + +// xn--c1avg : 2013-11-14 Public Interest Registry +орг + +// xn--c2br7g : 2015-01-15 VeriSign Sarl +नेट + +// xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l. +ストア + +// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +삼성 + +// xn--czr694b : 2014-01-16 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY.HONGKONG LIMITED +商标 + +// xn--czrs0t : 2013-12-19 Wild Island, LLC +商店 + +// xn--czru2d : 2013-11-21 Zodiac Capricorn Limited +商城 + +// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +дети + +// xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l. +ポイント + +// xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社 +新闻 + +// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited +工行 + +// xn--fct429k : 2015-04-09 Amazon EU S.à r.l. +家電 + +// xn--fhbei : 2015-01-15 VeriSign Sarl +كوم + +// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED +中文网 + +// xn--fiq64b : 2013-10-14 CITIC Group Corporation +中信 + +// xn--fjq720a : 2014-05-22 Will Bloom, LLC +娱乐 + +// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +谷歌 + +// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited +電訊盈科 + +// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited +购物 + +// xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l. +クラウド + +// xn--hxt814e : 2014-05-15 Zodiac Libra Limited +网店 + +// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +संगठन + +// xn--imr513n : 2014-12-11 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED +餐厅 + +// xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) +网络 + +// xn--j1aef : 2015-01-15 VeriSign Sarl +ком + +// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation +诺基亚 + +// xn--jvr189m : 2015-02-26 Amazon EU S.à r.l. +食品 + +// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +飞利浦 + +// xn--kpu716f : 2014-12-22 Richemont DNS Inc. +手表 + +// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +手机 + +// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +ارامكو + +// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH +العليان + +// xn--mgbab2bd : 2013-10-31 CORE Association +بازار + +// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L. +موبايلي + +// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +همراه + +// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +닷컴 + +// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +政府 + +// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +شبكة + +// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +بيتك + +// xn--nqv7f : 2013-11-14 Public Interest Registry +机构 + +// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +组织机构 + +// xn--nyqy26a : 2014-11-07 Stable Tone Limited +健康 + +// xn--p1acf : 2013-12-12 Rusnames Limited +рус + +// xn--pbt977c : 2014-12-22 Richemont DNS Inc. +珠宝 + +// xn--pssy2u : 2015-01-15 VeriSign Sarl +大拿 + +// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +みんな + +// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +グーグル + +// xn--rhqv96g : 2013-09-11 Stable Tone Limited +世界 + +// xn--rovu88b : 2015-02-26 Amazon EU S.à r.l. +書籍 + +// xn--ses554g : 2014-01-16 +网址 + +// xn--t60b56a : 2015-01-15 VeriSign Sarl +닷넷 + +// xn--tckwe : 2015-01-15 VeriSign Sarl +コム + +// xn--unup4y : 2013-07-14 Spring Fields, LLC +游戏 + +// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberater + +// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +vermögensberatung + +// xn--vhquv : 2013-08-27 Dash McCook, LLC +企业 + +// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +信息 + +// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +嘉里大酒店 + +// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +广东 + +// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +政务 + +// xperia : 2015-05-14 Sony Mobile Communications AB +xperia + +// xyz : 2013-12-05 XYZ.COM LLC +xyz + +// yachts : 2014-01-09 DERYachts, LLC +yachts + +// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +yahoo + +// yamaxun : 2014-12-18 Amazon EU S.à r.l. +yamaxun + +// yandex : 2014-04-10 YANDEX, LLC +yandex + +// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +yodobashi + +// yoga : 2014-05-29 Top Level Domain Holdings Limited +yoga + +// yokohama : 2013-12-12 GMO Registry, Inc. +yokohama + +// you : 2015-04-09 Amazon EU S.à r.l. +you + +// youtube : 2014-05-01 Charleston Road Registry Inc. +youtube + +// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +yun + +// zappos : 2015-06-25 Amazon EU S.à r.l. +zappos + +// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +zara + +// zero : 2014-12-18 Amazon EU S.à r.l. +zero + +// zip : 2014-05-08 Charleston Road Registry Inc. +zip + +// zippo : 2015-07-02 Zadco Company +zippo + +// zone : 2013-11-14 Outer Falls, LLC +zone + +// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +zuerich + + +// ===END ICANN DOMAINS=== +// ===BEGIN PRIVATE DOMAINS=== +// (Note: these are in alphabetical order by company name) + +// Amazon CloudFront : https://aws.amazon.com/cloudfront/ +// Submitted by Donavan Miller 2013-03-22 +cloudfront.net + +// Amazon Elastic Compute Cloud: https://aws.amazon.com/ec2/ +// Submitted by Osman Surkatty 2014-12-16 +ap-northeast-1.compute.amazonaws.com +ap-southeast-1.compute.amazonaws.com +ap-southeast-2.compute.amazonaws.com +cn-north-1.compute.amazonaws.cn +compute.amazonaws.cn +compute.amazonaws.com +compute-1.amazonaws.com +eu-west-1.compute.amazonaws.com +eu-central-1.compute.amazonaws.com +sa-east-1.compute.amazonaws.com +us-east-1.amazonaws.com +us-gov-west-1.compute.amazonaws.com +us-west-1.compute.amazonaws.com +us-west-2.compute.amazonaws.com +z-1.compute-1.amazonaws.com +z-2.compute-1.amazonaws.com + +// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/ +// Submitted by Adam Stein 2013-04-02 +elasticbeanstalk.com + +// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/ +// Submitted by Scott Vidmar 2013-03-27 +elb.amazonaws.com + +// Amazon S3 : https://aws.amazon.com/s3/ +// Submitted by Eric Kinolik 2015-04-08 +s3.amazonaws.com +s3-ap-northeast-1.amazonaws.com +s3-ap-southeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3-external-1.amazonaws.com +s3-external-2.amazonaws.com +s3-fips-us-gov-west-1.amazonaws.com +s3-eu-central-1.amazonaws.com +s3-eu-west-1.amazonaws.com +s3-sa-east-1.amazonaws.com +s3-us-gov-west-1.amazonaws.com +s3-us-west-1.amazonaws.com +s3-us-west-2.amazonaws.com +s3.cn-north-1.amazonaws.com.cn +s3.eu-central-1.amazonaws.com + +// BetaInABox +// Submitted by adrian@betainabox.com 2012-09-13 +betainabox.com + +// CentralNic : http://www.centralnic.com/names/domains +// Submitted by registry 2012-09-27 +ae.org +ar.com +br.com +cn.com +com.de +com.se +de.com +eu.com +gb.com +gb.net +hu.com +hu.net +jp.net +jpn.com +kr.com +mex.com +no.com +qc.com +ru.com +sa.com +se.com +se.net +uk.com +uk.net +us.com +uy.com +za.bz +za.com + +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown 2014-02-04 +africa.com + +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown 2014-02-04 +gr.com + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown 2014-02-04 +in.net + +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown 2014-02-04 +us.org + +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown 2014-02-04 +co.com + +// c.la : http://www.c.la/ +c.la + +// cloudControl : https://www.cloudcontrol.com/ +// Submitted by Tobias Wilken 2013-07-23 +cloudcontrolled.com +cloudcontrolapp.com + +// co.ca : http://registry.co.ca/ +co.ca + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes 2015-07-13 +c.cdn77.org +cdn77-ssl.net +r.cdn77.net +rsc.cdn77.org +ssl.origin.cdn77-secure.org + +// CoDNS B.V. +co.nl +co.no + +// Commerce Guys, SAS +// Submitted by Damien Tournoud 2015-01-22 +*.platform.sh + +// Cupcake : https://cupcake.io/ +// Submitted by Jonathan Rudenberg 2013-10-08 +cupcake.is + +// DreamHost : http://www.dreamhost.com/ +// Submitted by Andrew Farmer 2012-10-02 +dreamhosters.com + +// DuckDNS : http://www.duckdns.org/ +// Submitted by Richard Harper 2015-05-17 +duckdns.org + +// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com +dyndns.biz +dyndns.info +dyndns.org +dyndns.tv +at-band-camp.net +ath.cx +barrel-of-knowledge.info +barrell-of-knowledge.info +better-than.tv +blogdns.com +blogdns.net +blogdns.org +blogsite.org +boldlygoingnowhere.org +broke-it.net +buyshouses.net +cechire.com +dnsalias.com +dnsalias.net +dnsalias.org +dnsdojo.com +dnsdojo.net +dnsdojo.org +does-it.net +doesntexist.com +doesntexist.org +dontexist.com +dontexist.net +dontexist.org +doomdns.com +doomdns.org +dvrdns.org +dyn-o-saur.com +dynalias.com +dynalias.net +dynalias.org +dynathome.net +dyndns.ws +endofinternet.net +endofinternet.org +endoftheinternet.org +est-a-la-maison.com +est-a-la-masion.com +est-le-patron.com +est-mon-blogueur.com +for-better.biz +for-more.biz +for-our.info +for-some.biz +for-the.biz +forgot.her.name +forgot.his.name +from-ak.com +from-al.com +from-ar.com +from-az.net +from-ca.com +from-co.net +from-ct.com +from-dc.com +from-de.com +from-fl.com +from-ga.com +from-hi.com +from-ia.com +from-id.com +from-il.com +from-in.com +from-ks.com +from-ky.com +from-la.net +from-ma.com +from-md.com +from-me.org +from-mi.com +from-mn.com +from-mo.com +from-ms.com +from-mt.com +from-nc.com +from-nd.com +from-ne.com +from-nh.com +from-nj.com +from-nm.com +from-nv.com +from-ny.net +from-oh.com +from-ok.com +from-or.com +from-pa.com +from-pr.com +from-ri.com +from-sc.com +from-sd.com +from-tn.com +from-tx.com +from-ut.com +from-va.com +from-vt.com +from-wa.com +from-wi.com +from-wv.com +from-wy.com +ftpaccess.cc +fuettertdasnetz.de +game-host.org +game-server.cc +getmyip.com +gets-it.net +go.dyndns.org +gotdns.com +gotdns.org +groks-the.info +groks-this.info +ham-radio-op.net +here-for-more.info +hobby-site.com +hobby-site.org +home.dyndns.org +homedns.org +homeftp.net +homeftp.org +homeip.net +homelinux.com +homelinux.net +homelinux.org +homeunix.com +homeunix.net +homeunix.org +iamallama.com +in-the-band.net +is-a-anarchist.com +is-a-blogger.com +is-a-bookkeeper.com +is-a-bruinsfan.org +is-a-bulls-fan.com +is-a-candidate.org +is-a-caterer.com +is-a-celticsfan.org +is-a-chef.com +is-a-chef.net +is-a-chef.org +is-a-conservative.com +is-a-cpa.com +is-a-cubicle-slave.com +is-a-democrat.com +is-a-designer.com +is-a-doctor.com +is-a-financialadvisor.com +is-a-geek.com +is-a-geek.net +is-a-geek.org +is-a-green.com +is-a-guru.com +is-a-hard-worker.com +is-a-hunter.com +is-a-knight.org +is-a-landscaper.com +is-a-lawyer.com +is-a-liberal.com +is-a-libertarian.com +is-a-linux-user.org +is-a-llama.com +is-a-musician.com +is-a-nascarfan.com +is-a-nurse.com +is-a-painter.com +is-a-patsfan.org +is-a-personaltrainer.com +is-a-photographer.com +is-a-player.com +is-a-republican.com +is-a-rockstar.com +is-a-socialist.com +is-a-soxfan.org +is-a-student.com +is-a-teacher.com +is-a-techie.com +is-a-therapist.com +is-an-accountant.com +is-an-actor.com +is-an-actress.com +is-an-anarchist.com +is-an-artist.com +is-an-engineer.com +is-an-entertainer.com +is-by.us +is-certified.com +is-found.org +is-gone.com +is-into-anime.com +is-into-cars.com +is-into-cartoons.com +is-into-games.com +is-leet.com +is-lost.org +is-not-certified.com +is-saved.org +is-slick.com +is-uberleet.com +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +is-with-theband.com +isa-geek.com +isa-geek.net +isa-geek.org +isa-hockeynut.com +issmarterthanyou.com +isteingeek.de +istmein.de +kicks-ass.net +kicks-ass.org +knowsitall.info +land-4-sale.us +lebtimnetz.de +leitungsen.de +likes-pie.com +likescandy.com +merseine.nu +mine.nu +misconfused.org +mypets.ws +myphotos.cc +neat-url.com +office-on-the.net +on-the-web.tv +podzone.net +podzone.org +readmyblog.org +saves-the-whales.com +scrapper-site.net +scrapping.cc +selfip.biz +selfip.com +selfip.info +selfip.net +selfip.org +sells-for-less.com +sells-for-u.com +sells-it.net +sellsyourhome.org +servebbs.com +servebbs.net +servebbs.org +serveftp.net +serveftp.org +servegame.org +shacknet.nu +simple-url.com +space-to-rent.com +stuff-4-sale.org +stuff-4-sale.us +teaches-yoga.com +thruhere.net +traeumtgerade.de +webhop.biz +webhop.info +webhop.net +webhop.org +worse-than.tv +writesthisblog.com + +// EU.org https://eu.org/ +// Submitted by Pierre Beyssac 2015-04-17 + +eu.org +al.eu.org +asso.eu.org +at.eu.org +au.eu.org +be.eu.org +bg.eu.org +ca.eu.org +cd.eu.org +ch.eu.org +cn.eu.org +cy.eu.org +cz.eu.org +de.eu.org +dk.eu.org +edu.eu.org +ee.eu.org +es.eu.org +fi.eu.org +fr.eu.org +gr.eu.org +hr.eu.org +hu.eu.org +ie.eu.org +il.eu.org +in.eu.org +int.eu.org +is.eu.org +it.eu.org +jp.eu.org +kr.eu.org +lt.eu.org +lu.eu.org +lv.eu.org +mc.eu.org +me.eu.org +mk.eu.org +mt.eu.org +my.eu.org +net.eu.org +ng.eu.org +nl.eu.org +no.eu.org +nz.eu.org +paris.eu.org +pl.eu.org +pt.eu.org +q-a.eu.org +ro.eu.org +ru.eu.org +se.eu.org +si.eu.org +sk.eu.org +tr.eu.org +uk.eu.org +us.eu.org + +// Fastly Inc. http://www.fastly.com/ +// Submitted by Vladimir Vuksan 2013-05-31 +a.ssl.fastly.net +b.ssl.fastly.net +global.ssl.fastly.net +a.prod.fastly.net +global.prod.fastly.net + +// Firebase, Inc. +// Submitted by Chris Raynor 2014-01-21 +firebaseapp.com + +// Flynn : https://flynn.io +// Submitted by Jonathan Rudenberg 2014-07-12 +flynnhub.com + +// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains +// Submitted by David Illsley 2014-08-28 +service.gov.uk + +// GitHub, Inc. +// Submitted by Ben Toews 2014-02-06 +github.io +githubusercontent.com + +// GlobeHosting, Inc. +// Submitted by Zoltan Egresi 2013-07-12 +ro.com + +// Google, Inc. +// Submitted by Eduardo Vela 2014-12-19 +appspot.com +blogspot.ae +blogspot.al +blogspot.am +blogspot.ba +blogspot.be +blogspot.bg +blogspot.bj +blogspot.ca +blogspot.cf +blogspot.ch +blogspot.cl +blogspot.co.at +blogspot.co.id +blogspot.co.il +blogspot.co.ke +blogspot.co.nz +blogspot.co.uk +blogspot.co.za +blogspot.com +blogspot.com.ar +blogspot.com.au +blogspot.com.br +blogspot.com.by +blogspot.com.co +blogspot.com.cy +blogspot.com.ee +blogspot.com.eg +blogspot.com.es +blogspot.com.mt +blogspot.com.ng +blogspot.com.tr +blogspot.com.uy +blogspot.cv +blogspot.cz +blogspot.de +blogspot.dk +blogspot.fi +blogspot.fr +blogspot.gr +blogspot.hk +blogspot.hr +blogspot.hu +blogspot.ie +blogspot.in +blogspot.is +blogspot.it +blogspot.jp +blogspot.kr +blogspot.li +blogspot.lt +blogspot.lu +blogspot.md +blogspot.mk +blogspot.mr +blogspot.mx +blogspot.my +blogspot.nl +blogspot.no +blogspot.pe +blogspot.pt +blogspot.qa +blogspot.re +blogspot.ro +blogspot.rs +blogspot.ru +blogspot.se +blogspot.sg +blogspot.si +blogspot.sk +blogspot.sn +blogspot.td +blogspot.tw +blogspot.ug +blogspot.vn +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +withgoogle.com + +// Heroku : https://www.heroku.com/ +// Submitted by Tom Maher 2013-05-02 +herokuapp.com +herokussl.com + +// iki.fi +// Submitted by Hannu Aronsson 2009-11-05 +iki.fi + +// info.at : http://www.info.at/ +biz.at +info.at + +// Michau Enterprises Limited : http://www.co.pl/ +co.pl + +// Microsoft : http://microsoft.com +// Submitted by Barry Dorrans 2014-01-24 +azurewebsites.net +azure-mobile.net +cloudapp.net + +// Mozilla Foundation : https://mozilla.org/ +// Submited by glob 2015-07-06 +bmoattachments.org + +// Neustar Inc. +// Submitted by Trung Tran 2015-04-23 +4u.com + +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse 2014-02-02 +nfshost.com + +// NYC.mn : http://www.information.nyc.mn +// Submitted by Matthew Brown 2013-03-11 +nyc.mn + +// One Fold Media : http://www.onefoldmedia.com/ +// Submitted by Eddie Jones 2014-06-10 +nid.io + +// Opera Software, A.S.A. +// Submitted by Yngve Pettersen 2009-11-26 +operaunite.com + +// OutSystems +// Submitted by Duarte Santos 2014-03-11 +outsystemscloud.com + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry 2008-06-09 +priv.at + +// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ +// Submitted by Tim Kramer 2012-10-24 +rhcloud.com + +// SinaAppEngine : http://sae.sina.com.cn/ +// Submitted by SinaAppEngine 2015-02-02 +sinaapp.com +vipsinaapp.com +1kapp.com + +// TASK geographical domains (www.task.gda.pl/uslugi/dns) +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl + +// UDR Limited : http://www.udr.hk.com +// Submitted by registry 2014-11-07 +hk.com +hk.org +ltd.hk +inc.hk + +// Yola : https://www.yola.com/ +// Submitted by Stefano Rivera 2014-07-09 +yolasite.com + +// ZaNiC : http://www.za.net/ +// Submitted by registry 2009-10-03 +za.net +za.org + +// ===END PRIVATE DOMAINS=== diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp new file mode 100644 index 000000000..72b557774 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp @@ -0,0 +1,779 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "MDNSResponderOperator.h" +#include "MDNSResponderReply.h" +#include "mozilla/EndianUtils.h" +#include "mozilla/Logging.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Unused.h" +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsDNSServiceInfo.h" +#include "nsHashPropertyBag.h" +#include "nsIProperty.h" +#include "nsISimpleEnumerator.h" +#include "nsIVariant.h" +#include "nsServiceManagerUtils.h" +#include "nsNetAddr.h" +#include "nsNetCID.h" +#include "nsSocketTransportService2.h" +#include "nsThreadUtils.h" +#include "nsXPCOMCID.h" +#include "private/pprio.h" + +#include "nsASocketHandler.h" + +namespace mozilla { +namespace net { + +static LazyLogModule gMDNSLog("MDNSResponderOperator"); +#undef LOG_I +#define LOG_I(...) MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) +#undef LOG_E +#define LOG_E(...) MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Error, (__VA_ARGS__)) + +class MDNSResponderOperator::ServiceWatcher final + : public nsASocketHandler +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + + // nsASocketHandler methods + virtual void OnSocketReady(PRFileDesc* fd, int16_t outFlags) override + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + MOZ_ASSERT(fd == mFD); + + if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL)) { + LOG_E("error polling on listening socket (%p)", fd); + mCondition = NS_ERROR_UNEXPECTED; + } + + if (!(outFlags & PR_POLL_READ)) { + return; + } + + DNSServiceProcessResult(mService); + } + + virtual void OnSocketDetached(PRFileDesc *fd) override + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + MOZ_ASSERT(mThread); + MOZ_ASSERT(fd == mFD); + + if (!mFD) { + return; + } + + // Bug 1175387: do not double close the handle here. + PR_ChangeFileDescNativeHandle(mFD, -1); + PR_Close(mFD); + mFD = nullptr; + + mThread->Dispatch(NewRunnableMethod(this, &ServiceWatcher::Deallocate), + NS_DISPATCH_NORMAL); + } + + virtual void IsLocal(bool *aIsLocal) override { *aIsLocal = true; } + + virtual void KeepWhenOffline(bool *aKeepWhenOffline) override + { + *aKeepWhenOffline = true; + } + + virtual uint64_t ByteCountSent() override { return 0; } + virtual uint64_t ByteCountReceived() override { return 0; } + + explicit ServiceWatcher(DNSServiceRef aService, + MDNSResponderOperator* aOperator) + : mThread(nullptr) + , mSts(nullptr) + , mOperatorHolder(aOperator) + , mService(aService) + , mFD(nullptr) + , mAttached(false) + { + if (!gSocketTransportService) + { + nsCOMPtr sts = + do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID); + } + } + + nsresult Init() + { + MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread); + mThread = NS_GetCurrentThread(); + + if (!mService) { + return NS_OK; + } + + if (!gSocketTransportService) { + return NS_ERROR_FAILURE; + } + mSts = gSocketTransportService; + + int osfd = DNSServiceRefSockFD(mService); + if (osfd == -1) { + return NS_ERROR_FAILURE; + } + + mFD = PR_ImportFile(osfd); + return PostEvent(&ServiceWatcher::OnMsgAttach); + } + + void Close() + { + MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread); + + if (!gSocketTransportService) { + Deallocate(); + return; + } + + PostEvent(&ServiceWatcher::OnMsgClose); + } + +private: + ~ServiceWatcher() = default; + + void Deallocate() + { + if (mService) { + DNSServiceRefDeallocate(mService); + mService = nullptr; + } + mOperatorHolder = nullptr; + } + + nsresult PostEvent(void(ServiceWatcher::*func)(void)) + { + return gSocketTransportService->Dispatch(NewRunnableMethod(this, func), + NS_DISPATCH_NORMAL); + } + + void OnMsgClose() + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + if (NS_FAILED(mCondition)) { + return; + } + + // tear down socket. this signals the STS to detach our socket handler. + mCondition = NS_BINDING_ABORTED; + + // if we are attached, then socket transport service will call our + // OnSocketDetached method automatically. Otherwise, we have to call it + // (and thus close the socket) manually. + if (!mAttached) { + OnSocketDetached(mFD); + } + } + + void OnMsgAttach() + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + if (NS_FAILED(mCondition)) { + return; + } + + mCondition = TryAttach(); + + // if we hit an error while trying to attach then bail... + if (NS_FAILED(mCondition)) { + NS_ASSERTION(!mAttached, "should not be attached already"); + OnSocketDetached(mFD); + } + + } + + nsresult TryAttach() + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + nsresult rv; + + if (!gSocketTransportService) { + return NS_ERROR_FAILURE; + } + + // + // find out if it is going to be ok to attach another socket to the STS. + // if not then we have to wait for the STS to tell us that it is ok. + // the notification is asynchronous, which means that when we could be + // in a race to call AttachSocket once notified. for this reason, when + // we get notified, we just re-enter this function. as a result, we are + // sure to ask again before calling AttachSocket. in this way we deal + // with the race condition. though it isn't the most elegant solution, + // it is far simpler than trying to build a system that would guarantee + // FIFO ordering (which wouldn't even be that valuable IMO). see bug + // 194402 for more info. + // + if (!gSocketTransportService->CanAttachSocket()) { + nsCOMPtr event = + NewRunnableMethod(this, &ServiceWatcher::OnMsgAttach); + + nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); + if (NS_FAILED(rv)) { + return rv; + } + } + + // + // ok, we can now attach our socket to the STS for polling + // + rv = gSocketTransportService->AttachSocket(mFD, this); + if (NS_FAILED(rv)) { + return rv; + } + + mAttached = true; + + // + // now, configure our poll flags for listening... + // + mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT); + + return NS_OK; + } + + nsCOMPtr mThread; + RefPtr mSts; + RefPtr mOperatorHolder; + DNSServiceRef mService; + PRFileDesc* mFD; + bool mAttached; +}; + +NS_IMPL_ISUPPORTS(MDNSResponderOperator::ServiceWatcher, nsISupports) + +MDNSResponderOperator::MDNSResponderOperator() + : mService(nullptr) + , mWatcher(nullptr) + , mThread(NS_GetCurrentThread()) + , mIsCancelled(false) +{ +} + +MDNSResponderOperator::~MDNSResponderOperator() +{ + Stop(); +} + +nsresult +MDNSResponderOperator::Start() +{ + if (mIsCancelled) { + return NS_OK; + } + + if (IsServing()) { + Stop(); + } + + return NS_OK; +} + +nsresult +MDNSResponderOperator::Stop() +{ + return ResetService(nullptr); +} + +nsresult +MDNSResponderOperator::ResetService(DNSServiceRef aService) +{ + nsresult rv; + + if (aService != mService) { + if (mWatcher) { + mWatcher->Close(); + mWatcher = nullptr; + } + + if (aService) { + RefPtr watcher = new ServiceWatcher(aService, this); + if (NS_WARN_IF(NS_FAILED(rv = watcher->Init()))) { + return rv; + } + mWatcher = watcher; + } + + mService = aService; + } + return NS_OK; +} + +BrowseOperator::BrowseOperator(const nsACString& aServiceType, + nsIDNSServiceDiscoveryListener* aListener) + : MDNSResponderOperator() + , mServiceType(aServiceType) + , mListener(aListener) +{ +} + +nsresult +BrowseOperator::Start() +{ + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { + return rv; + } + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = DNSServiceBrowse(&service, + 0, + kDNSServiceInterfaceIndexAny, + mServiceType.get(), + nullptr, + &BrowseReplyRunnable::Reply, + this); + NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, "DNSServiceBrowse fail"); + + if (mListener) { + if (kDNSServiceErr_NoError == err) { + mListener->OnDiscoveryStarted(mServiceType); + } else { + mListener->OnStartDiscoveryFailed(mServiceType, err); + } + } + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +nsresult +BrowseOperator::Stop() +{ + bool isServing = IsServing(); + nsresult rv = MDNSResponderOperator::Stop(); + + if (isServing && mListener) { + if (NS_SUCCEEDED(rv)) { + mListener->OnDiscoveryStopped(mServiceType); + } else { + mListener->OnStopDiscoveryFailed(mServiceType, + static_cast(rv)); + } + } + + return rv; +} + +void +BrowseOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { + LOG_E("BrowseOperator::Reply (%d)", aErrorCode); + if (mListener) { + mListener->OnStartDiscoveryFailed(mServiceType, aErrorCode); + } + return; + } + + if (!mListener) { return; } + nsCOMPtr info = new nsDNSServiceInfo(); + + if (NS_WARN_IF(!info)) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aServiceName)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aReplyDomain)))) { return; } + + if (aFlags & kDNSServiceFlagsAdd) { + mListener->OnServiceFound(info); + } else { + mListener->OnServiceLost(info); + } +} + +RegisterOperator::RegisterOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener) + : MDNSResponderOperator() + , mServiceInfo(aServiceInfo) + , mListener(aListener) +{ +} + +nsresult +RegisterOperator::Start() +{ + nsresult rv; + + rv = MDNSResponderOperator::Start(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + uint16_t port; + if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetPort(&port)))) { + return rv; + } + nsAutoCString type; + if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetServiceType(type)))) { + return rv; + } + + TXTRecordRef txtRecord; + char buf[TXT_BUFFER_SIZE] = { 0 }; + TXTRecordCreate(&txtRecord, TXT_BUFFER_SIZE, buf); + + nsCOMPtr attributes; + if (NS_FAILED(rv = mServiceInfo->GetAttributes(getter_AddRefs(attributes)))) { + LOG_I("register: no attributes"); + } else { + nsCOMPtr enumerator; + if (NS_WARN_IF(NS_FAILED(rv = + attributes->GetEnumerator(getter_AddRefs(enumerator))))) { + return rv; + } + + bool hasMoreElements; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && + hasMoreElements) { + nsCOMPtr element; + MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element))); + nsCOMPtr property = do_QueryInterface(element); + MOZ_ASSERT(property); + + nsAutoString name; + nsCOMPtr value; + MOZ_ALWAYS_SUCCEEDS(property->GetName(name)); + MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value))); + + nsAutoCString str; + if (NS_WARN_IF(NS_FAILED(value->GetAsACString(str)))) { + continue; + } + + TXTRecordSetValue(&txtRecord, + /* it's safe because key name is ASCII only. */ + NS_LossyConvertUTF16toASCII(name).get(), + str.Length(), + str.get()); + } + } + + nsAutoCString host; + nsAutoCString name; + nsAutoCString domain; + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = + DNSServiceRegister(&service, + 0, + 0, + NS_SUCCEEDED(mServiceInfo->GetServiceName(name)) ? + name.get() : nullptr, + type.get(), + NS_SUCCEEDED(mServiceInfo->GetDomainName(domain)) ? + domain.get() : nullptr, + NS_SUCCEEDED(mServiceInfo->GetHost(host)) ? + host.get() : nullptr, + NativeEndian::swapToNetworkOrder(port), + TXTRecordGetLength(&txtRecord), + TXTRecordGetBytesPtr(&txtRecord), + &RegisterReplyRunnable::Reply, + this); + NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, + "DNSServiceRegister fail"); + + TXTRecordDeallocate(&txtRecord); + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + if (mListener) { + mListener->OnRegistrationFailed(mServiceInfo, err); + } + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +nsresult +RegisterOperator::Stop() +{ + bool isServing = IsServing(); + nsresult rv = MDNSResponderOperator::Stop(); + + if (isServing && mListener) { + if (NS_SUCCEEDED(rv)) { + mListener->OnServiceUnregistered(mServiceInfo); + } else { + mListener->OnUnregistrationFailed(mServiceInfo, + static_cast(rv)); + } + } + + return rv; +} + +void +RegisterOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& aDomain) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + if (kDNSServiceErr_NoError != aErrorCode) { + LOG_E("RegisterOperator::Reply (%d)", aErrorCode); + } + + if (!mListener) { return; } + nsCOMPtr info = new nsDNSServiceInfo(mServiceInfo); + if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aName)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aDomain)))) { return; } + + if (kDNSServiceErr_NoError == aErrorCode) { + if (aFlags & kDNSServiceFlagsAdd) { + mListener->OnServiceRegistered(info); + } else { + // If a successfully-registered name later suffers a name conflict + // or similar problem and has to be deregistered, the callback will + // be invoked with the kDNSServiceFlagsAdd flag not set. + LOG_E("RegisterOperator::Reply: deregister"); + if (NS_WARN_IF(NS_FAILED(Stop()))) { + return; + } + } + } else { + mListener->OnRegistrationFailed(info, aErrorCode); + } +} + +ResolveOperator::ResolveOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) + : MDNSResponderOperator() + , mServiceInfo(aServiceInfo) + , mListener(aListener) +{ +} + +nsresult +ResolveOperator::Start() +{ + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { + return rv; + } + + nsAutoCString name; + mServiceInfo->GetServiceName(name); + nsAutoCString type; + mServiceInfo->GetServiceType(type); + nsAutoCString domain; + mServiceInfo->GetDomainName(domain); + + LOG_I("Resolve: (%s), (%s), (%s)", name.get(), type.get(), domain.get()); + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = + DNSServiceResolve(&service, + 0, + kDNSServiceInterfaceIndexAny, + name.get(), + type.get(), + domain.get(), + (DNSServiceResolveReply)&ResolveReplyRunnable::Reply, + this); + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + if (mListener) { + mListener->OnResolveFailed(mServiceInfo, err); + } + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +void +ResolveOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + auto guard = MakeScopeExit([&] { + Unused << NS_WARN_IF(NS_FAILED(Stop())); + }); + + if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { + LOG_E("ResolveOperator::Reply (%d)", aErrorCode); + return; + } + + // Resolve TXT record + int count = TXTRecordGetCount(aTxtLen, aTxtRecord); + LOG_I("resolve: txt count = %d, len = %d", count, aTxtLen); + nsCOMPtr attributes = new nsHashPropertyBag(); + if (NS_WARN_IF(!attributes)) { + return; + } + if (count) { + for (int i = 0; i < count; ++i) { + char key[TXT_BUFFER_SIZE] = { '\0' }; + uint8_t vSize = 0; + const void* value = nullptr; + if (kDNSServiceErr_NoError != + TXTRecordGetItemAtIndex(aTxtLen, + aTxtRecord, + i, + TXT_BUFFER_SIZE, + key, + &vSize, + &value)) { + break; + } + + nsAutoCString str(reinterpret_cast(value), vSize); + LOG_I("resolve TXT: (%d) %s=%s", vSize, key, str.get()); + + if (NS_WARN_IF(NS_FAILED(attributes->SetPropertyAsACString( + /* it's safe to convert because key name is ASCII only. */ + NS_ConvertASCIItoUTF16(key), + str)))) { + break; + } + } + } + + if (!mListener) { return; } + nsCOMPtr info = new nsDNSServiceInfo(mServiceInfo); + if (NS_WARN_IF(NS_FAILED(info->SetHost(aHostTarget)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetPort(aPort)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetAttributes(attributes)))) { return; } + + if (kDNSServiceErr_NoError == aErrorCode) { + GetAddrInfor(info); + } + else { + mListener->OnResolveFailed(info, aErrorCode); + Unused << NS_WARN_IF(NS_FAILED(Stop())); + } +} + +void +ResolveOperator::GetAddrInfor(nsIDNSServiceInfo* aServiceInfo) +{ + RefPtr getAddreOp = new GetAddrInfoOperator(aServiceInfo, + mListener); + Unused << NS_WARN_IF(NS_FAILED(getAddreOp->Start())); +} + +GetAddrInfoOperator::GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) + : MDNSResponderOperator() + , mServiceInfo(aServiceInfo) + , mListener(aListener) +{ +} + +nsresult +GetAddrInfoOperator::Start() +{ + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { + return rv; + } + + nsAutoCString host; + mServiceInfo->GetHost(host); + + LOG_I("GetAddrInfo: (%s)", host.get()); + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = + DNSServiceGetAddrInfo(&service, + kDNSServiceFlagsForceMulticast, + kDNSServiceInterfaceIndexAny, + kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, + host.get(), + (DNSServiceGetAddrInfoReply)&GetAddrInfoReplyRunnable::Reply, + this); + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + if (mListener) { + mListener->OnResolveFailed(mServiceInfo, err); + } + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +void +GetAddrInfoOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const NetAddr& aAddress, + uint32_t aTTL) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + auto guard = MakeScopeExit([&] { + Unused << NS_WARN_IF(NS_FAILED(Stop())); + }); + + if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { + LOG_E("GetAddrInfoOperator::Reply (%d)", aErrorCode); + return; + } + + if (!mListener) { return; } + + NetAddr addr = aAddress; + nsCOMPtr address = new nsNetAddr(&addr); + nsCString addressStr; + if (NS_WARN_IF(NS_FAILED(address->GetAddress(addressStr)))) { return; } + + nsCOMPtr info = new nsDNSServiceInfo(mServiceInfo); + if (NS_WARN_IF(NS_FAILED(info->SetAddress(addressStr)))) { return; } + + /** + * |kDNSServiceFlagsMoreComing| means this callback will be one or more + * callback events later, so this instance should be kept alive until all + * follow-up events are processed. + */ + if (aFlags & kDNSServiceFlagsMoreComing) { + guard.release(); + } + + if (kDNSServiceErr_NoError == aErrorCode) { + mListener->OnServiceResolved(info); + } else { + mListener->OnResolveFailed(info, aErrorCode); + } +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.h b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.h new file mode 100644 index 000000000..a932baa7c --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.h @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h +#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h + +#include "dns_sd.h" +#include "mozilla/Atomics.h" +#include "mozilla/RefPtr.h" +#include "nsCOMPtr.h" +#include "nsIDNSServiceDiscovery.h" +#include "nsIThread.h" +#include "nsString.h" + +namespace mozilla { +namespace net { + +class MDNSResponderOperator +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MDNSResponderOperator) + +public: + MDNSResponderOperator(); + + virtual nsresult Start(); + virtual nsresult Stop(); + void Cancel() { mIsCancelled = true; } + nsIThread* GetThread() const { return mThread; } + +protected: + virtual ~MDNSResponderOperator(); + + bool IsServing() const { return mService; } + nsresult ResetService(DNSServiceRef aService); + +private: + class ServiceWatcher; + + DNSServiceRef mService; + RefPtr mWatcher; + nsCOMPtr mThread; // remember caller thread for callback + Atomic mIsCancelled; +}; + +class BrowseOperator final : public MDNSResponderOperator +{ +public: + BrowseOperator(const nsACString& aServiceType, + nsIDNSServiceDiscoveryListener* aListener); + + nsresult Start() override; + nsresult Stop() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain); + +private: + ~BrowseOperator() = default; + + nsCString mServiceType; + nsCOMPtr mListener; +}; + +class RegisterOperator final : public MDNSResponderOperator +{ + enum { TXT_BUFFER_SIZE = 256 }; + +public: + RegisterOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener); + + nsresult Start() override; + nsresult Stop() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& aDomain); + +private: + ~RegisterOperator() = default; + + nsCOMPtr mServiceInfo; + nsCOMPtr mListener; +}; + +class ResolveOperator final : public MDNSResponderOperator +{ + enum { TXT_BUFFER_SIZE = 256 }; + +public: + ResolveOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener); + + nsresult Start() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord); + +private: + ~ResolveOperator() = default; + void GetAddrInfor(nsIDNSServiceInfo* aServiceInfo); + + nsCOMPtr mServiceInfo; + nsCOMPtr mListener; +}; + +union NetAddr; + +class GetAddrInfoOperator final : public MDNSResponderOperator +{ +public: + GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener); + + nsresult Start() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const NetAddr& aAddress, + uint32_t aTTL); + +private: + ~GetAddrInfoOperator() = default; + + nsCOMPtr mServiceInfo; + nsCOMPtr mListener; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp new file mode 100644 index 000000000..7aa5b3759 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "MDNSResponderReply.h" +#include "mozilla/EndianUtils.h" +#include "private/pprio.h" + +namespace mozilla { +namespace net { + +BrowseReplyRunnable::BrowseReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain, + BrowseOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mInterfaceIndex(aInterfaceIndex) + , mErrorCode(aErrorCode) + , mServiceName(aServiceName) + , mRegType(aRegType) + , mReplyDomain(aReplyDomain) + , mContext(aContext) +{ +} + +NS_IMETHODIMP +BrowseReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + mContext->Reply(mSdRef, + mFlags, + mInterfaceIndex, + mErrorCode, + mServiceName, + mRegType, + mReplyDomain); + return NS_OK; +} + +void +BrowseReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aServiceName, + const char* aRegType, + const char* aReplyDomain, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + BrowseOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + thread->Dispatch(new BrowseReplyRunnable(aSdRef, + aFlags, + aInterfaceIndex, + aErrorCode, + nsCString(aServiceName), + nsCString(aRegType), + nsCString(aReplyDomain), + obj), + NS_DISPATCH_NORMAL); +} + +RegisterReplyRunnable::RegisterReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& domain, + RegisterOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mErrorCode(aErrorCode) + , mName(aName) + , mRegType(aRegType) + , mDomain(domain) + , mContext(aContext) +{ +} + +NS_IMETHODIMP +RegisterReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + + mContext->Reply(mSdRef, + mFlags, + mErrorCode, + mName, + mRegType, + mDomain); + return NS_OK; +} + +void +RegisterReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const char* aName, + const char* aRegType, + const char* domain, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + RegisterOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + thread->Dispatch(new RegisterReplyRunnable(aSdRef, + aFlags, + aErrorCode, + nsCString(aName), + nsCString(aRegType), + nsCString(domain), + obj), + NS_DISPATCH_NORMAL); +} + +ResolveReplyRunnable::ResolveReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + ResolveOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mInterfaceIndex(aInterfaceIndex) + , mErrorCode(aErrorCode) + , mFullname(aFullName) + , mHosttarget(aHostTarget) + , mPort(aPort) + , mTxtLen(aTxtLen) + , mTxtRecord(new unsigned char[aTxtLen]) + , mContext(aContext) +{ + if (mTxtRecord) { + memcpy(mTxtRecord.get(), aTxtRecord, aTxtLen); + } +} + +ResolveReplyRunnable::~ResolveReplyRunnable() +{ +} + +NS_IMETHODIMP +ResolveReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + mContext->Reply(mSdRef, + mFlags, + mInterfaceIndex, + mErrorCode, + mFullname, + mHosttarget, + mPort, + mTxtLen, + mTxtRecord.get()); + return NS_OK; +} + +void +ResolveReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aFullName, + const char* aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + ResolveOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + thread->Dispatch(new ResolveReplyRunnable(aSdRef, + aFlags, + aInterfaceIndex, + aErrorCode, + nsCString(aFullName), + nsCString(aHostTarget), + NativeEndian::swapFromNetworkOrder(aPort), + aTxtLen, + aTxtRecord, + obj), + NS_DISPATCH_NORMAL); +} + +GetAddrInfoReplyRunnable::GetAddrInfoReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const mozilla::net::NetAddr& aAddress, + uint32_t aTTL, + GetAddrInfoOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mInterfaceIndex(aInterfaceIndex) + , mErrorCode(aErrorCode) + , mHostName(aHostName) + , mAddress(aAddress) + , mTTL(aTTL) + , mContext(aContext) +{ +} + +GetAddrInfoReplyRunnable::~GetAddrInfoReplyRunnable() +{ +} + +NS_IMETHODIMP +GetAddrInfoReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + mContext->Reply(mSdRef, + mFlags, + mInterfaceIndex, + mErrorCode, + mHostName, + mAddress, + mTTL); + return NS_OK; +} + +void +GetAddrInfoReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aHostName, + const struct sockaddr* aAddress, + uint32_t aTTL, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + GetAddrInfoOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + NetAddr address; + address.raw.family = aAddress->sa_family; + + static_assert(sizeof(address.raw.data) >= sizeof(aAddress->sa_data), + "size of sockaddr.sa_data is too big"); + memcpy(&address.raw.data, aAddress->sa_data, sizeof(aAddress->sa_data)); + + thread->Dispatch(new GetAddrInfoReplyRunnable(aSdRef, + aFlags, + aInterfaceIndex, + aErrorCode, + nsCString(aHostName), + address, + aTTL, + obj), + NS_DISPATCH_NORMAL); +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.h b/netwerk/dns/mdns/libmdns/MDNSResponderReply.h new file mode 100644 index 000000000..794a585f8 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h +#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h + +#include "dns_sd.h" +#include "MDNSResponderOperator.h" +#include "mozilla/UniquePtr.h" +#include "nsIThread.h" +#include "mozilla/net/DNS.h" +#include "mozilla/RefPtr.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace net { + +class BrowseReplyRunnable final : public Runnable +{ +public: + BrowseReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain, + BrowseOperator* aContext); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aServiceName, + const char* aRegType, + const char* aReplyDomain, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + uint32_t mInterfaceIndex; + DNSServiceErrorType mErrorCode; + nsCString mServiceName; + nsCString mRegType; + nsCString mReplyDomain; + RefPtr mContext; +}; + +class RegisterReplyRunnable final : public Runnable +{ +public: + RegisterReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& aDomain, + RegisterOperator* aContext); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const char* aName, + const char* aRegType, + const char* aDomain, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + DNSServiceErrorType mErrorCode; + nsCString mName; + nsCString mRegType; + nsCString mDomain; + RefPtr mContext; +}; + +class ResolveReplyRunnable final : public Runnable +{ +public: + ResolveReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + ResolveOperator* aContext); + ~ResolveReplyRunnable(); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aFullName, + const char* aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + uint32_t mInterfaceIndex; + DNSServiceErrorType mErrorCode; + nsCString mFullname; + nsCString mHosttarget; + uint16_t mPort; + uint16_t mTxtLen; + UniquePtr mTxtRecord; + RefPtr mContext; +}; + +class GetAddrInfoReplyRunnable final : public Runnable +{ +public: + GetAddrInfoReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const mozilla::net::NetAddr& aAddress, + uint32_t aTTL, + GetAddrInfoOperator* aContext); + ~GetAddrInfoReplyRunnable(); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aHostName, + const struct sockaddr* aAddress, + uint32_t aTTL, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + uint32_t mInterfaceIndex; + DNSServiceErrorType mErrorCode; + nsCString mHostName; + mozilla::net::NetAddr mAddress; + uint32_t mTTL; + RefPtr mContext; +}; + +} // namespace net +} // namespace mozilla + + #endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h diff --git a/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm b/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm new file mode 100644 index 000000000..771f9a794 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm @@ -0,0 +1,244 @@ +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- +/* 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/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["MulticastDNS"]; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Messaging.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +var log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "MulticastDNS"); + +const FAILURE_INTERNAL_ERROR = -65537; + +// Helper function for sending commands to Java. +function send(type, data, callback) { + let msg = { + type: type + }; + + for (let i in data) { + try { + msg[i] = data[i]; + } catch (e) { + } + } + + Messaging.sendRequestForResult(msg) + .then(result => callback(result, null), + err => callback(null, typeof err === "number" ? err : FAILURE_INTERNAL_ERROR)); +} + +// Receives service found/lost event from NsdManager +function ServiceManager() { +} + +ServiceManager.prototype = { + listeners: {}, + numListeners: 0, + + registerEvent: function() { + log("registerEvent"); + Messaging.addListener(this.onServiceFound.bind(this), "NsdManager:ServiceFound"); + Messaging.addListener(this.onServiceLost.bind(this), "NsdManager:ServiceLost"); + }, + + unregisterEvent: function() { + log("unregisterEvent"); + Messaging.removeListener("NsdManager:ServiceFound"); + Messaging.removeListener("NsdManager:ServiceLost"); + }, + + addListener: function(aServiceType, aListener) { + log("addListener: " + aServiceType + ", " + aListener); + + if (!this.listeners[aServiceType]) { + this.listeners[aServiceType] = []; + } + if (this.listeners[aServiceType].includes(aListener)) { + log("listener already exists"); + return; + } + + this.listeners[aServiceType].push(aListener); + ++this.numListeners; + + if (this.numListeners === 1) { + this.registerEvent(); + } + + log("listener added: " + this); + }, + + removeListener: function(aServiceType, aListener) { + log("removeListener: " + aServiceType + ", " + aListener); + + if (!this.listeners[aServiceType]) { + log("listener doesn't exist"); + return; + } + let index = this.listeners[aServiceType].indexOf(aListener); + if (index < 0) { + log("listener doesn't exist"); + return; + } + + this.listeners[aServiceType].splice(index, 1); + --this.numListeners; + + if (this.numListeners === 0) { + this.unregisterEvent(); + } + + log("listener removed" + this); + }, + + onServiceFound: function(aServiceInfo) { + let listeners = this.listeners[aServiceInfo.serviceType]; + if (listeners) { + for (let listener of listeners) { + listener.onServiceFound(aServiceInfo); + } + } else { + log("no listener"); + } + return {}; + }, + + onServiceLost: function(aServiceInfo) { + let listeners = this.listeners[aServiceInfo.serviceType]; + if (listeners) { + for (let listener of listeners) { + listener.onServiceLost(aServiceInfo); + } + } else { + log("no listener"); + } + return {}; + } +}; + +// make an object from nsIPropertyBag2 +function parsePropertyBag2(bag) { + if (!bag || !(bag instanceof Ci.nsIPropertyBag2)) { + throw new TypeError("Not a property bag"); + } + + let attributes = []; + let enumerator = bag.enumerator; + while (enumerator.hasMoreElements()) { + let name = enumerator.getNext().QueryInterface(Ci.nsIProperty).name; + let value = bag.getPropertyAsACString(name); + attributes.push({ + "name": name, + "value": value + }); + } + + return attributes; +} + +function MulticastDNS() { + this.serviceManager = new ServiceManager(); +} + +MulticastDNS.prototype = { + startDiscovery: function(aServiceType, aListener) { + this.serviceManager.addListener(aServiceType, aListener); + + let serviceInfo = { + serviceType: aServiceType, + uniqueId: aListener.uuid + }; + + send("NsdManager:DiscoverServices", serviceInfo, (result, err) => { + if (err) { + log("onStartDiscoveryFailed: " + aServiceType + " (" + err + ")"); + this.serviceManager.removeListener(aServiceType, aListener); + aListener.onStartDiscoveryFailed(aServiceType, err); + } else { + aListener.onDiscoveryStarted(result); + } + }); + }, + + stopDiscovery: function(aServiceType, aListener) { + this.serviceManager.removeListener(aServiceType, aListener); + + let serviceInfo = { + uniqueId: aListener.uuid + }; + + send("NsdManager:StopServiceDiscovery", serviceInfo, (result, err) => { + if (err) { + log("onStopDiscoveryFailed: " + aServiceType + " (" + err + ")"); + aListener.onStopDiscoveryFailed(aServiceType, err); + } else { + aListener.onDiscoveryStopped(aServiceType); + } + }); + }, + + registerService: function(aServiceInfo, aListener) { + let serviceInfo = { + port: aServiceInfo.port, + serviceType: aServiceInfo.serviceType, + uniqueId: aListener.uuid + }; + + try { + serviceInfo.host = aServiceInfo.host; + } catch(e) { + // host unspecified + } + try { + serviceInfo.serviceName = aServiceInfo.serviceName; + } catch(e) { + // serviceName unspecified + } + try { + serviceInfo.attributes = parsePropertyBag2(aServiceInfo.attributes); + } catch(e) { + // attributes unspecified + } + + send("NsdManager:RegisterService", serviceInfo, (result, err) => { + if (err) { + log("onRegistrationFailed: (" + err + ")"); + aListener.onRegistrationFailed(aServiceInfo, err); + } else { + aListener.onServiceRegistered(result); + } + }); + }, + + unregisterService: function(aServiceInfo, aListener) { + let serviceInfo = { + uniqueId: aListener.uuid + }; + + send("NsdManager:UnregisterService", serviceInfo, (result, err) => { + if (err) { + log("onUnregistrationFailed: (" + err + ")"); + aListener.onUnregistrationFailed(aServiceInfo, err); + } else { + aListener.onServiceUnregistered(aServiceInfo); + } + }); + }, + + resolveService: function(aServiceInfo, aListener) { + send("NsdManager:ResolveService", aServiceInfo, (result, err) => { + if (err) { + log("onResolveFailed: (" + err + ")"); + aListener.onResolveFailed(aServiceInfo, err); + } else { + aListener.onServiceResolved(result); + } + }); + } +}; diff --git a/netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm b/netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm new file mode 100644 index 000000000..f0539fccb --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DNSPacket.jsm @@ -0,0 +1,297 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['DNSPacket']; + +const { utils: Cu } = Components; + +Cu.import('resource://gre/modules/Services.jsm'); + +Cu.import('resource://gre/modules/DataReader.jsm'); +Cu.import('resource://gre/modules/DataWriter.jsm'); +Cu.import('resource://gre/modules/DNSRecord.jsm'); +Cu.import('resource://gre/modules/DNSResourceRecord.jsm'); + +const DEBUG = true; + +function debug(msg) { + Services.console.logStringMessage('DNSPacket: ' + msg); +} + +let DNS_PACKET_SECTION_TYPES = [ + 'QD', // Question + 'AN', // Answer + 'NS', // Authority + 'AR' // Additional +]; + +/** + * DNS Packet Structure + * ************************************************* + * + * Header + * ====== + * + * 00 2-Bytes 15 + * ------------------------------------------------- + * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| + * ------------------------------------------------- + * |<==================== ID =====================>| + * |QR|<== OP ===>|AA|TC|RD|RA|UN|AD|CD|<== RC ===>| + * |<================== QDCOUNT ==================>| + * |<================== ANCOUNT ==================>| + * |<================== NSCOUNT ==================>| + * |<================== ARCOUNT ==================>| + * ------------------------------------------------- + * + * ID: 2-Bytes + * FLAGS: 2-Bytes + * - QR: 1-Bit + * - OP: 4-Bits + * - AA: 1-Bit + * - TC: 1-Bit + * - RD: 1-Bit + * - RA: 1-Bit + * - UN: 1-Bit + * - AD: 1-Bit + * - CD: 1-Bit + * - RC: 4-Bits + * QDCOUNT: 2-Bytes + * ANCOUNT: 2-Bytes + * NSCOUNT: 2-Bytes + * ARCOUNT: 2-Bytes + * + * + * Data + * ==== + * + * 00 2-Bytes 15 + * ------------------------------------------------- + * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| + * ------------------------------------------------- + * || + * || + * || + * || + * ------------------------------------------------- + * + * QD: ??-Bytes + * AN: ??-Bytes + * NS: ??-Bytes + * AR: ??-Bytes + * + * + * Question Record + * =============== + * + * 00 2-Bytes 15 + * ------------------------------------------------- + * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| + * ------------------------------------------------- + * || + * |<=================== TYPE ====================>| + * |<=================== CLASS ===================>| + * ------------------------------------------------- + * + * NAME: ??-Bytes + * TYPE: 2-Bytes + * CLASS: 2-Bytes + * + * + * Resource Record + * =============== + * + * 00 4-Bytes 31 + * ------------------------------------------------- + * |00|02|04|06|08|10|12|14|16|18|20|22|24|26|28|30| + * ------------------------------------------------- + * || + * |<======= TYPE ========>|<======= CLASS =======>| + * |<==================== TTL ====================>| + * |<====== DATALEN ======>|| + * ------------------------------------------------- + * + * NAME: ??-Bytes + * TYPE: 2-Bytes + * CLASS: 2-Bytes + * DATALEN: 2-Bytes + * DATA: ??-Bytes (Specified By DATALEN) + */ +class DNSPacket { + constructor() { + this._flags = _valueToFlags(0x0000); + this._records = {}; + + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + this._records[sectionType] = []; + }); + } + + static parse(data) { + let reader = new DataReader(data); + if (reader.getValue(2) !== 0x0000) { + throw new Error('Packet must start with 0x0000'); + } + + let packet = new DNSPacket(); + packet._flags = _valueToFlags(reader.getValue(2)); + + let recordCounts = {}; + + // Parse the record counts. + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + recordCounts[sectionType] = reader.getValue(2); + }); + + // Parse the actual records. + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + let recordCount = recordCounts[sectionType]; + for (let i = 0; i < recordCount; i++) { + if (sectionType === 'QD') { + packet.addRecord(sectionType, + DNSRecord.parseFromPacketReader(reader)); + } + + else { + packet.addRecord(sectionType, + DNSResourceRecord.parseFromPacketReader(reader)); + } + } + }); + + if (!reader.eof) { + DEBUG && debug('Did not complete parsing packet data'); + } + + return packet; + } + + getFlag(flag) { + return this._flags[flag]; + } + + setFlag(flag, value) { + this._flags[flag] = value; + } + + addRecord(sectionType, record) { + this._records[sectionType].push(record); + } + + getRecords(sectionTypes, recordType) { + let records = []; + + sectionTypes.forEach((sectionType) => { + records = records.concat(this._records[sectionType]); + }); + + if (!recordType) { + return records; + } + + return records.filter(r => r.recordType === recordType); + } + + serialize() { + let writer = new DataWriter(); + + // Write leading 0x0000 (2 bytes) + writer.putValue(0x0000, 2); + + // Write `flags` (2 bytes) + writer.putValue(_flagsToValue(this._flags), 2); + + // Write lengths of record sections (2 bytes each) + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + writer.putValue(this._records[sectionType].length, 2); + }); + + // Write records + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + this._records[sectionType].forEach((record) => { + writer.putBytes(record.serialize()); + }); + }); + + return writer.data; + } + + toJSON() { + return JSON.stringify(this.toJSONObject()); + } + + toJSONObject() { + let result = {flags: this._flags}; + DNS_PACKET_SECTION_TYPES.forEach((sectionType) => { + result[sectionType] = []; + + let records = this._records[sectionType]; + records.forEach((record) => { + result[sectionType].push(record.toJSONObject()); + }); + }); + + return result; + } +} + +/** + * @private + */ +function _valueToFlags(value) { + return { + QR: (value & 0x8000) >> 15, + OP: (value & 0x7800) >> 11, + AA: (value & 0x0400) >> 10, + TC: (value & 0x0200) >> 9, + RD: (value & 0x0100) >> 8, + RA: (value & 0x0080) >> 7, + UN: (value & 0x0040) >> 6, + AD: (value & 0x0020) >> 5, + CD: (value & 0x0010) >> 4, + RC: (value & 0x000f) >> 0 + }; +} + +/** + * @private + */ +function _flagsToValue(flags) { + let value = 0x0000; + + value += flags.QR & 0x01; + + value <<= 4; + value += flags.OP & 0x0f; + + value <<= 1; + value += flags.AA & 0x01; + + value <<= 1; + value += flags.TC & 0x01; + + value <<= 1; + value += flags.RD & 0x01; + + value <<= 1; + value += flags.RA & 0x01; + + value <<= 1; + value += flags.UN & 0x01; + + value <<= 1; + value += flags.AD & 0x01; + + value <<= 1; + value += flags.CD & 0x01; + + value <<= 4; + value += flags.RC & 0x0f; + + return value; +} diff --git a/netwerk/dns/mdns/libmdns/fallback/DNSRecord.jsm b/netwerk/dns/mdns/libmdns/fallback/DNSRecord.jsm new file mode 100644 index 000000000..f5d48731f --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DNSRecord.jsm @@ -0,0 +1,70 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['DNSRecord']; + +const { utils: Cu } = Components; + +Cu.import('resource://gre/modules/DataWriter.jsm'); +Cu.import('resource://gre/modules/DNSTypes.jsm'); + +class DNSRecord { + constructor(properties = {}) { + this.name = properties.name || ''; + this.recordType = properties.recordType || DNS_RECORD_TYPES.ANY; + this.classCode = properties.classCode || DNS_CLASS_CODES.IN; + this.cacheFlush = properties.cacheFlush || false; + } + + static parseFromPacketReader(reader) { + let name = reader.getLabel(); + let recordType = reader.getValue(2); + let classCode = reader.getValue(2); + let cacheFlush = (classCode & 0x8000) ? true : false; + classCode &= 0xff; + + return new this({ + name: name, + recordType: recordType, + classCode: classCode, + cacheFlush: cacheFlush + }); + } + + serialize() { + let writer = new DataWriter(); + + // Write `name` (ends with trailing 0x00 byte) + writer.putLabel(this.name); + + // Write `recordType` (2 bytes) + writer.putValue(this.recordType, 2); + + // Write `classCode` (2 bytes) + let classCode = this.classCode; + if (this.cacheFlush) { + classCode |= 0x8000; + } + writer.putValue(classCode, 2); + + return writer.data; + } + + toJSON() { + return JSON.stringify(this.toJSONObject()); + } + + toJSONObject() { + return { + name: this.name, + recordType: this.recordType, + classCode: this.classCode, + cacheFlush: this.cacheFlush + }; + } +} diff --git a/netwerk/dns/mdns/libmdns/fallback/DNSResourceRecord.jsm b/netwerk/dns/mdns/libmdns/fallback/DNSResourceRecord.jsm new file mode 100644 index 000000000..ba0072a50 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DNSResourceRecord.jsm @@ -0,0 +1,221 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['DNSResourceRecord']; + +const { utils: Cu } = Components; + +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import('resource://gre/modules/DataReader.jsm'); +Cu.import('resource://gre/modules/DataWriter.jsm'); +Cu.import('resource://gre/modules/DNSRecord.jsm'); +Cu.import('resource://gre/modules/DNSTypes.jsm'); + +function debug(msg) { + Services.console.logStringMessage('MulticastDNS: ' + msg); +} + +const DNS_RESOURCE_RECORD_DEFAULT_TTL = 120; // 120 seconds + +class DNSResourceRecord extends DNSRecord { + constructor(properties = {}) { + super(properties); + + this.ttl = properties.ttl || DNS_RESOURCE_RECORD_DEFAULT_TTL; + this.data = properties.data || {}; + } + + static parseFromPacketReader(reader) { + let record = super.parseFromPacketReader(reader); + + let ttl = reader.getValue(4); + let recordData = reader.getBytes(reader.getValue(2)); + let packetData = reader.data; + + let data; + + switch (record.recordType) { + case DNS_RECORD_TYPES.A: + data = _parseA(recordData, packetData); + break; + case DNS_RECORD_TYPES.PTR: + data = _parsePTR(recordData, packetData); + break; + case DNS_RECORD_TYPES.TXT: + data = _parseTXT(recordData, packetData); + break; + case DNS_RECORD_TYPES.SRV: + data = _parseSRV(recordData, packetData); + break; + default: + data = null; + break; + } + + record.ttl = ttl; + record.data = data; + + return record; + } + + serialize() { + let writer = new DataWriter(super.serialize()); + + // Write `ttl` (4 bytes) + writer.putValue(this.ttl, 4); + + let data; + + switch (this.recordType) { + case DNS_RECORD_TYPES.A: + data = _serializeA(this.data); + break; + case DNS_RECORD_TYPES.PTR: + data = _serializePTR(this.data); + break; + case DNS_RECORD_TYPES.TXT: + data = _serializeTXT(this.data); + break; + case DNS_RECORD_TYPES.SRV: + data = _serializeSRV(this.data); + break; + default: + data = new Uint8Array(); + break; + } + + // Write `data` length. + writer.putValue(data.length, 2); + + // Write `data` (ends with trailing 0x00 byte) + writer.putBytes(data); + + return writer.data; + } + + toJSON() { + return JSON.stringify(this.toJSONObject()); + } + + toJSONObject() { + let result = super.toJSONObject(); + result.ttl = this.ttl; + result.data = this.data; + return result; + } +} + +/** + * @private + */ +function _parseA(recordData, packetData) { + let reader = new DataReader(recordData); + + let parts = []; + for (let i = 0; i < 4; i++) { + parts.push(reader.getValue(1)); + } + + return parts.join('.'); +} + +/** + * @private + */ +function _parsePTR(recordData, packetData) { + let reader = new DataReader(recordData); + + return reader.getLabel(packetData); +} + +/** + * @private + */ +function _parseTXT(recordData, packetData) { + let reader = new DataReader(recordData); + + let result = {}; + + let label = reader.getLabel(packetData); + if (label.length > 0) { + let parts = label.split('.'); + parts.forEach((part) => { + let [name] = part.split('=', 1); + let value = part.substr(name.length + 1); + result[name] = value; + }); + } + + return result; +} + +/** + * @private + */ +function _parseSRV(recordData, packetData) { + let reader = new DataReader(recordData); + + let priority = reader.getValue(2); + let weight = reader.getValue(2); + let port = reader.getValue(2); + let target = reader.getLabel(packetData); + + return { priority, weight, port, target }; +} + +/** + * @private + */ +function _serializeA(data) { + let writer = new DataWriter(); + + let parts = data.split('.'); + for (let i = 0; i < 4; i++) { + writer.putValue(parseInt(parts[i], 10) || 0); + } + + return writer.data; +} + +/** + * @private + */ +function _serializePTR(data) { + let writer = new DataWriter(); + + writer.putLabel(data); + + return writer.data; +} + +/** + * @private + */ +function _serializeTXT(data) { + let writer = new DataWriter(); + + for (let name in data) { + writer.putLengthString(name + '=' + data[name]); + } + + return writer.data; +} + +/** + * @private + */ +function _serializeSRV(data) { + let writer = new DataWriter(); + + writer.putValue(data.priority || 0, 2); + writer.putValue(data.weight || 0, 2); + writer.putValue(data.port || 0, 2); + writer.putLabel(data.target); + + return writer.data; +} diff --git a/netwerk/dns/mdns/libmdns/fallback/DNSTypes.jsm b/netwerk/dns/mdns/libmdns/fallback/DNSTypes.jsm new file mode 100644 index 000000000..8c5470639 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DNSTypes.jsm @@ -0,0 +1,100 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = [ + 'DNS_QUERY_RESPONSE_CODES', + 'DNS_AUTHORITATIVE_ANSWER_CODES', + 'DNS_CLASS_CODES', + 'DNS_RECORD_TYPES' +]; + +let DNS_QUERY_RESPONSE_CODES = { + QUERY : 0, // RFC 1035 - Query + RESPONSE : 1 // RFC 1035 - Reponse +}; + +let DNS_AUTHORITATIVE_ANSWER_CODES = { + NO : 0, // RFC 1035 - Not Authoritative + YES : 1 // RFC 1035 - Is Authoritative +}; + +let DNS_CLASS_CODES = { + IN : 0x01, // RFC 1035 - Internet + CS : 0x02, // RFC 1035 - CSNET + CH : 0x03, // RFC 1035 - CHAOS + HS : 0x04, // RFC 1035 - Hesiod + NONE : 0xfe, // RFC 2136 - None + ANY : 0xff, // RFC 1035 - Any +}; + +let DNS_RECORD_TYPES = { + SIGZERO : 0, // RFC 2931 + A : 1, // RFC 1035 + NS : 2, // RFC 1035 + MD : 3, // RFC 1035 + MF : 4, // RFC 1035 + CNAME : 5, // RFC 1035 + SOA : 6, // RFC 1035 + MB : 7, // RFC 1035 + MG : 8, // RFC 1035 + MR : 9, // RFC 1035 + NULL : 10, // RFC 1035 + WKS : 11, // RFC 1035 + PTR : 12, // RFC 1035 + HINFO : 13, // RFC 1035 + MINFO : 14, // RFC 1035 + MX : 15, // RFC 1035 + TXT : 16, // RFC 1035 + RP : 17, // RFC 1183 + AFSDB : 18, // RFC 1183 + X25 : 19, // RFC 1183 + ISDN : 20, // RFC 1183 + RT : 21, // RFC 1183 + NSAP : 22, // RFC 1706 + NSAP_PTR : 23, // RFC 1348 + SIG : 24, // RFC 2535 + KEY : 25, // RFC 2535 + PX : 26, // RFC 2163 + GPOS : 27, // RFC 1712 + AAAA : 28, // RFC 1886 + LOC : 29, // RFC 1876 + NXT : 30, // RFC 2535 + EID : 31, // RFC ???? + NIMLOC : 32, // RFC ???? + SRV : 33, // RFC 2052 + ATMA : 34, // RFC ???? + NAPTR : 35, // RFC 2168 + KX : 36, // RFC 2230 + CERT : 37, // RFC 2538 + DNAME : 39, // RFC 2672 + OPT : 41, // RFC 2671 + APL : 42, // RFC 3123 + DS : 43, // RFC 4034 + SSHFP : 44, // RFC 4255 + IPSECKEY : 45, // RFC 4025 + RRSIG : 46, // RFC 4034 + NSEC : 47, // RFC 4034 + DNSKEY : 48, // RFC 4034 + DHCID : 49, // RFC 4701 + NSEC3 : 50, // RFC ???? + NSEC3PARAM : 51, // RFC ???? + HIP : 55, // RFC 5205 + SPF : 99, // RFC 4408 + UINFO : 100, // RFC ???? + UID : 101, // RFC ???? + GID : 102, // RFC ???? + UNSPEC : 103, // RFC ???? + TKEY : 249, // RFC 2930 + TSIG : 250, // RFC 2931 + IXFR : 251, // RFC 1995 + AXFR : 252, // RFC 1035 + MAILB : 253, // RFC 1035 + MAILA : 254, // RFC 1035 + ANY : 255, // RFC 1035 + DLV : 32769 // RFC 4431 +}; diff --git a/netwerk/dns/mdns/libmdns/fallback/DataReader.jsm b/netwerk/dns/mdns/libmdns/fallback/DataReader.jsm new file mode 100644 index 000000000..a20c1dc32 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DataReader.jsm @@ -0,0 +1,133 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['DataReader']; + +class DataReader { + // `data` is `Uint8Array` + constructor(data, startByte = 0) { + this._data = data; + this._cursor = startByte; + } + + get buffer() { + return this._data.buffer; + } + + get data() { + return this._data; + } + + get eof() { + return this._cursor >= this._data.length; + } + + getBytes(length = 1) { + if (!length) { + return new Uint8Array(); + } + + let end = this._cursor + length; + if (end > this._data.length) { + return new Uint8Array(); + } + + let uint8Array = new Uint8Array(this.buffer.slice(this._cursor, end)); + this._cursor += length; + + return uint8Array; + } + + getString(length) { + let uint8Array = this.getBytes(length); + return _uint8ArrayToString(uint8Array); + } + + getValue(length) { + let uint8Array = this.getBytes(length); + return _uint8ArrayToValue(uint8Array); + } + + getLabel(decompressData) { + let parts = []; + let partLength; + + while ((partLength = this.getValue(1))) { + // If a length has been specified instead of a pointer, + // read the string of the specified length. + if (partLength !== 0xc0) { + parts.push(this.getString(partLength)); + continue; + } + + // TODO: Handle case where we have a pointer to the label + parts.push(String.fromCharCode(0xc0) + this.getString(1)); + break; + } + + let label = parts.join('.'); + + return _decompressLabel(label, decompressData || this._data); + } +} + +/** + * @private + */ +function _uint8ArrayToValue(uint8Array) { + let length = uint8Array.length; + if (length === 0) { + return null; + } + + let value = 0; + for (let i = 0; i < length; i++) { + value = value << 8; + value += uint8Array[i]; + } + + return value; +} + +/** + * @private + */ +function _uint8ArrayToString(uint8Array) { + let length = uint8Array.length; + if (length === 0) { + return ''; + } + + let results = []; + for (let i = 0; i < length; i += 1024) { + results.push(String.fromCharCode.apply(null, uint8Array.subarray(i, i + 1024))); + } + + return results.join(''); +} + +/** + * @private + */ +function _decompressLabel(label, decompressData) { + let result = ''; + + for (let i = 0, length = label.length; i < length; i++) { + if (label.charCodeAt(i) !== 0xc0) { + result += label.charAt(i); + continue; + } + + i++; + + let reader = new DataReader(decompressData, label.charCodeAt(i)); + result += _decompressLabel(reader.getLabel(), decompressData); + } + + return result; +} diff --git a/netwerk/dns/mdns/libmdns/fallback/DataWriter.jsm b/netwerk/dns/mdns/libmdns/fallback/DataWriter.jsm new file mode 100644 index 000000000..af20d65f5 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/DataWriter.jsm @@ -0,0 +1,98 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['DataWriter']; + +class DataWriter { + constructor(data, maxBytes = 512) { + if (typeof data === 'number') { + maxBytes = data; + data = undefined; + } + + this._buffer = new ArrayBuffer(maxBytes); + this._data = new Uint8Array(this._buffer); + this._cursor = 0; + + if (data) { + this.putBytes(data); + } + } + + get buffer() { + return this._buffer.slice(0, this._cursor); + } + + get data() { + return new Uint8Array(this.buffer); + } + + // `data` is `Uint8Array` + putBytes(data) { + if (this._cursor + data.length > this._data.length) { + throw new Error('DataWriter buffer is exceeded'); + } + + for (let i = 0, length = data.length; i < length; i++) { + this._data[this._cursor] = data[i]; + this._cursor++; + } + } + + putByte(byte) { + if (this._cursor + 1 > this._data.length) { + throw new Error('DataWriter buffer is exceeded'); + } + + this._data[this._cursor] = byte + this._cursor++; + } + + putValue(value, length) { + length = length || 1; + if (length == 1) { + this.putByte(value); + } else { + this.putBytes(_valueToUint8Array(value, length)); + } + } + + putLabel(label) { + // Eliminate any trailing '.'s in the label (valid in text representation). + label = label.replace(/\.$/, ''); + let parts = label.split('.'); + parts.forEach((part) => { + this.putLengthString(part); + }); + this.putValue(0); + } + + putLengthString(string) { + if (string.length > 0xff) { + throw new Error("String too long."); + } + this.putValue(string.length); + for (let i = 0; i < string.length; i++) { + this.putValue(string.charCodeAt(i)); + } + } +} + +/** + * @private + */ +function _valueToUint8Array(value, length) { + let arrayBuffer = new ArrayBuffer(length); + let uint8Array = new Uint8Array(arrayBuffer); + for (let i = length - 1; i >= 0; i--) { + uint8Array[i] = value & 0xff; + value = value >> 8; + } + + return uint8Array; +} diff --git a/netwerk/dns/mdns/libmdns/fallback/MulticastDNS.jsm b/netwerk/dns/mdns/libmdns/fallback/MulticastDNS.jsm new file mode 100644 index 000000000..f43dfd5f8 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/fallback/MulticastDNS.jsm @@ -0,0 +1,875 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */ +/* jshint esnext: true, moz: true */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['MulticastDNS']; + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import('resource://gre/modules/Timer.jsm'); +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); + +Cu.import('resource://gre/modules/DNSPacket.jsm'); +Cu.import('resource://gre/modules/DNSRecord.jsm'); +Cu.import('resource://gre/modules/DNSResourceRecord.jsm'); +Cu.import('resource://gre/modules/DNSTypes.jsm'); + +const NS_NETWORK_LINK_TOPIC = 'network:link-status-changed'; + +let observerService = Cc["@mozilla.org/observer-service;1"] + .getService(Components.interfaces.nsIObserverService); +let networkInfoService = Cc['@mozilla.org/network-info-service;1'] + .createInstance(Ci.nsINetworkInfoService); + +const DEBUG = true; + +const MDNS_MULTICAST_GROUP = '224.0.0.251'; +const MDNS_PORT = 5353; +const DEFAULT_TTL = 120; + +function debug(msg) { + dump('MulticastDNS: ' + msg + '\n'); +} + +function ServiceKey(svc) { + return "" + svc.serviceType.length + "/" + svc.serviceType + "|" + + svc.serviceName.length + "/" + svc.serviceName + "|" + + svc.port; +} + +function TryGet(obj, name) { + try { + return obj[name]; + } catch (err) { + return undefined; + } +} + +function IsIpv4Address(addr) { + let parts = addr.split('.'); + if (parts.length != 4) { + return false; + } + for (let part of parts) { + let partInt = Number.parseInt(part, 10); + if (partInt.toString() != part) { + return false; + } + if (partInt < 0 || partInt >= 256) { + return false; + } + } + return true; +} + +class PublishedService { + constructor(attrs) { + this.serviceType = attrs.serviceType.replace(/\.$/, ''); + this.serviceName = attrs.serviceName; + this.domainName = TryGet(attrs, 'domainName') || "local"; + this.address = TryGet(attrs, 'address') || "0.0.0.0"; + this.port = attrs.port; + this.serviceAttrs = _propertyBagToObject(TryGet(attrs, 'attributes') || {}); + this.host = TryGet(attrs, 'host'); + this.key = this.generateKey(); + this.lastAdvertised = undefined; + this.advertiseTimer = undefined; + } + + equals(svc) { + return (this.port == svc.port) && + (this.serviceName == svc.serviceName) && + (this.serviceType == svc.serviceType); + } + + generateKey() { + return ServiceKey(this); + } + + ptrMatch(name) { + return name == (this.serviceType + "." + this.domainName); + } + + clearAdvertiseTimer() { + if (!this.advertiseTimer) { + return; + } + clearTimeout(this.advertiseTimer); + this.advertiseTimer = undefined; + } +} + +class MulticastDNS { + constructor() { + this._listeners = new Map(); + this._sockets = new Map(); + this._services = new Map(); + this._discovered = new Map(); + this._querySocket = undefined; + this._broadcastReceiverSocket = undefined; + this._broadcastTimer = undefined; + + this._networkLinkObserver = { + observe: (subject, topic, data) => { + DEBUG && debug(NS_NETWORK_LINK_TOPIC + '(' + data + '); Clearing list of previously discovered services'); + this._discovered.clear(); + } + }; + } + + _attachNetworkLinkObserver() { + if (this._networkLinkObserverTimeout) { + clearTimeout(this._networkLinkObserverTimeout); + } + + if (!this._isNetworkLinkObserverAttached) { + DEBUG && debug('Attaching observer ' + NS_NETWORK_LINK_TOPIC); + observerService.addObserver(this._networkLinkObserver, NS_NETWORK_LINK_TOPIC, false); + this._isNetworkLinkObserverAttached = true; + } + } + + _detachNetworkLinkObserver() { + if (this._isNetworkLinkObserverAttached) { + if (this._networkLinkObserverTimeout) { + clearTimeout(this._networkLinkObserverTimeout); + } + + this._networkLinkObserverTimeout = setTimeout(() => { + DEBUG && debug('Detaching observer ' + NS_NETWORK_LINK_TOPIC); + observerService.removeObserver(this._networkLinkObserver, NS_NETWORK_LINK_TOPIC); + this._isNetworkLinkObserverAttached = false; + this._networkLinkObserverTimeout = null; + }, 5000); + } + } + + startDiscovery(aServiceType, aListener) { + DEBUG && debug('startDiscovery("' + aServiceType + '")'); + let { serviceType } = _parseServiceDomainName(aServiceType); + + this._attachNetworkLinkObserver(); + this._addServiceListener(serviceType, aListener); + + try { + this._query(serviceType + '.local'); + aListener.onDiscoveryStarted(serviceType); + } catch (e) { + DEBUG && debug('startDiscovery("' + serviceType + '") FAILED: ' + e); + this._removeServiceListener(serviceType, aListener); + aListener.onStartDiscoveryFailed(serviceType, Cr.NS_ERROR_FAILURE); + } + } + + stopDiscovery(aServiceType, aListener) { + DEBUG && debug('stopDiscovery("' + aServiceType + '")'); + let { serviceType } = _parseServiceDomainName(aServiceType); + + this._detachNetworkLinkObserver(); + this._removeServiceListener(serviceType, aListener); + + aListener.onDiscoveryStopped(serviceType); + + this._checkCloseSockets(); + } + + resolveService(aServiceInfo, aListener) { + DEBUG && debug('resolveService(): ' + aServiceInfo.serviceName); + + // Address info is already resolved during discovery + setTimeout(() => aListener.onServiceResolved(aServiceInfo)); + } + + registerService(aServiceInfo, aListener) { + DEBUG && debug('registerService(): ' + aServiceInfo.serviceName); + + // Initialize the broadcast receiver socket in case it + // hasn't already been started so we can listen for + // multicast queries/announcements on all interfaces. + this._getBroadcastReceiverSocket(); + + for (let name of ['port', 'serviceName', 'serviceType']) { + if (!TryGet(aServiceInfo, name)) { + aListener.onRegistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE); + throw new Error('Invalid nsIDNSServiceInfo; Missing "' + name + '"'); + } + } + + let publishedService; + try { + publishedService = new PublishedService(aServiceInfo); + } catch (e) { + DEBUG && debug("Error constructing PublishedService: " + e + " - " + e.stack); + setTimeout(() => aListener.onRegistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE)); + return; + } + + // Ensure such a service does not already exist. + if (this._services.get(publishedService.key)) { + setTimeout(() => aListener.onRegistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE)); + return; + } + + // Make sure that the service addr is '0.0.0.0', or there is at least one + // socket open on the address the service is open on. + this._getSockets().then((sockets) => { + if (publishedService.address != '0.0.0.0' && !sockets.get(publishedService.address)) { + setTimeout(() => aListener.onRegistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE)); + return; + } + + this._services.set(publishedService.key, publishedService); + + // Service registered.. call onServiceRegistered on next tick. + setTimeout(() => aListener.onServiceRegistered(aServiceInfo)); + + // Set a timeout to start advertising the service too. + publishedService.advertiseTimer = setTimeout(() => { + this._advertiseService(publishedService.key, /* firstAdv = */ true); + }); + }); + } + + unregisterService(aServiceInfo, aListener) { + DEBUG && debug('unregisterService(): ' + aServiceInfo.serviceName); + + let serviceKey; + try { + serviceKey = ServiceKey(aServiceInfo); + } catch (e) { + setTimeout(() => aListener.onUnregistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE)); + return; + } + + let publishedService = this._services.get(serviceKey); + if (!publishedService) { + setTimeout(() => aListener.onUnregistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE)); + return; + } + + // Clear any advertise timeout for this published service. + publishedService.clearAdvertiseTimer(); + + // Delete the service from the service map. + if (!this._services.delete(serviceKey)) { + setTimeout(() => aListener.onUnregistrationFailed(aServiceInfo, Cr.NS_ERROR_FAILURE)); + return; + } + + // Check the broadcast timer again to rejig when it should run next. + this._checkStartBroadcastTimer(); + + // Check to see if sockets should be closed, and if so close them. + this._checkCloseSockets(); + + aListener.onServiceUnregistered(aServiceInfo); + } + + _respondToQuery(serviceKey, message) { + let address = message.fromAddr.address; + let port = message.fromAddr.port; + DEBUG && debug('_respondToQuery(): key=' + serviceKey + ', fromAddr=' + + address + ":" + port); + + let publishedService = this._services.get(serviceKey); + if (!publishedService) { + debug("_respondToQuery Could not find service (key=" + serviceKey + ")"); + return; + } + + DEBUG && debug('_respondToQuery(): key=' + serviceKey + ': SENDING RESPONSE'); + this._advertiseServiceHelper(publishedService, {address,port}); + } + + _advertiseService(serviceKey, firstAdv) { + DEBUG && debug('_advertiseService(): key=' + serviceKey); + let publishedService = this._services.get(serviceKey); + if (!publishedService) { + debug("_advertiseService Could not find service to advertise (key=" + serviceKey + ")"); + return; + } + + publishedService.advertiseTimer = undefined; + + this._advertiseServiceHelper(publishedService, null).then(() => { + // If first advertisement, re-advertise in 1 second. + // Otherwise, set the lastAdvertised time. + if (firstAdv) { + publishedService.advertiseTimer = setTimeout(() => { + this._advertiseService(serviceKey) + }, 1000); + } else { + publishedService.lastAdvertised = Date.now(); + this._checkStartBroadcastTimer(); + } + }); + } + + _advertiseServiceHelper(svc, target) { + if (!target) { + target = {address:MDNS_MULTICAST_GROUP, port:MDNS_PORT}; + } + + return this._getSockets().then((sockets) => { + sockets.forEach((socket, address) => { + if (svc.address == "0.0.0.0" || address == svc.address) + { + let packet = this._makeServicePacket(svc, [address]); + let data = packet.serialize(); + try { + socket.send(target.address, target.port, data, data.length); + } catch (err) { + DEBUG && debug("Failed to send packet to " + + target.address + ":" + target.port); + } + } + }); + }); + } + + _cancelBroadcastTimer() { + if (!this._broadcastTimer) { + return; + } + clearTimeout(this._broadcastTimer); + this._broadcastTimer = undefined; + } + + _checkStartBroadcastTimer() { + DEBUG && debug("_checkStartBroadcastTimer()"); + // Cancel any existing broadcasting timer. + this._cancelBroadcastTimer(); + + let now = Date.now(); + + // Go through services and find services to broadcast. + let bcastServices = []; + let nextBcastWait = undefined; + for (let [serviceKey, publishedService] of this._services) { + // if lastAdvertised is undefined, service hasn't finished it's initial + // two broadcasts. + if (publishedService.lastAdvertised === undefined) { + continue; + } + + // Otherwise, check lastAdvertised against now. + let msSinceAdv = now - publishedService.lastAdvertised; + + // If msSinceAdv is more than 90% of the way to the TTL, advertise now. + if (msSinceAdv > (DEFAULT_TTL * 1000 * 0.9)) { + bcastServices.push(publishedService); + continue; + } + + // Otherwise, calculate the next time to advertise for this service. + // We set that at 95% of the time to the TTL expiry. + let nextAdvWait = (DEFAULT_TTL * 1000 * 0.95) - msSinceAdv; + if (nextBcastWait === undefined || nextBcastWait > nextAdvWait) { + nextBcastWait = nextAdvWait; + } + } + + // Schedule an immediate advertisement of all services to be advertised now. + for (let svc of bcastServices) { + svc.advertiseTimer = setTimeout(() => this._advertiseService(svc.key)); + } + + // Schedule next broadcast check for the next bcast time. + if (nextBcastWait !== undefined) { + DEBUG && debug("_checkStartBroadcastTimer(): Scheduling next check in " + nextBcastWait + "ms"); + this._broadcastTimer = setTimeout(() => this._checkStartBroadcastTimer(), nextBcastWait); + } + } + + _query(name) { + DEBUG && debug('query("' + name + '")'); + let packet = new DNSPacket(); + packet.setFlag('QR', DNS_QUERY_RESPONSE_CODES.QUERY); + + // PTR Record + packet.addRecord('QD', new DNSRecord({ + name: name, + recordType: DNS_RECORD_TYPES.PTR, + classCode: DNS_CLASS_CODES.IN, + cacheFlush: true + })); + + let data = packet.serialize(); + + // Initialize the broadcast receiver socket in case it + // hasn't already been started so we can listen for + // multicast queries/announcements on all interfaces. + this._getBroadcastReceiverSocket(); + + this._getQuerySocket().then((querySocket) => { + DEBUG && debug('sending query on query socket ("' + name + '")'); + querySocket.send(MDNS_MULTICAST_GROUP, MDNS_PORT, data, data.length); + }); + + // Automatically announce previously-discovered + // services that match and haven't expired yet. + setTimeout(() => { + DEBUG && debug('announcing previously discovered services ("' + name + '")'); + let { serviceType } = _parseServiceDomainName(name); + + this._clearExpiredDiscoveries(); + this._discovered.forEach((discovery, key) => { + let serviceInfo = discovery.serviceInfo; + if (serviceInfo.serviceType !== serviceType) { + return; + } + + let listeners = this._listeners.get(serviceInfo.serviceType) || []; + listeners.forEach((listener) => { + listener.onServiceFound(serviceInfo); + }); + }); + }); + } + + _clearExpiredDiscoveries() { + this._discovered.forEach((discovery, key) => { + if (discovery.expireTime < Date.now()) { + this._discovered.delete(key); + return; + } + }); + } + + _handleQueryPacket(packet, message) { + packet.getRecords(['QD']).forEach((record) => { + // Don't respond if the query's class code is not IN or ANY. + if (record.classCode !== DNS_CLASS_CODES.IN && + record.classCode !== DNS_CLASS_CODES.ANY) { + return; + } + + // Don't respond if the query's record type is not PTR or ANY. + if (record.recordType !== DNS_RECORD_TYPES.PTR && + record.recordType !== DNS_RECORD_TYPES.ANY) { + return; + } + + for (let [serviceKey, publishedService] of this._services) { + DEBUG && debug("_handleQueryPacket: " + packet.toJSON()); + if (publishedService.ptrMatch(record.name)) { + this._respondToQuery(serviceKey, message); + } + } + }); + } + + _makeServicePacket(service, addresses) { + let packet = new DNSPacket(); + packet.setFlag('QR', DNS_QUERY_RESPONSE_CODES.RESPONSE); + packet.setFlag('AA', DNS_AUTHORITATIVE_ANSWER_CODES.YES); + + let host = service.host || _hostname; + + // e.g.: foo-bar-service._http._tcp.local + let serviceDomainName = service.serviceName + '.' + service.serviceType + '.local'; + + // PTR Record + packet.addRecord('AN', new DNSResourceRecord({ + name: service.serviceType + '.local', // e.g.: _http._tcp.local + recordType: DNS_RECORD_TYPES.PTR, + data: serviceDomainName + })); + + // SRV Record + packet.addRecord('AR', new DNSResourceRecord({ + name: serviceDomainName, + recordType: DNS_RECORD_TYPES.SRV, + classCode: DNS_CLASS_CODES.IN, + cacheFlush: true, + data: { + priority: 0, + weight: 0, + port: service.port, + target: host // e.g.: My-Android-Phone.local + } + })); + + // A Records + for (let address of addresses) { + packet.addRecord('AR', new DNSResourceRecord({ + name: host, + recordType: DNS_RECORD_TYPES.A, + data: address + })); + } + + // TXT Record + packet.addRecord('AR', new DNSResourceRecord({ + name: serviceDomainName, + recordType: DNS_RECORD_TYPES.TXT, + classCode: DNS_CLASS_CODES.IN, + cacheFlush: true, + data: service.serviceAttrs || {} + })); + + return packet; + } + + _handleResponsePacket(packet, message) { + let services = {}; + let hosts = {}; + + let srvRecords = packet.getRecords(['AN', 'AR'], DNS_RECORD_TYPES.SRV); + let txtRecords = packet.getRecords(['AN', 'AR'], DNS_RECORD_TYPES.TXT); + let ptrRecords = packet.getRecords(['AN', 'AR'], DNS_RECORD_TYPES.PTR); + let aRecords = packet.getRecords(['AN', 'AR'], DNS_RECORD_TYPES.A); + + srvRecords.forEach((record) => { + let data = record.data || {}; + + services[record.name] = { + host: data.target, + port: data.port, + ttl: record.ttl + }; + }); + + txtRecords.forEach((record) => { + if (!services[record.name]) { + return; + } + + services[record.name].attributes = record.data; + }); + + aRecords.forEach((record) => { + if (IsIpv4Address(record.data)) { + hosts[record.name] = record.data; + } + }); + + ptrRecords.forEach((record) => { + let name = record.data; + if (!services[name]) { + return; + } + + let {host, port} = services[name]; + if (!host || !port) { + return; + } + + let { serviceName, serviceType, domainName } = _parseServiceDomainName(name); + if (!serviceName || !serviceType || !domainName) { + return; + } + + let address = hosts[host]; + if (!address) { + return; + } + + let ttl = services[name].ttl || 0; + let serviceInfo = { + serviceName: serviceName, + serviceType: serviceType, + host: host, + address: address, + port: port, + domainName: domainName, + attributes: services[name].attributes || {} + }; + + this._onServiceFound(serviceInfo, ttl); + }); + } + + _onServiceFound(serviceInfo, ttl = 0) { + let expireTime = Date.now() + (ttl * 1000); + let key = serviceInfo.serviceName + '.' + + serviceInfo.serviceType + '.' + + serviceInfo.domainName + ' @' + + serviceInfo.address + ':' + + serviceInfo.port; + + // If this service was already discovered, just update + // its expiration time and don't re-emit it. + if (this._discovered.has(key)) { + this._discovered.get(key).expireTime = expireTime; + return; + } + + this._discovered.set(key, { + serviceInfo: serviceInfo, + expireTime: expireTime + }); + + let listeners = this._listeners.get(serviceInfo.serviceType) || []; + listeners.forEach((listener) => { + listener.onServiceFound(serviceInfo); + }); + + DEBUG && debug('_onServiceFound()' + serviceInfo.serviceName); + } + + /** + * Gets a non-exclusive socket on 0.0.0.0:{random} to send + * multicast queries on all interfaces. This socket does + * not need to join a multicast group since it is still + * able to *send* multicast queries, but it does not need + * to *listen* for multicast queries/announcements since + * the `_broadcastReceiverSocket` is already handling them. + */ + _getQuerySocket() { + return new Promise((resolve, reject) => { + if (!this._querySocket) { + this._querySocket = _openSocket('0.0.0.0', 0, { + onPacketReceived: this._onPacketReceived.bind(this), + onStopListening: this._onStopListening.bind(this) + }); + } + resolve(this._querySocket); + }); + } + + /** + * Gets a non-exclusive socket on 0.0.0.0:5353 to listen + * for multicast queries/announcements on all interfaces. + * Since this socket needs to listen for multicast queries + * and announcements, this socket joins the multicast + * group on *all* interfaces (0.0.0.0). + */ + _getBroadcastReceiverSocket() { + return new Promise((resolve, reject) => { + if (!this._broadcastReceiverSocket) { + this._broadcastReceiverSocket = _openSocket('0.0.0.0', MDNS_PORT, { + onPacketReceived: this._onPacketReceived.bind(this), + onStopListening: this._onStopListening.bind(this) + }, /* multicastInterface = */ '0.0.0.0'); + } + resolve(this._broadcastReceiverSocket); + }); + } + + /** + * Gets a non-exclusive socket for each interface on + * {iface-ip}:5353 for sending query responses as + * well as for listening for unicast queries. These + * sockets do not need to join a multicast group + * since they are still able to *send* multicast + * query responses, but they do not need to *listen* + * for multicast queries since the `_querySocket` is + * already handling them. + */ + _getSockets() { + return new Promise((resolve) => { + if (this._sockets.size > 0) { + resolve(this._sockets); + return; + } + + Promise.all([getAddresses(), getHostname()]).then(() => { + _addresses.forEach((address) => { + let socket = _openSocket(address, MDNS_PORT, null); + this._sockets.set(address, socket); + }); + + resolve(this._sockets); + }); + }); + } + + _checkCloseSockets() { + // Nothing to do if no sockets to close. + if (this._sockets.size == 0) + return; + + // Don't close sockets if discovery listeners are still present. + if (this._listeners.size > 0) + return; + + // Don't close sockets if advertised services are present. + // Since we need to listen for service queries and respond to them. + if (this._services.size > 0) + return; + + this._closeSockets(); + } + + _closeSockets() { + this._sockets.forEach(socket => socket.close()); + this._sockets.clear(); + } + + _onPacketReceived(socket, message) { + let packet = DNSPacket.parse(message.rawData); + + switch (packet.getFlag('QR')) { + case DNS_QUERY_RESPONSE_CODES.QUERY: + this._handleQueryPacket(packet, message); + break; + case DNS_QUERY_RESPONSE_CODES.RESPONSE: + this._handleResponsePacket(packet, message); + break; + default: + break; + } + } + + _onStopListening(socket, status) { + DEBUG && debug('_onStopListening() ' + status); + } + + _addServiceListener(serviceType, listener) { + let listeners = this._listeners.get(serviceType); + if (!listeners) { + listeners = []; + this._listeners.set(serviceType, listeners); + } + + if (!listeners.find(l => l === listener)) { + listeners.push(listener); + } + } + + _removeServiceListener(serviceType, listener) { + let listeners = this._listeners.get(serviceType); + if (!listeners) { + return; + } + + let index = listeners.findIndex(l => l === listener); + if (index >= 0) { + listeners.splice(index, 1); + } + + if (listeners.length === 0) { + this._listeners.delete(serviceType); + } + } +} + +let _addresses; + +/** + * @private + */ +function getAddresses() { + return new Promise((resolve, reject) => { + if (_addresses) { + resolve(_addresses); + return; + } + + networkInfoService.listNetworkAddresses({ + onListedNetworkAddresses(aAddressArray) { + _addresses = aAddressArray.filter((address) => { + return address.indexOf('%p2p') === -1 && // No WiFi Direct interfaces + address.indexOf(':') === -1 && // XXX: No IPv6 for now + address != "127.0.0.1" // No ipv4 loopback addresses. + }); + + DEBUG && debug('getAddresses(): ' + _addresses); + resolve(_addresses); + }, + + onListNetworkAddressesFailed() { + DEBUG && debug('getAddresses() FAILED!'); + resolve([]); + } + }); + }); +} + +let _hostname; + +/** + * @private + */ +function getHostname() { + return new Promise((resolve) => { + if (_hostname) { + resolve(_hostname); + return; + } + + networkInfoService.getHostname({ + onGotHostname(aHostname) { + _hostname = aHostname.replace(/\s/g, '-') + '.local'; + + DEBUG && debug('getHostname(): ' + _hostname); + resolve(_hostname); + }, + + onGetHostnameFailed() { + DEBUG && debug('getHostname() FAILED'); + resolve('localhost'); + } + }); + }); +} + +/** + * Parse fully qualified domain name to service name, instance name, + * and domain name. See https://tools.ietf.org/html/rfc6763#section-7. + * + * Example: 'foo-bar-service._http._tcp.local' -> { + * serviceName: 'foo-bar-service', + * serviceType: '_http._tcp', + * domainName: 'local' + * } + * + * @private + */ +function _parseServiceDomainName(serviceDomainName) { + let parts = serviceDomainName.split('.'); + let index = Math.max(parts.lastIndexOf('_tcp'), parts.lastIndexOf('_udp')); + + return { + serviceName: parts.splice(0, index - 1).join('.'), + serviceType: parts.splice(0, 2).join('.'), + domainName: parts.join('.') + }; +} + +/** + * @private + */ +function _propertyBagToObject(propBag) { + let result = {}; + if (propBag.QueryInterface) { + propBag.QueryInterface(Ci.nsIPropertyBag2); + let propEnum = propBag.enumerator; + while (propEnum.hasMoreElements()) { + let prop = propEnum.getNext().QueryInterface(Ci.nsIProperty); + result[prop.name] = prop.value.toString(); + } + } else { + for (let name in propBag) { + result[name] = propBag[name].toString(); + } + } + return result; +} + +/** + * @private + */ +function _openSocket(addr, port, handler, multicastInterface) { + let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket); + socket.init2(addr, port, Services.scriptSecurityManager.getSystemPrincipal(), true); + + if (handler) { + socket.asyncListen({ + onPacketReceived: handler.onPacketReceived, + onStopListening: handler.onStopListening + }); + } + + if (multicastInterface) { + socket.joinMulticast(MDNS_MULTICAST_GROUP, multicastInterface); + } + + return socket; +} diff --git a/netwerk/dns/mdns/libmdns/moz.build b/netwerk/dns/mdns/libmdns/moz.build new file mode 100644 index 000000000..d2dca4955 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/moz.build @@ -0,0 +1,56 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa' or \ + (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] >= '16'): + UNIFIED_SOURCES += [ + 'MDNSResponderOperator.cpp', + 'MDNSResponderReply.cpp', + 'nsDNSServiceDiscovery.cpp', + ] + + LOCAL_INCLUDES += [ + '/netwerk/base', + ] + + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'external/mdnsresponder/mDNSShared', + ] + ] + +else: + EXTRA_COMPONENTS += [ + 'nsDNSServiceDiscovery.js', + 'nsDNSServiceDiscovery.manifest', + ] + + EXTRA_JS_MODULES += [ + 'fallback/DataReader.jsm', + 'fallback/DataWriter.jsm', + 'fallback/DNSPacket.jsm', + 'fallback/DNSRecord.jsm', + 'fallback/DNSResourceRecord.jsm', + 'fallback/DNSTypes.jsm', + 'fallback/MulticastDNS.jsm', + ] + + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + EXTRA_JS_MODULES += [ + 'MulticastDNSAndroid.jsm', + ] + +UNIFIED_SOURCES += [ + 'nsDNSServiceInfo.cpp', + 'nsMulticastDNSModule.cpp', +] + +include('/ipc/chromium/chromium-config.mozbuild') +FINAL_LIBRARY = 'xul' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp new file mode 100644 index 000000000..8ffa74b71 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp @@ -0,0 +1,285 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "nsDNSServiceDiscovery.h" +#include "MDNSResponderOperator.h" +#include "nsICancelable.h" +#include "nsXULAppAPI.h" +#include "private/pprio.h" + +#ifdef MOZ_WIDGET_GONK +#include +#endif // MOZ_WIDGET_GONK + +namespace mozilla { +namespace net { + +namespace { + +inline void +StartService() +{ +#ifdef MOZ_WIDGET_GONK + char value[PROPERTY_VALUE_MAX] = { '\0' }; + property_get("init.svc.mdnsd", value, ""); + + if (strcmp(value, "running") == 0) { + return; + } + property_set("ctl.start", "mdnsd"); +#endif // MOZ_WIDGET_GONK +} + +inline void +StopService() +{ +#ifdef MOZ_WIDGET_GONK + char value[PROPERTY_VALUE_MAX] = { '\0' }; + property_get("init.svc.mdnsd", value, ""); + + if (strcmp(value, "stopped") == 0) { + return; + } + property_set("ctl.stop", "mdnsd"); +#endif // MOZ_WIDGET_GONK +} + +class ServiceCounter +{ +public: + static bool IsServiceRunning() + { + return !!sUseCount; + } + +private: + static uint32_t sUseCount; + +protected: + ServiceCounter() + { + MOZ_ASSERT(NS_IsMainThread()); + if (!sUseCount++) { + StartService(); + } + } + + virtual ~ServiceCounter() + { + MOZ_ASSERT(NS_IsMainThread()); + if (!--sUseCount) { + StopService(); + } + } +}; + +uint32_t ServiceCounter::sUseCount = 0; + +class DiscoveryRequest final : public nsICancelable + , private ServiceCounter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICANCELABLE + + explicit DiscoveryRequest(nsDNSServiceDiscovery* aService, + nsIDNSServiceDiscoveryListener* aListener); + +private: + virtual ~DiscoveryRequest() { Cancel(NS_OK); } + + RefPtr mService; + nsIDNSServiceDiscoveryListener* mListener; +}; + +NS_IMPL_ISUPPORTS(DiscoveryRequest, nsICancelable) + +DiscoveryRequest::DiscoveryRequest(nsDNSServiceDiscovery* aService, + nsIDNSServiceDiscoveryListener* aListener) + : mService(aService) + , mListener(aListener) +{ +} + +NS_IMETHODIMP +DiscoveryRequest::Cancel(nsresult aReason) +{ + if (mService) { + mService->StopDiscovery(mListener); + } + + mService = nullptr; + return NS_OK; +} + +class RegisterRequest final : public nsICancelable + , private ServiceCounter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICANCELABLE + + explicit RegisterRequest(nsDNSServiceDiscovery* aService, + nsIDNSRegistrationListener* aListener); + +private: + virtual ~RegisterRequest() { Cancel(NS_OK); } + + RefPtr mService; + nsIDNSRegistrationListener* mListener; +}; + +NS_IMPL_ISUPPORTS(RegisterRequest, nsICancelable) + +RegisterRequest::RegisterRequest(nsDNSServiceDiscovery* aService, + nsIDNSRegistrationListener* aListener) + : mService(aService) + , mListener(aListener) +{ +} + +NS_IMETHODIMP +RegisterRequest::Cancel(nsresult aReason) +{ + if (mService) { + mService->UnregisterService(mListener); + } + + mService = nullptr; + return NS_OK; +} + +} // namespace anonymous + +NS_IMPL_ISUPPORTS(nsDNSServiceDiscovery, nsIDNSServiceDiscovery) + +nsDNSServiceDiscovery::~nsDNSServiceDiscovery() +{ +#ifdef MOZ_WIDGET_GONK + StopService(); +#endif +} + +nsresult +nsDNSServiceDiscovery::Init() +{ + if (!XRE_IsParentProcess()) { + MOZ_ASSERT(false, "nsDNSServiceDiscovery can only be used in parent process"); + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::StartDiscovery(const nsACString& aServiceType, + nsIDNSServiceDiscoveryListener* aListener, + nsICancelable** aRetVal) +{ + MOZ_ASSERT(aRetVal); + + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = StopDiscovery(aListener)))) { + return rv; + } + + nsCOMPtr req = new DiscoveryRequest(this, aListener); + RefPtr browserOp = new BrowseOperator(aServiceType, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = browserOp->Start()))) { + return rv; + } + + mDiscoveryMap.Put(aListener, browserOp); + + req.forget(aRetVal); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::StopDiscovery(nsIDNSServiceDiscoveryListener* aListener) +{ + nsresult rv; + + RefPtr browserOp; + if (!mDiscoveryMap.Get(aListener, getter_AddRefs(browserOp))) { + return NS_OK; + } + + browserOp->Cancel(); // cancel non-started operation + if (NS_WARN_IF(NS_FAILED(rv = browserOp->Stop()))) { + return rv; + } + + mDiscoveryMap.Remove(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::RegisterService(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener, + nsICancelable** aRetVal) +{ + MOZ_ASSERT(aRetVal); + + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = UnregisterService(aListener)))) { + return rv; + } + + nsCOMPtr req = new RegisterRequest(this, aListener); + RefPtr registerOp = new RegisterOperator(aServiceInfo, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = registerOp->Start()))) { + return rv; + } + + mRegisterMap.Put(aListener, registerOp); + + req.forget(aRetVal); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::UnregisterService(nsIDNSRegistrationListener* aListener) +{ + nsresult rv; + + RefPtr registerOp; + if (!mRegisterMap.Get(aListener, getter_AddRefs(registerOp))) { + return NS_OK; + } + + registerOp->Cancel(); // cancel non-started operation + if (NS_WARN_IF(NS_FAILED(rv = registerOp->Stop()))) { + return rv; + } + + mRegisterMap.Remove(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::ResolveService(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) +{ + if (!ServiceCounter::IsServiceRunning()) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + + RefPtr resolveOp = new ResolveOperator(aServiceInfo, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = resolveOp->Start()))) { + return rv; + } + + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h new file mode 100644 index 000000000..9bf2c798a --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h +#define mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h + +#include "nsIDNSServiceDiscovery.h" +#include "nsCOMPtr.h" +#include "mozilla/RefPtr.h" +#include "nsRefPtrHashtable.h" + +namespace mozilla { +namespace net { + +class BrowseOperator; +class RegisterOperator; + +class nsDNSServiceDiscovery final : public nsIDNSServiceDiscovery +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSSERVICEDISCOVERY + + explicit nsDNSServiceDiscovery() = default; + + /* + ** The mDNS service is started on demand. If no one uses, mDNS service will not + ** start. Therefore, all operations before service started will fail + ** and get error code |kDNSServiceErr_ServiceNotRunning| defined in dns_sd.h. + **/ + nsresult Init(); + + nsresult StopDiscovery(nsIDNSServiceDiscoveryListener* aListener); + nsresult UnregisterService(nsIDNSRegistrationListener* aListener); + +private: + virtual ~nsDNSServiceDiscovery(); + + nsRefPtrHashtable mDiscoveryMap; + nsRefPtrHashtable mRegisterMap; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js new file mode 100644 index 000000000..b94f67297 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js @@ -0,0 +1,201 @@ +/* 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/. */ +"use strict"; + +const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; + +Cu.import("resource://gre/modules/ExtensionUtils.jsm"); +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +let { PlatformInfo } = ExtensionUtils; + +if (PlatformInfo.os == "android" && !Services.prefs.getBoolPref("network.mdns.use_js_fallback")) { + Cu.import("resource://gre/modules/MulticastDNSAndroid.jsm"); +} else { + Cu.import("resource://gre/modules/MulticastDNS.jsm"); +} + +const DNSSERVICEDISCOVERY_CID = Components.ID("{f9346d98-f27a-4e89-b744-493843416480}"); +const DNSSERVICEDISCOVERY_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1"; +const DNSSERVICEINFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1"; + +function log(aMsg) { + dump("-*- nsDNSServiceDiscovery.js : " + aMsg + "\n"); +} + +function generateUuid() { + var uuidGenerator = Components.classes["@mozilla.org/uuid-generator;1"]. + getService(Ci.nsIUUIDGenerator); + return uuidGenerator.generateUUID().toString(); +} + +// Helper class to transform return objects to correct type. +function ListenerWrapper(aListener, aMdns) { + this.listener = aListener; + this.mdns = aMdns; + + this.discoveryStarting = false; + this.stopDiscovery = false; + + this.registrationStarting = false; + this.stopRegistration = false; + + this.uuid = generateUuid(); +} + +ListenerWrapper.prototype = { + // Helper function for transforming an Object into nsIDNSServiceInfo. + makeServiceInfo: function (aServiceInfo) { + let serviceInfo = Cc[DNSSERVICEINFO_CONTRACT_ID].createInstance(Ci.nsIDNSServiceInfo); + + for (let name of ['host', 'address', 'port', 'serviceName', 'serviceType']) { + try { + serviceInfo[name] = aServiceInfo[name]; + } catch (e) { + // ignore exceptions + } + } + + let attributes; + try { + attributes = _toPropertyBag2(aServiceInfo.attributes); + } catch (err) { + // Ignore unset attributes in object. + log("Caught unset attributes error: " + err + " - " + err.stack); + attributes = Cc['@mozilla.org/hash-property-bag;1'] + .createInstance(Ci.nsIWritablePropertyBag2); + } + serviceInfo.attributes = attributes; + + return serviceInfo; + }, + + /* transparent types */ + onDiscoveryStarted: function(aServiceType) { + this.discoveryStarting = false; + this.listener.onDiscoveryStarted(aServiceType); + + if (this.stopDiscovery) { + this.mdns.stopDiscovery(aServiceType, this); + } + }, + onDiscoveryStopped: function(aServiceType) { + this.listener.onDiscoveryStopped(aServiceType); + }, + onStartDiscoveryFailed: function(aServiceType, aErrorCode) { + log('onStartDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')'); + this.discoveryStarting = false; + this.stopDiscovery = true; + this.listener.onStartDiscoveryFailed(aServiceType, aErrorCode); + }, + onStopDiscoveryFailed: function(aServiceType, aErrorCode) { + log('onStopDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')'); + this.listener.onStopDiscoveryFailed(aServiceType, aErrorCode); + }, + + /* transform types */ + onServiceFound: function(aServiceInfo) { + this.listener.onServiceFound(this.makeServiceInfo(aServiceInfo)); + }, + onServiceLost: function(aServiceInfo) { + this.listener.onServiceLost(this.makeServiceInfo(aServiceInfo)); + }, + onServiceRegistered: function(aServiceInfo) { + this.registrationStarting = false; + this.listener.onServiceRegistered(this.makeServiceInfo(aServiceInfo)); + + if (this.stopRegistration) { + this.mdns.unregisterService(aServiceInfo, this); + } + }, + onServiceUnregistered: function(aServiceInfo) { + this.listener.onServiceUnregistered(this.makeServiceInfo(aServiceInfo)); + }, + onServiceResolved: function(aServiceInfo) { + this.listener.onServiceResolved(this.makeServiceInfo(aServiceInfo)); + }, + + onRegistrationFailed: function(aServiceInfo, aErrorCode) { + log('onRegistrationFailed: (' + aErrorCode + ')'); + this.registrationStarting = false; + this.stopRegistration = true; + this.listener.onRegistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode); + }, + onUnregistrationFailed: function(aServiceInfo, aErrorCode) { + log('onUnregistrationFailed: (' + aErrorCode + ')'); + this.listener.onUnregistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode); + }, + onResolveFailed: function(aServiceInfo, aErrorCode) { + log('onResolveFailed: (' + aErrorCode + ')'); + this.listener.onResolveFailed(this.makeServiceInfo(aServiceInfo), aErrorCode); + } +}; + +function nsDNSServiceDiscovery() { + log("nsDNSServiceDiscovery"); + this.mdns = new MulticastDNS(); +} + +nsDNSServiceDiscovery.prototype = { + classID: DNSSERVICEDISCOVERY_CID, + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIDNSServiceDiscovery]), + + startDiscovery: function(aServiceType, aListener) { + log("startDiscovery"); + let listener = new ListenerWrapper(aListener, this.mdns); + listener.discoveryStarting = true; + this.mdns.startDiscovery(aServiceType, listener); + + return { + QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), + cancel: (function() { + if (this.discoveryStarting || this.stopDiscovery) { + this.stopDiscovery = true; + return; + } + this.mdns.stopDiscovery(aServiceType, listener); + }).bind(listener) + }; + }, + + registerService: function(aServiceInfo, aListener) { + log("registerService"); + let listener = new ListenerWrapper(aListener, this.mdns); + listener.registrationStarting = true; + this.mdns.registerService(aServiceInfo, listener); + + return { + QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), + cancel: (function() { + if (this.registrationStarting || this.stopRegistration) { + this.stopRegistration = true; + return; + } + this.mdns.unregisterService(aServiceInfo, listener); + }).bind(listener) + }; + }, + + resolveService: function(aServiceInfo, aListener) { + log("resolveService"); + this.mdns.resolveService(aServiceInfo, new ListenerWrapper(aListener)); + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsDNSServiceDiscovery]); + +function _toPropertyBag2(obj) +{ + if (obj.QueryInterface) { + return obj.QueryInterface(Ci.nsIPropertyBag2); + } + + let result = Cc['@mozilla.org/hash-property-bag;1'] + .createInstance(Ci.nsIWritablePropertyBag2); + for (let name in obj) { + result.setPropertyAsAString(name, obj[name]); + } + return result; +} diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.manifest b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.manifest new file mode 100644 index 000000000..c17e719f2 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.manifest @@ -0,0 +1,3 @@ +# nsDNSServiceDiscovery.js +component {f9346d98-f27a-4e89-b744-493843416480} nsDNSServiceDiscovery.js +contract @mozilla.org/toolkit/components/mdnsresponder/dns-sd;1 {f9346d98-f27a-4e89-b744-493843416480} diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp b/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp new file mode 100644 index 000000000..7c67b49ac --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.cpp @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "nsDNSServiceInfo.h" +#include "nsHashPropertyBag.h" +#include "nsIProperty.h" +#include "nsISimpleEnumerator.h" +#include "nsISupportsImpl.h" +#include "mozilla/Unused.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS(nsDNSServiceInfo, nsIDNSServiceInfo) + +nsDNSServiceInfo::nsDNSServiceInfo(nsIDNSServiceInfo* aServiceInfo) +{ + if (NS_WARN_IF(!aServiceInfo)) { + return; + } + + nsAutoCString str; + uint16_t value; + + if (NS_SUCCEEDED(aServiceInfo->GetHost(str))) { + Unused << NS_WARN_IF(NS_FAILED(SetHost(str))); + } + if (NS_SUCCEEDED(aServiceInfo->GetAddress(str))) { + Unused << NS_WARN_IF(NS_FAILED(SetAddress(str))); + } + if (NS_SUCCEEDED(aServiceInfo->GetPort(&value))) { + Unused << NS_WARN_IF(NS_FAILED(SetPort(value))); + } + if (NS_SUCCEEDED(aServiceInfo->GetServiceName(str))) { + Unused << NS_WARN_IF(NS_FAILED(SetServiceName(str))); + } + if (NS_SUCCEEDED(aServiceInfo->GetServiceType(str))) { + Unused << NS_WARN_IF(NS_FAILED(SetServiceType(str))); + } + if (NS_SUCCEEDED(aServiceInfo->GetDomainName(str))) { + Unused << NS_WARN_IF(NS_FAILED(SetDomainName(str))); + } + + nsCOMPtr attributes; // deep copy + if (NS_SUCCEEDED(aServiceInfo->GetAttributes(getter_AddRefs(attributes)))) { + nsCOMPtr enumerator; + if (NS_WARN_IF(NS_FAILED(attributes->GetEnumerator(getter_AddRefs(enumerator))))) { + return; + } + + nsCOMPtr newAttributes = new nsHashPropertyBag(); + + bool hasMoreElements; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && + hasMoreElements) { + nsCOMPtr element; + Unused << + NS_WARN_IF(NS_FAILED(enumerator->GetNext(getter_AddRefs(element)))); + nsCOMPtr property = do_QueryInterface(element); + MOZ_ASSERT(property); + + nsAutoString name; + nsCOMPtr value; + Unused << NS_WARN_IF(NS_FAILED(property->GetName(name))); + Unused << NS_WARN_IF(NS_FAILED(property->GetValue(getter_AddRefs(value)))); + nsAutoCString valueStr; + Unused << NS_WARN_IF(NS_FAILED(value->GetAsACString(valueStr))); + + Unused << NS_WARN_IF(NS_FAILED(newAttributes->SetPropertyAsACString(name, valueStr))); + } + + Unused << NS_WARN_IF(NS_FAILED(SetAttributes(newAttributes))); + } +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetHost(nsACString& aHost) +{ + if (!mIsHostSet) { + return NS_ERROR_NOT_INITIALIZED; + } + aHost = mHost; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetHost(const nsACString& aHost) +{ + mHost = aHost; + mIsHostSet = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetAddress(nsACString& aAddress) +{ + if (!mIsAddressSet) { + return NS_ERROR_NOT_INITIALIZED; + } + aAddress = mAddress; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetAddress(const nsACString& aAddress) +{ + mAddress = aAddress; + mIsAddressSet = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetPort(uint16_t* aPort) +{ + if (NS_WARN_IF(!aPort)) { + return NS_ERROR_INVALID_ARG; + } + if (!mIsPortSet) { + return NS_ERROR_NOT_INITIALIZED; + } + *aPort = mPort; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetPort(uint16_t aPort) +{ + mPort = aPort; + mIsPortSet = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetServiceName(nsACString& aServiceName) +{ + if (!mIsServiceNameSet) { + return NS_ERROR_NOT_INITIALIZED; + } + aServiceName = mServiceName; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetServiceName(const nsACString& aServiceName) +{ + mServiceName = aServiceName; + mIsServiceNameSet = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetServiceType(nsACString& aServiceType) +{ + if (!mIsServiceTypeSet) { + return NS_ERROR_NOT_INITIALIZED; + } + aServiceType = mServiceType; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetServiceType(const nsACString& aServiceType) +{ + mServiceType = aServiceType; + mIsServiceTypeSet = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetDomainName(nsACString& aDomainName) +{ + if (!mIsDomainNameSet) { + return NS_ERROR_NOT_INITIALIZED; + } + aDomainName = mDomainName; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetDomainName(const nsACString& aDomainName) +{ + mDomainName = aDomainName; + mIsDomainNameSet = true; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::GetAttributes(nsIPropertyBag2** aAttributes) +{ + if (!mIsAttributesSet) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr attributes(mAttributes); + attributes.forget(aAttributes); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceInfo::SetAttributes(nsIPropertyBag2* aAttributes) +{ + mAttributes = aAttributes; + mIsAttributesSet = aAttributes ? true : false; + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.h b/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.h new file mode 100644 index 000000000..cca9c5d01 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceInfo.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceInfo_h +#define mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceInfo_h + +#include "nsCOMPtr.h" +#include "nsIDNSServiceDiscovery.h" +#include "nsIPropertyBag2.h" +#include "nsString.h" + +namespace mozilla { +namespace net { + +class nsDNSServiceInfo final : public nsIDNSServiceInfo +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSSERVICEINFO + + explicit nsDNSServiceInfo() = default; + explicit nsDNSServiceInfo(nsIDNSServiceInfo* aServiceInfo); + +private: + virtual ~nsDNSServiceInfo() = default; + +private: + nsCString mHost; + nsCString mAddress; + uint16_t mPort = 0; + nsCString mServiceName; + nsCString mServiceType; + nsCString mDomainName; + nsCOMPtr mAttributes; + + bool mIsHostSet = false; + bool mIsAddressSet = false; + bool mIsPortSet = false; + bool mIsServiceNameSet = false; + bool mIsServiceTypeSet = false; + bool mIsDomainNameSet = false; + bool mIsAttributesSet = false; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceInfo_h diff --git a/netwerk/dns/mdns/libmdns/nsMulticastDNSModule.cpp b/netwerk/dns/mdns/libmdns/nsMulticastDNSModule.cpp new file mode 100644 index 000000000..22bad3bc7 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsMulticastDNSModule.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#if defined(MOZ_WIDGET_COCOA) || (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16) +#define ENABLE_DNS_SERVICE_DISCOVERY +#endif + +#include "mozilla/ModuleUtils.h" + +#ifdef ENABLE_DNS_SERVICE_DISCOVERY +#include "nsDNSServiceDiscovery.h" +#endif + +#include "nsDNSServiceInfo.h" + +#ifdef ENABLE_DNS_SERVICE_DISCOVERY +using mozilla::net::nsDNSServiceDiscovery; +#define DNSSERVICEDISCOVERY_CID \ + {0x8df43d23, 0xd3f9, 0x4dd5, \ + { 0xb9, 0x65, 0xde, 0x2c, 0xa3, 0xf6, 0xa4, 0x2c }} +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDNSServiceDiscovery, Init) +NS_DEFINE_NAMED_CID(DNSSERVICEDISCOVERY_CID); +#endif // ENABLE_DNS_SERVICE_DISCOVERY + +using mozilla::net::nsDNSServiceInfo; +#define DNSSERVICEINFO_CID \ + {0x14a50f2b, 0x7ff6, 0x48a5, \ + { 0x88, 0xe3, 0x61, 0x5f, 0xd1, 0x11, 0xf5, 0xd3 }} +NS_GENERIC_FACTORY_CONSTRUCTOR(nsDNSServiceInfo) +NS_DEFINE_NAMED_CID(DNSSERVICEINFO_CID); + +static const mozilla::Module::CIDEntry knsDNSServiceDiscoveryCIDs[] = { +#ifdef ENABLE_DNS_SERVICE_DISCOVERY + { &kDNSSERVICEDISCOVERY_CID, false, nullptr, nsDNSServiceDiscoveryConstructor }, +#endif + { &kDNSSERVICEINFO_CID, false, nullptr, nsDNSServiceInfoConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry knsDNSServiceDiscoveryContracts[] = { +#ifdef ENABLE_DNS_SERVICE_DISCOVERY + { DNSSERVICEDISCOVERY_CONTRACT_ID, &kDNSSERVICEDISCOVERY_CID }, +#endif + { DNSSERVICEINFO_CONTRACT_ID, &kDNSSERVICEINFO_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry knsDNSServiceDiscoveryCategories[] = { + { nullptr } +}; + +static const mozilla::Module knsDNSServiceDiscoveryModule = { + mozilla::Module::kVersion, + knsDNSServiceDiscoveryCIDs, + knsDNSServiceDiscoveryContracts, + knsDNSServiceDiscoveryCategories +}; + +NSMODULE_DEFN(nsDNSServiceDiscoveryModule) = &knsDNSServiceDiscoveryModule; diff --git a/netwerk/dns/mdns/moz.build b/netwerk/dns/mdns/moz.build new file mode 100644 index 000000000..190bb48e5 --- /dev/null +++ b/netwerk/dns/mdns/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +DIRS += ['libmdns'] + +XPIDL_SOURCES += [ + 'nsIDNSServiceDiscovery.idl', +] + +XPIDL_MODULE = 'necko_mdns' diff --git a/netwerk/dns/mdns/nsIDNSServiceDiscovery.idl b/netwerk/dns/mdns/nsIDNSServiceDiscovery.idl new file mode 100644 index 000000000..23c678ecc --- /dev/null +++ b/netwerk/dns/mdns/nsIDNSServiceDiscovery.idl @@ -0,0 +1,219 @@ +/* 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/. */ + +#include "nsISupports.idl" + +interface nsICancelable; +interface nsIPropertyBag2; + +/** + * Service information + */ +[scriptable, uuid(670ed0f9-2fa5-4544-bf1e-ea58ac179374)] +interface nsIDNSServiceInfo : nsISupports +{ + /** + * The host name of the service. (E.g. "Android.local.") + * @throws NS_ERROR_NOT_INITIALIZED when getting unset value. + */ + attribute AUTF8String host; + + /** + * The IP address of the service. + * @throws NS_ERROR_NOT_INITIALIZED when getting unset value. + */ + attribute AUTF8String address; + + /** + * The port number of the service. (E.g. 80) + * @throws NS_ERROR_NOT_INITIALIZED when getting unset value. + */ + attribute unsigned short port; + + /** + * The service name of the service for display. (E.g. "My TV") + * @throws NS_ERROR_NOT_INITIALIZED when getting unset value. + */ + attribute AUTF8String serviceName; + + /** + * The type of the service. (E.g. "_http._tcp") + * @throws NS_ERROR_NOT_INITIALIZED when getting unset value. + */ + attribute AUTF8String serviceType; + + /** + * The domain name of the service. (E.g. "local.") + * @throws NS_ERROR_NOT_INITIALIZED when getting unset value. + */ + attribute AUTF8String domainName; + + /** + * The attributes of the service. + */ + attribute nsIPropertyBag2 attributes; +}; + +/** + * The callback interface for service discovery + */ +[scriptable, uuid(3025b7f2-97bb-435b-b43d-26731b3f5fc4)] +interface nsIDNSServiceDiscoveryListener : nsISupports +{ + /** + * Callback when the discovery begins. + * @param aServiceType + * the service type of |startDiscovery|. + */ + void onDiscoveryStarted(in AUTF8String aServiceType); + + /** + * Callback when the discovery ends. + * @param aServiceType + * the service type of |startDiscovery|. + */ + void onDiscoveryStopped(in AUTF8String aServiceType); + + /** + * Callback when the a service is found. + * @param aServiceInfo + * the info about the found service, where |serviceName|, |aServiceType|, and |domainName| are set. + */ + void onServiceFound(in nsIDNSServiceInfo aServiceInfo); + + /** + * Callback when the a service is lost. + * @param aServiceInfo + * the info about the lost service, where |serviceName|, |aServiceType|, and |domainName| are set. + */ + void onServiceLost(in nsIDNSServiceInfo aServiceInfo); + + /** + * Callback when the discovery cannot start. + * @param aServiceType + * the service type of |startDiscovery|. + * @param aErrorCode + * the error code. + */ + void onStartDiscoveryFailed(in AUTF8String aServiceType, in long aErrorCode); + + /** + * Callback when the discovery cannot stop. + * @param aServiceType + * the service type of |startDiscovery|. + * @param aErrorCode + * the error code. + */ + void onStopDiscoveryFailed(in AUTF8String aServiceType, in long aErrorCode); +}; + +/** + * The callback interface for service registration + */ +[scriptable, uuid(e165e4be-abf4-4963-a66d-ed3ca116e5e4)] +interface nsIDNSRegistrationListener : nsISupports +{ + const long ERROR_SERVICE_NOT_RUNNING = -65563; + + /** + * Callback when the service is registered successfully. + * @param aServiceInfo + * the info about the registered service, + * where |serviceName|, |aServiceType|, and |domainName| are set. + */ + void onServiceRegistered(in nsIDNSServiceInfo aServiceInfo); + + /** + * Callback when the service is unregistered successfully. + * @param aServiceInfo + * the info about the unregistered service. + */ + void onServiceUnregistered(in nsIDNSServiceInfo aServiceInfo); + + /** + * Callback when the service cannot be registered. + * @param aServiceInfo + * the info about the service to be registered. + * @param aErrorCode + * the error code. + */ + void onRegistrationFailed(in nsIDNSServiceInfo aServiceInfo, in long aErrorCode); + + /** + * Callback when the service cannot be unregistered. + * @param aServiceInfo + * the info about the registered service. + * @param aErrorCode + * the error code. + */ + void onUnregistrationFailed(in nsIDNSServiceInfo aServiceInfo, in long aErrorCode); +}; + +/** + * The callback interface for service resolve + */ +[scriptable, uuid(24ee6408-648e-421d-accf-c6e5adeccf97)] +interface nsIDNSServiceResolveListener : nsISupports +{ + /** + * Callback when the service is resolved successfully. + * @param aServiceInfo + * the info about the resolved service, where |host| and |port| are set. + */ + void onServiceResolved(in nsIDNSServiceInfo aServiceInfo); + + /** + * Callback when the service cannot be resolved. + * @param aServiceInfo + * the info about the service to be resolved. + * @param aErrorCode + * the error code. + */ + void onResolveFailed(in nsIDNSServiceInfo aServiceInfo, in long aErrorCode); +}; + +/** + * The interface for DNS service discovery/registration/resolve + */ +[scriptable, uuid(6487899b-beb1-455a-ba65-e4fd465066d7)] +interface nsIDNSServiceDiscovery : nsISupports +{ + /** + * Browse for instances of a service. + * @param aServiceType + * the service type to be discovered, E.g. "_http._tcp". + * @param aListener + * callback interface for discovery notifications. + * @return An object that can be used to cancel the service discovery. + */ + nsICancelable startDiscovery(in AUTF8String aServiceType, in nsIDNSServiceDiscoveryListener aListener); + + /** + * Register a service that is discovered via |startDiscovery| and |resolveService| calls. + * @param aServiceInfo + * the service information to be registered. + * |port| and |aServiceType| are required attributes. + * @param aListener + * callback interface for registration notifications. + * @return An object that can be used to cancel the service registration. + */ + nsICancelable registerService(in nsIDNSServiceInfo aServiceInfo, in nsIDNSRegistrationListener aListener); + + /** + * Resolve a service name discovered via |startDiscovery| to a target host name, port number. + * @param aServiceInfo + * the service information to be registered. + * |serviceName|, |aServiceType|, and |domainName| are required attributes as reported to the |onServiceFound| callback. + * @param aListener + * callback interface for registration notifications. + */ + void resolveService(in nsIDNSServiceInfo aServiceInfo, in nsIDNSServiceResolveListener aListener); +}; + +%{ C++ +#define DNSSERVICEDISCOVERY_CONTRACT_ID \ + "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1" +#define DNSSERVICEINFO_CONTRACT_ID \ + "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1" +%} diff --git a/netwerk/dns/moz.build b/netwerk/dns/moz.build new file mode 100644 index 000000000..f788d9a33 --- /dev/null +++ b/netwerk/dns/moz.build @@ -0,0 +1,78 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +DIRS += [ + 'mdns', +] + +XPIDL_SOURCES += [ + 'nsIDNSListener.idl', + 'nsIDNSRecord.idl', + 'nsIDNSService.idl', + 'nsIEffectiveTLDService.idl', + 'nsIIDNService.idl', + 'nsPIDNSService.idl', +] + +XPIDL_MODULE = 'necko_dns' + +EXPORTS.mozilla.net += [ + 'ChildDNSService.h', + 'DNS.h', + 'DNSListenerProxy.h', + 'DNSRequestChild.h', + 'DNSRequestParent.h', + 'PDNSParams.h', +] + +SOURCES += [ + 'nsEffectiveTLDService.cpp', # Excluded from UNIFIED_SOURCES due to special build flags. + 'nsHostResolver.cpp', # Redefines LOG +] + +UNIFIED_SOURCES += [ + 'ChildDNSService.cpp', + 'DNS.cpp', + 'DNSListenerProxy.cpp', + 'DNSRequestChild.cpp', + 'DNSRequestParent.cpp', + 'GetAddrInfo.cpp', + 'nsDNSService2.cpp', + 'nsIDNService.cpp', + 'punycode.c', +] + +IPDL_SOURCES = [ + 'PDNSRequest.ipdl', + 'PDNSRequestParams.ipdlh', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' + +GENERATED_FILES = [ + 'etld_data.inc', +] +etld_data = GENERATED_FILES['etld_data.inc'] +etld_data.script = 'prepare_tlds.py' +etld_data.inputs = ['effective_tld_names.dat'] + +# need to include etld_data.inc +LOCAL_INCLUDES += [ + '/netwerk/base', +] + +if CONFIG['ENABLE_INTL_API']: + DEFINES['IDNA2008'] = True + USE_LIBS += ['icu'] +else: + UNIFIED_SOURCES += [ + 'nameprep.c', + ] + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/netwerk/dns/nameprep.c b/netwerk/dns/nameprep.c new file mode 100644 index 000000000..039797885 --- /dev/null +++ b/netwerk/dns/nameprep.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2001,2002 Japan Network Information Center. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set forth bellow. + * + * LICENSE TERMS AND CONDITIONS + * + * The following License Terms and Conditions apply, unless a different + * license is obtained from Japan Network Information Center ("JPNIC"), + * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, + * Chiyoda-ku, Tokyo 101-0047, Japan. + * + * 1. Use, Modification and Redistribution (including distribution of any + * modified or derived work) in source and/or binary forms is permitted + * under this License Terms and Conditions. + * + * 2. Redistribution of source code must retain the copyright notices as they + * appear in each source code file, this License Terms and Conditions. + * + * 3. Redistribution in binary form must reproduce the Copyright Notice, + * this License Terms and Conditions, in the documentation and/or other + * materials provided with the distribution. For the purposes of binary + * distribution the "Copyright Notice" refers to the following language: + * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." + * + * 4. The name of JPNIC may not be used to endorse or promote products + * derived from this Software without specific prior written approval of + * JPNIC. + * + * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + + +#include +#include + +#include "nsIDNKitInterface.h" + +#define UCS_MAX 0x7fffffff +#define UNICODE_MAX 0x10ffff + + +/* + * Load NAMEPREP compiled tables. + */ +#include "nameprepdata.c" + +/* + * Define mapping/checking functions for each version of the draft. + */ + +#define VERSION id11 +#include "nameprep_template.c" +#undef VERSION + +typedef const char *(*nameprep_mapproc)(uint32_t v); +typedef int (*nameprep_checkproc)(uint32_t v); +typedef idn_biditype_t (*nameprep_biditypeproc)(uint32_t v); + +static struct idn_nameprep { + char *version; + nameprep_mapproc map_proc; + nameprep_checkproc prohibited_proc; + nameprep_checkproc unassigned_proc; + nameprep_biditypeproc biditype_proc; +} nameprep_versions[] = { +#define MAKE_NAMEPREP_HANDLE(version, id) \ + { version, \ + compose_sym2(nameprep_map_, id), \ + compose_sym2(nameprep_prohibited_, id), \ + compose_sym2(nameprep_unassigned_, id), \ + compose_sym2(nameprep_biditype_, id), } + MAKE_NAMEPREP_HANDLE("nameprep-11", id11), + { NULL, NULL, NULL, NULL, NULL }, +}; + +static idn_result_t idn_nameprep_check(nameprep_checkproc proc, + const uint32_t *str, + const uint32_t **found); + +idn_result_t +idn_nameprep_create(const char *version, idn_nameprep_t *handlep) { + idn_nameprep_t handle; + + assert(handlep != NULL); + + TRACE(("idn_nameprep_create(version=%-.50s)\n", + version == NULL ? "" : version)); + + if (version == NULL) + version = IDN_NAMEPREP_CURRENT; + + /* + * Lookup table for the specified version. Since the number of + * versions won't be large (I don't want see draft-23 or such :-), + * simple linear search is OK. + */ + for (handle = nameprep_versions; handle->version != NULL; handle++) { + if (strcmp(handle->version, version) == 0) { + *handlep = handle; + return (idn_success); + } + } + return (idn_notfound); +} + +void +idn_nameprep_destroy(idn_nameprep_t handle) { + assert(handle != NULL); + + TRACE(("idn_nameprep_destroy()\n")); + + /* Nothing to do. */ +} + +idn_result_t +idn_nameprep_map(idn_nameprep_t handle, const uint32_t *from, + uint32_t *to, size_t tolen) { + assert(handle != NULL && from != NULL && to != NULL); + + TRACE(("idn_nameprep_map(ctx=%s, from=\"%s\")\n", + handle->version, idn__debug_ucs4xstring(from, 50))); + + while (*from != '\0') { + uint32_t v = *from; + const char *mapped; + + if (v > UCS_MAX) { + /* This cannot happen, but just in case.. */ + return (idn_invalid_codepoint); + } else if (v > UNICODE_MAX) { + /* No mapping is possible. */ + mapped = NULL; + } else { + /* Try mapping. */ + mapped = (*handle->map_proc)(v); + } + + if (mapped == NULL) { + /* No mapping. Just copy verbatim. */ + if (tolen < 1) + return (idn_buffer_overflow); + *to++ = v; + tolen--; + } else { + const unsigned char *mappeddata; + size_t mappedlen; + + mappeddata = (const unsigned char *)mapped + 1; + mappedlen = *mapped; + + if (tolen < (mappedlen + 3) / 4) + return (idn_buffer_overflow); + tolen -= (mappedlen + 3) / 4; + while (mappedlen >= 4) { + *to = *mappeddata++; + *to |= *mappeddata++ << 8; + *to |= *mappeddata++ << 16; + *to |= *mappeddata++ << 24; + mappedlen -= 4; + to++; + } + if (mappedlen > 0) { + *to = *mappeddata++; + *to |= (mappedlen >= 2) ? + *mappeddata++ << 8: 0; + *to |= (mappedlen >= 3) ? + *mappeddata++ << 16: 0; + to++; + } + } + from++; + } + if (tolen == 0) + return (idn_buffer_overflow); + *to = '\0'; + return (idn_success); +} + +idn_result_t +idn_nameprep_isprohibited(idn_nameprep_t handle, const uint32_t *str, + const uint32_t **found) { + assert(handle != NULL && str != NULL && found != NULL); + + TRACE(("idn_nameprep_isprohibited(ctx=%s, str=\"%s\")\n", + handle->version, idn__debug_ucs4xstring(str, 50))); + + return (idn_nameprep_check(handle->prohibited_proc, str, found)); +} + +idn_result_t +idn_nameprep_isunassigned(idn_nameprep_t handle, const uint32_t *str, + const uint32_t **found) { + assert(handle != NULL && str != NULL && found != NULL); + + TRACE(("idn_nameprep_isunassigned(handle->version, str=\"%s\")\n", + handle->version, idn__debug_ucs4xstring(str, 50))); + + return (idn_nameprep_check(handle->unassigned_proc, str, found)); +} + +static idn_result_t +idn_nameprep_check(nameprep_checkproc proc, const uint32_t *str, + const uint32_t **found) { + uint32_t v; + + while (*str != '\0') { + v = *str; + + if (v > UCS_MAX) { + /* This cannot happen, but just in case.. */ + return (idn_invalid_codepoint); + } else if (v > UNICODE_MAX) { + /* It is invalid.. */ + *found = str; + return (idn_success); + } else if ((*proc)(v)) { + *found = str; + return (idn_success); + } + str++; + } + *found = NULL; + return (idn_success); +} + +idn_result_t +idn_nameprep_isvalidbidi(idn_nameprep_t handle, const uint32_t *str, + const uint32_t **found) { + uint32_t v; + idn_biditype_t first_char; + idn_biditype_t last_char; + int found_r_al; + + assert(handle != NULL && str != NULL && found != NULL); + + TRACE(("idn_nameprep_isvalidbidi(ctx=%s, str=\"%s\")\n", + handle->version, idn__debug_ucs4xstring(str, 50))); + + if (*str == '\0') { + *found = NULL; + return (idn_success); + } + + /* + * check first character's type and initialize variables. + */ + found_r_al = 0; + if (*str > UCS_MAX) { + /* This cannot happen, but just in case.. */ + return (idn_invalid_codepoint); + } else if (*str > UNICODE_MAX) { + /* It is invalid.. */ + *found = str; + return (idn_success); + } + first_char = last_char = (*(handle->biditype_proc))(*str); + if (first_char == idn_biditype_r_al) { + found_r_al = 1; + } + str++; + + /* + * see whether string is valid or not. + */ + while (*str != '\0') { + v = *str; + + if (v > UCS_MAX) { + /* This cannot happen, but just in case.. */ + return (idn_invalid_codepoint); + } else if (v > UNICODE_MAX) { + /* It is invalid.. */ + *found = str; + return (idn_success); + } else { + last_char = (*(handle->biditype_proc))(v); + if (found_r_al && last_char == idn_biditype_l) { + *found = str; + return (idn_success); + } + if (first_char != idn_biditype_r_al && last_char == idn_biditype_r_al) { + *found = str; + return (idn_success); + } + if (last_char == idn_biditype_r_al) { + found_r_al = 1; + } + } + str++; + } + + if (found_r_al) { + if (last_char != idn_biditype_r_al) { + *found = str - 1; + return (idn_success); + } + } + + *found = NULL; + return (idn_success); +} + +idn_result_t +idn_nameprep_createproc(const char *parameter, void **handlep) { + return idn_nameprep_create(parameter, (idn_nameprep_t *)handlep); +} + +void +idn_nameprep_destroyproc(void *handle) { + idn_nameprep_destroy((idn_nameprep_t)handle); +} + +idn_result_t +idn_nameprep_mapproc(void *handle, const uint32_t *from, + uint32_t *to, size_t tolen) { + return idn_nameprep_map((idn_nameprep_t)handle, from, to, tolen); +} + +idn_result_t +idn_nameprep_prohibitproc(void *handle, const uint32_t *str, + const uint32_t **found) { + return idn_nameprep_isprohibited((idn_nameprep_t)handle, str, found); +} + +idn_result_t +idn_nameprep_unassignedproc(void *handle, const uint32_t *str, + const uint32_t **found) { + return idn_nameprep_isunassigned((idn_nameprep_t)handle, str, found); +} + +idn_result_t +idn_nameprep_bidiproc(void *handle, const uint32_t *str, + const uint32_t **found) { + return idn_nameprep_isvalidbidi((idn_nameprep_t)handle, str, found); +} diff --git a/netwerk/dns/nameprep_template.c b/netwerk/dns/nameprep_template.c new file mode 100644 index 000000000..7fe36518a --- /dev/null +++ b/netwerk/dns/nameprep_template.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2001 Japan Network Information Center. All rights reserved. + * + * By using this file, you agree to the terms and conditions set forth bellow. + * + * LICENSE TERMS AND CONDITIONS + * + * The following License Terms and Conditions apply, unless a different + * license is obtained from Japan Network Information Center ("JPNIC"), + * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, + * Chiyoda-ku, Tokyo 101-0047, Japan. + * + * 1. Use, Modification and Redistribution (including distribution of any + * modified or derived work) in source and/or binary forms is permitted + * under this License Terms and Conditions. + * + * 2. Redistribution of source code must retain the copyright notices as they + * appear in each source code file, this License Terms and Conditions. + * + * 3. Redistribution in binary form must reproduce the Copyright Notice, + * this License Terms and Conditions, in the documentation and/or other + * materials provided with the distribution. For the purposes of binary + * distribution the "Copyright Notice" refers to the following language: + * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." + * + * 4. The name of JPNIC may not be used to endorse or promote products + * derived from this Software without specific prior written approval of + * JPNIC. + * + * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Include this file once for each version of NAMEPREP. + * VERSION should be defined to appropriate value before inclusion. + */ + +#ifndef NAMEPREP_TEMPLATE_INIT +#define NAMEPREP_TEMPLATE_INIT + +/* Symbol composition. */ +#define compose_sym2(a, b) compose_sym2X(a, b) +#define compose_sym2X(a, b) a ## b +#define compose_sym3(a, b, c) compose_sym3X(a, b, c) +#define compose_sym3X(a, b, c) a ## b ## c + +/* The table is based on "Optimized Two-Stage Table" mentioned in + * Unicode 3.0 page 106, extended to handle 21bit data instead of 16 bit. + */ + +/* Index calculation for multi-level index tables. */ +#define IDX0(type, v) IDX_0(v, BITS1(type), BITS2(type)) +#define IDX1(type, v) IDX_1(v, BITS1(type), BITS2(type)) +#define IDX2(type, v) IDX_2(v, BITS1(type), BITS2(type)) + +#define IDX_0(v, bits1, bits2) ((v) >> ((bits1) + (bits2))) +#define IDX_1(v, bits1, bits2) (((v) >> (bits2)) & ((1 << (bits1)) - 1)) +#define IDX_2(v, bits1, bits2) ((v) & ((1 << (bits2)) - 1)) + +#define BITS1(type) type ## _BITS_1 +#define BITS2(type) type ## _BITS_2 + +#endif /* NAMEPREP_TEMPLATE_INIT */ + +static const char * +compose_sym2(nameprep_map_, VERSION) (uint32_t v) { + int idx0 = IDX0(MAP, v); + int idx1 = IDX1(MAP, v); + int idx2 = IDX2(MAP, v); + int offset; + +#define IMAP compose_sym3(nameprep_, VERSION, _map_imap) +#define TABLE compose_sym3(nameprep_, VERSION, _map_table) +#define DATA compose_sym3(nameprep_, VERSION, _map_data) + offset = TABLE[IMAP[IMAP[idx0] + idx1]].tbl[idx2]; + if (offset == 0) + return (NULL); /* no mapping */ + return (const char *)(DATA + offset); +#undef IMAP +#undef TABLE +#undef DATA +} + +static int +compose_sym2(nameprep_prohibited_, VERSION) (uint32_t v) { + int idx0 = IDX0(PROH, v); + int idx1 = IDX1(PROH, v); + int idx2 = IDX2(PROH, v); + const unsigned char *bm; + +#define IMAP compose_sym3(nameprep_, VERSION, _prohibited_imap) +#define BITMAP compose_sym3(nameprep_, VERSION, _prohibited_bitmap) + bm = BITMAP[IMAP[IMAP[idx0] + idx1]].bm; + return (bm[idx2 / 8] & (1 << (idx2 % 8))); +#undef IMAP +#undef BITMAP +} + +static int +compose_sym2(nameprep_unassigned_, VERSION) (uint32_t v) { + int idx0 = IDX0(UNAS, v); + int idx1 = IDX1(UNAS, v); + int idx2 = IDX2(UNAS, v); + const unsigned char *bm; + +#define IMAP compose_sym3(nameprep_, VERSION, _unassigned_imap) +#define BITMAP compose_sym3(nameprep_, VERSION, _unassigned_bitmap) + bm = BITMAP[IMAP[IMAP[idx0] + idx1]].bm; + return (bm[idx2 / 8] & (1 << (idx2 % 8))); +#undef IMAP +#undef BITMAP +} + +static idn_biditype_t +compose_sym2(nameprep_biditype_, VERSION) (uint32_t v) { + int idx0 = IDX0(BIDI, v); + int idx1 = IDX1(BIDI, v); + int idx2 = IDX2(BIDI, v); + int offset; + +#define IMAP compose_sym3(nameprep_, VERSION, _bidi_imap) +#define TABLE compose_sym3(nameprep_, VERSION, _bidi_table) +#define DATA compose_sym3(nameprep_, VERSION, _bidi_data) + offset = TABLE[IMAP[IMAP[idx0] + idx1]].tbl[idx2]; + return DATA[offset]; +#undef IMAP +#undef TABLE +#undef DATA +} diff --git a/netwerk/dns/nameprepdata.c b/netwerk/dns/nameprepdata.c new file mode 100644 index 000000000..cd7e2db0e --- /dev/null +++ b/netwerk/dns/nameprepdata.c @@ -0,0 +1,2588 @@ +/* + * Copyright (c) 2001,2002 Japan Network Information Center. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set forth bellow. + * + * LICENSE TERMS AND CONDITIONS + * + * The following License Terms and Conditions apply, unless a different + * license is obtained from Japan Network Information Center ("JPNIC"), + * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, + * Chiyoda-ku, Tokyo 101-0047, Japan. + * + * 1. Use, Modification and Redistribution (including distribution of any + * modified or derived work) in source and/or binary forms is permitted + * under this License Terms and Conditions. + * + * 2. Redistribution of source code must retain the copyright notices as they + * appear in each source code file, this License Terms and Conditions. + * + * 3. Redistribution in binary form must reproduce the Copyright Notice, + * this License Terms and Conditions, in the documentation and/or other + * materials provided with the distribution. For the purposes of binary + * distribution the "Copyright Notice" refers to the following language: + * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." + * + * 4. The name of JPNIC may not be used to endorse or promote products + * derived from this Software without specific prior written approval of + * JPNIC. + * + * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + + /* + * Do not edit this file! + * This file is generated from NAMEPREP specification. + */ + +#define MAP_BITS_0 9 +#define MAP_BITS_1 7 +#define MAP_BITS_2 5 + +#define PROH_BITS_0 7 +#define PROH_BITS_1 7 +#define PROH_BITS_2 7 + +#define UNAS_BITS_0 7 +#define UNAS_BITS_1 7 +#define UNAS_BITS_2 7 + +#define BIDI_BITS_0 9 +#define BIDI_BITS_1 7 +#define BIDI_BITS_2 5 + + +static const unsigned short nameprep_id11_map_imap[] = { + 272, 400, 528, 656, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 912, + 1040, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 1168, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, + 0, 0, 1, 0, 0, 2, 3, 0, + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 14, 15, 16, 17, 18, 19, + 20, 21, 0, 22, 23, 24, 25, 26, + 27, 28, 29, 0, 30, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 31, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 0, 0, 49, 0, 50, 0, 0, + 51, 52, 53, 54, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 56, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 57, 58, 59, 60, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 61, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 62, 0, 0, 0, 0, 0, 0, 63, + 0, 64, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 65, 66, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 67, 68, 69, + 70, 80, 81, 73, 74, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const struct { + unsigned short tbl[32]; +} nameprep_id11_map_table[] = { + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, + 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, + 44, 46, 48, 50, 52, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 54, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, + 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, + 101, 0, 103, 105, 107, 109, 111, 113, 115, 117, + }}, + {{ + 123, 0, 126, 0, 129, 0, 132, 0, 135, 0, 138, + 0, 141, 0, 144, 0, 147, 0, 150, 0, 153, 0, + 156, 0, 159, 0, 162, 0, 165, 0, 168, 0, + }}, + {{ + 171, 0, 174, 0, 177, 0, 180, 0, 183, 0, 186, + 0, 189, 0, 192, 0, 195, 0, 202, 0, 205, 0, + 208, 0, 0, 211, 0, 214, 0, 217, 0, 220, + }}, + {{ + 0, 223, 0, 226, 0, 229, 0, 232, 0, 235, 241, + 0, 244, 0, 247, 0, 250, 0, 253, 0, 256, 0, + 259, 0, 262, 0, 265, 0, 268, 0, 271, 0, + }}, + {{ + 274, 0, 277, 0, 280, 0, 283, 0, 286, 0, 289, + 0, 292, 0, 295, 0, 298, 0, 301, 0, 304, 0, + 307, 0, 310, 312, 0, 315, 0, 318, 0, 38, + }}, + {{ + 0, 321, 324, 0, 327, 0, 330, 333, 0, 336, 339, + 342, 0, 0, 345, 348, 351, 354, 0, 357, 360, 0, + 363, 366, 369, 0, 0, 0, 372, 375, 0, 378, + }}, + {{ + 381, 0, 384, 0, 387, 0, 390, 393, 0, 396, 0, + 0, 399, 0, 402, 405, 0, 408, 411, 414, 0, 417, + 0, 420, 423, 0, 0, 0, 426, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 429, 429, 0, 432, 432, 0, 435, + 435, 0, 438, 0, 441, 0, 444, 0, 447, 0, 450, + 0, 453, 0, 456, 0, 459, 0, 0, 462, 0, + }}, + {{ + 465, 0, 468, 0, 471, 0, 474, 0, 477, 0, 480, + 0, 483, 0, 486, 0, 489, 496, 496, 0, 499, 0, + 502, 505, 508, 0, 511, 0, 514, 0, 517, 0, + }}, + {{ + 520, 0, 523, 0, 526, 0, 529, 0, 532, 0, 535, + 0, 538, 0, 541, 0, 544, 0, 547, 0, 550, 0, + 553, 0, 556, 0, 559, 0, 562, 0, 565, 0, + }}, + {{ + 568, 0, 571, 0, 574, 0, 577, 0, 580, 0, 583, + 0, 586, 0, 589, 0, 592, 0, 595, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 598, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 601, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 608, 0, 611, 614, 617, + 0, 620, 0, 623, 626, 629, 640, 643, 646, 649, 652, + 655, 658, 661, 598, 664, 667, 54, 670, 673, 676, + }}, + {{ + 679, 682, 0, 685, 688, 691, 694, 697, 700, 703, 706, + 709, 0, 0, 0, 0, 712, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 685, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 643, 661, 691, 623, 709, 694, + 679, 0, 723, 0, 726, 0, 729, 0, 732, 0, + }}, + {{ + 735, 0, 738, 0, 741, 0, 744, 0, 747, 0, 750, + 0, 753, 0, 756, 0, 664, 682, 685, 0, 661, 652, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 759, 762, 765, 768, 771, 774, 777, 780, 783, 786, 789, + 792, 795, 798, 801, 804, 807, 810, 813, 816, 819, 822, + 825, 828, 831, 834, 837, 840, 843, 846, 849, 852, + }}, + {{ + 855, 858, 861, 864, 867, 870, 873, 876, 879, 882, 885, + 888, 891, 894, 897, 900, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 903, 0, 906, 0, 909, 0, 912, 0, 915, 0, 918, + 0, 921, 0, 924, 0, 927, 0, 930, 0, 933, 0, + 936, 0, 939, 0, 942, 0, 945, 0, 948, 0, + }}, + {{ + 951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 954, + 0, 957, 0, 960, 0, 963, 0, 966, 0, 969, 0, + 972, 0, 975, 0, 978, 0, 981, 0, 984, 0, + }}, + {{ + 987, 0, 990, 0, 993, 0, 996, 0, 999, 0, 1002, + 0, 1005, 0, 1008, 0, 1011, 0, 1014, 0, 1017, 0, + 1020, 0, 1023, 0, 1026, 0, 1029, 0, 1032, 0, + }}, + {{ + 0, 1035, 0, 1038, 0, 1041, 0, 1044, 0, 1047, 0, + 1050, 0, 1053, 0, 0, 1056, 0, 1059, 0, 1062, 0, + 1065, 0, 1068, 0, 1071, 0, 1074, 0, 1077, 0, + }}, + {{ + 1080, 0, 1083, 0, 1086, 0, 1089, 0, 1092, 0, 1095, + 0, 1098, 0, 1101, 0, 1104, 0, 1107, 0, 1110, 0, + 0, 0, 1113, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1116, 0, 1119, 0, 1122, 0, 1125, 0, 1128, 0, 1131, + 0, 1134, 0, 1137, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1140, 1143, 1146, 1149, 1152, + 1155, 1158, 1161, 1164, 1167, 1170, 1173, 1176, 1179, 1182, + }}, + {{ + 1185, 1188, 1191, 1194, 1197, 1200, 1203, 1206, 1209, 1212, 1215, + 1218, 1221, 1224, 1227, 1230, 1233, 1236, 1239, 1242, 1245, 1248, + 1251, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 1254, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1261, 0, 1264, 0, 1267, 0, 1270, 0, 1273, 0, 1276, + 0, 1279, 0, 1282, 0, 1285, 0, 1288, 0, 1291, 0, + 1294, 0, 1297, 0, 1300, 0, 1303, 0, 1306, 0, + }}, + {{ + 1309, 0, 1312, 0, 1315, 0, 1318, 0, 1321, 0, 1324, + 0, 1327, 0, 1330, 0, 1333, 0, 1336, 0, 1339, 0, + 1342, 0, 1345, 0, 1348, 0, 1351, 0, 1354, 0, + }}, + {{ + 1357, 0, 1360, 0, 1363, 0, 1366, 0, 1369, 0, 1372, + 0, 1375, 0, 1378, 0, 1381, 0, 1384, 0, 1387, 0, + 1390, 0, 1393, 0, 1396, 0, 1399, 0, 1402, 0, + }}, + {{ + 1405, 0, 1408, 0, 1411, 0, 1414, 0, 1417, 0, 1420, + 0, 1423, 0, 1426, 0, 1429, 0, 1432, 0, 1435, 0, + 1438, 0, 1441, 0, 1444, 0, 1447, 0, 1450, 0, + }}, + {{ + 1453, 0, 1456, 0, 1459, 0, 1462, 0, 1465, 0, 1468, + 0, 1471, 0, 1474, 0, 1477, 0, 1480, 0, 1483, 0, + 1486, 1493, 1500, 1507, 1514, 1405, 0, 0, 0, 0, + }}, + {{ + 1521, 0, 1524, 0, 1527, 0, 1530, 0, 1533, 0, 1536, + 0, 1539, 0, 1542, 0, 1545, 0, 1548, 0, 1551, 0, + 1554, 0, 1557, 0, 1560, 0, 1563, 0, 1566, 0, + }}, + {{ + 1569, 0, 1572, 0, 1575, 0, 1578, 0, 1581, 0, 1584, + 0, 1587, 0, 1590, 0, 1593, 0, 1596, 0, 1599, 0, + 1602, 0, 1605, 0, 1608, 0, 1611, 0, 1614, 0, + }}, + {{ + 1617, 0, 1620, 0, 1623, 0, 1626, 0, 1629, 0, 1632, + 0, 1635, 0, 1638, 0, 1641, 0, 1644, 0, 1647, 0, + 1650, 0, 1653, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 1656, 1659, 1662, + 1665, 1668, 1671, 1674, 1677, 0, 0, 0, 0, 0, 0, + 0, 0, 1680, 1683, 1686, 1689, 1692, 1695, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 1698, 1701, 1704, + 1707, 1710, 1713, 1716, 1719, 0, 0, 0, 0, 0, 0, + 0, 0, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 1746, 1749, 1752, + 1755, 1758, 1761, 0, 0, 1764, 0, 1771, 0, 1782, 0, + 1793, 0, 0, 1804, 0, 1807, 0, 1810, 0, 1813, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 1816, 1819, 1822, + 1825, 1828, 1831, 1834, 1837, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1840, 1847, 1854, 1861, 1868, 1875, 1882, 1889, 1840, 1847, 1854, + 1861, 1868, 1875, 1882, 1889, 1896, 1903, 1910, 1917, 1924, 1931, + 1938, 1945, 1896, 1903, 1910, 1917, 1924, 1931, 1938, 1945, + }}, + {{ + 1952, 1959, 1966, 1973, 1980, 1987, 1994, 2001, 1952, 1959, 1966, + 1973, 1980, 1987, 1994, 2001, 0, 0, 2008, 2015, 2022, 0, + 2029, 2036, 2047, 2050, 2053, 2056, 2015, 0, 598, 0, + }}, + {{ + 0, 0, 2059, 2066, 2073, 0, 2080, 2087, 2098, 2101, 2104, + 2107, 2066, 0, 0, 0, 0, 0, 2110, 629, 0, 0, + 2121, 2128, 2139, 2142, 2145, 2148, 0, 0, 0, 0, + }}, + {{ + 0, 0, 2151, 712, 2162, 0, 2169, 2176, 2187, 2190, 2193, + 2196, 2199, 0, 0, 0, 0, 0, 2202, 2209, 2216, 0, + 2223, 2230, 2241, 2244, 2247, 2250, 2209, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 2253, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 6, 2259, 0, 0, 0, 351, 0, 2265, 0, + 16, 16, 16, 0, 0, 18, 18, 24, 0, 0, 28, + 2271, 0, 0, 32, 34, 36, 36, 36, 0, 0, + }}, + {{ + 2277, 2283, 2293, 0, 52, 0, 703, 0, 52, 0, 22, + 67, 4, 6, 0, 0, 10, 12, 0, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 646, 679, + }}, + {{ + 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2299, 2302, 2305, 2308, 2311, 2314, 2317, 2320, 2323, 2326, 2329, + 2332, 2335, 2338, 2341, 2344, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2347, 2350, 2353, 2356, 2359, 2362, 2365, 2368, 2371, 2374, + }}, + {{ + 2377, 2380, 2383, 2386, 2389, 2392, 2395, 2398, 2401, 2404, 2407, + 2410, 2413, 2416, 2419, 2422, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2425, 0, 2435, 0, 2441, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2447, 2453, 2459, 2465, 2471, 2477, 2483, 2489, 0, 0, 2495, + 2501, 2507, 0, 0, 0, 2513, 2519, 2529, 2539, 2549, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2447, 2559, + 2569, 2579, 0, 0, 0, 0, 0, 0, 0, 2589, 2595, + 2601, 2607, 2613, 2607, 2619, 2625, 2631, 2637, 2643, 2637, + }}, + {{ + 2649, 2656, 0, 2663, 0, 0, 2669, 2683, 2693, 2699, 0, + 2705, 0, 2711, 2717, 0, 0, 0, 0, 0, 0, 0, + 0, 2723, 0, 2729, 2739, 0, 2745, 2751, 0, 0, + }}, + {{ + 2757, 2763, 2769, 2775, 2785, 2795, 2795, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2801, 2808, 2815, + 2822, 2829, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + }}, + {{ + 0, 2836, 2839, 2842, 2845, 2848, 2851, 2854, 2857, 2860, 2863, + 2866, 2869, 2872, 2875, 2878, 2881, 2884, 2887, 2890, 2893, 2896, + 2899, 2902, 2905, 2908, 2911, 0, 0, 0, 0, 0, + }}, + {{ + 2914, 2918, 2922, 2926, 2930, 2934, 2938, 2942, 2946, 2950, 2954, + 2958, 2962, 2966, 2970, 2974, 2978, 2982, 2986, 2990, 2994, 2998, + 3002, 3006, 3010, 3014, 3018, 3022, 3026, 3030, 3034, 3038, + }}, + {{ + 3042, 3046, 3050, 3054, 3058, 3062, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, + 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, + 46, 48, 50, 52, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, + 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, + }}, + {{ + 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, + 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, + 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, + }}, + {{ + 50, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 6, 8, + }}, + {{ + 0, 0, 14, 0, 0, 20, 22, 0, 0, 28, 30, + 32, 34, 0, 38, 40, 42, 44, 46, 48, 50, 52, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 4, 6, 8, 10, 12, + 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, + }}, + {{ + 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 2, 4, 0, 8, 10, 12, 14, + 0, 0, 20, 22, 24, 26, 28, 30, 32, 34, 0, + 38, 40, 42, 44, 46, 48, 50, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 4, 0, 8, 10, 12, 14, 0, + }}, + {{ + 18, 20, 22, 24, 26, 0, 30, 0, 0, 0, 38, + 40, 42, 44, 46, 48, 50, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, + 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, + }}, + {{ + 42, 44, 46, 48, 50, 52, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 50, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, + }}, + {{ + 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 640, 643, 646, + 649, 652, 655, 658, 661, 598, 664, 667, 54, 670, 673, + 676, 679, 682, 661, 685, 688, 691, 694, 697, 700, + }}, + {{ + 703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 640, 643, 646, 649, 652, 655, 658, 661, 598, + 664, 667, 54, 670, 673, 676, 679, 682, 661, 685, 688, + 691, 694, 697, 700, 703, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 640, 643, 646, 649, + }}, + {{ + 652, 655, 658, 661, 598, 664, 667, 54, 670, 673, 676, + 679, 682, 661, 685, 688, 691, 694, 697, 700, 703, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 685, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 640, 643, 646, 649, 652, 655, 658, 661, 598, 664, + }}, + {{ + 667, 54, 670, 673, 676, 679, 682, 661, 685, 688, 691, + 694, 697, 700, 703, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 685, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 640, 643, 646, 649, 652, 655, + 658, 661, 598, 664, 667, 54, 670, 673, 676, 679, + }}, + {{ + 682, 661, 685, 688, 691, 694, 697, 700, 703, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 0, 0, 0, 0, + }}, +}; + +static const unsigned char nameprep_id11_map_data[] = { + 0, 0, 1, 97, 1, 98, 1, 99, 1, 100, 1, 101, + 1, 102, 1, 103, 1, 104, 1, 105, 1, 106, 1, 107, + 1, 108, 1, 109, 1, 110, 1, 111, 1, 112, 1, 113, + 1, 114, 1, 115, 1, 116, 1, 117, 1, 118, 1, 119, + 1, 120, 1, 121, 1, 122, 2, 188, 3, 1, 224, 1, + 225, 1, 226, 1, 227, 1, 228, 1, 229, 1, 230, 1, + 231, 1, 232, 1, 233, 1, 234, 1, 235, 1, 236, 1, + 237, 1, 238, 1, 239, 1, 240, 1, 241, 1, 242, 1, + 243, 1, 244, 1, 245, 1, 246, 1, 248, 1, 249, 1, + 250, 1, 251, 1, 252, 1, 253, 1, 254, 5, 115, 0, + 0, 0, 115, 2, 1, 1, 2, 3, 1, 2, 5, 1, + 2, 7, 1, 2, 9, 1, 2, 11, 1, 2, 13, 1, + 2, 15, 1, 2, 17, 1, 2, 19, 1, 2, 21, 1, + 2, 23, 1, 2, 25, 1, 2, 27, 1, 2, 29, 1, + 2, 31, 1, 2, 33, 1, 2, 35, 1, 2, 37, 1, + 2, 39, 1, 2, 41, 1, 2, 43, 1, 2, 45, 1, + 2, 47, 1, 6, 105, 0, 0, 0, 7, 3, 2, 51, + 1, 2, 53, 1, 2, 55, 1, 2, 58, 1, 2, 60, + 1, 2, 62, 1, 2, 64, 1, 2, 66, 1, 2, 68, + 1, 2, 70, 1, 2, 72, 1, 5, 188, 2, 0, 0, + 110, 2, 75, 1, 2, 77, 1, 2, 79, 1, 2, 81, + 1, 2, 83, 1, 2, 85, 1, 2, 87, 1, 2, 89, + 1, 2, 91, 1, 2, 93, 1, 2, 95, 1, 2, 97, + 1, 2, 99, 1, 2, 101, 1, 2, 103, 1, 2, 105, + 1, 2, 107, 1, 2, 109, 1, 2, 111, 1, 2, 113, + 1, 2, 115, 1, 2, 117, 1, 2, 119, 1, 1, 255, + 2, 122, 1, 2, 124, 1, 2, 126, 1, 2, 83, 2, + 2, 131, 1, 2, 133, 1, 2, 84, 2, 2, 136, 1, + 2, 86, 2, 2, 87, 2, 2, 140, 1, 2, 221, 1, + 2, 89, 2, 2, 91, 2, 2, 146, 1, 2, 96, 2, + 2, 99, 2, 2, 105, 2, 2, 104, 2, 2, 153, 1, + 2, 111, 2, 2, 114, 2, 2, 117, 2, 2, 161, 1, + 2, 163, 1, 2, 165, 1, 2, 128, 2, 2, 168, 1, + 2, 131, 2, 2, 173, 1, 2, 136, 2, 2, 176, 1, + 2, 138, 2, 2, 139, 2, 2, 180, 1, 2, 182, 1, + 2, 146, 2, 2, 185, 1, 2, 189, 1, 2, 198, 1, + 2, 201, 1, 2, 204, 1, 2, 206, 1, 2, 208, 1, + 2, 210, 1, 2, 212, 1, 2, 214, 1, 2, 216, 1, + 2, 218, 1, 2, 220, 1, 2, 223, 1, 2, 225, 1, + 2, 227, 1, 2, 229, 1, 2, 231, 1, 2, 233, 1, + 2, 235, 1, 2, 237, 1, 2, 239, 1, 6, 106, 0, + 0, 0, 12, 3, 2, 243, 1, 2, 245, 1, 2, 149, + 1, 2, 191, 1, 2, 249, 1, 2, 251, 1, 2, 253, + 1, 2, 255, 1, 2, 1, 2, 2, 3, 2, 2, 5, + 2, 2, 7, 2, 2, 9, 2, 2, 11, 2, 2, 13, + 2, 2, 15, 2, 2, 17, 2, 2, 19, 2, 2, 21, + 2, 2, 23, 2, 2, 25, 2, 2, 27, 2, 2, 29, + 2, 2, 31, 2, 2, 158, 1, 2, 35, 2, 2, 37, + 2, 2, 39, 2, 2, 41, 2, 2, 43, 2, 2, 45, + 2, 2, 47, 2, 2, 49, 2, 2, 51, 2, 2, 185, + 3, 6, 32, 0, 0, 0, 185, 3, 2, 172, 3, 2, + 173, 3, 2, 174, 3, 2, 175, 3, 2, 204, 3, 2, + 205, 3, 2, 206, 3, 10, 185, 3, 0, 0, 8, 3, + 0, 0, 1, 3, 2, 177, 3, 2, 178, 3, 2, 179, + 3, 2, 180, 3, 2, 181, 3, 2, 182, 3, 2, 183, + 3, 2, 184, 3, 2, 186, 3, 2, 187, 3, 2, 189, + 3, 2, 190, 3, 2, 191, 3, 2, 192, 3, 2, 193, + 3, 2, 195, 3, 2, 196, 3, 2, 197, 3, 2, 198, + 3, 2, 199, 3, 2, 200, 3, 2, 201, 3, 2, 202, + 3, 2, 203, 3, 10, 197, 3, 0, 0, 8, 3, 0, + 0, 1, 3, 2, 217, 3, 2, 219, 3, 2, 221, 3, + 2, 223, 3, 2, 225, 3, 2, 227, 3, 2, 229, 3, + 2, 231, 3, 2, 233, 3, 2, 235, 3, 2, 237, 3, + 2, 239, 3, 2, 80, 4, 2, 81, 4, 2, 82, 4, + 2, 83, 4, 2, 84, 4, 2, 85, 4, 2, 86, 4, + 2, 87, 4, 2, 88, 4, 2, 89, 4, 2, 90, 4, + 2, 91, 4, 2, 92, 4, 2, 93, 4, 2, 94, 4, + 2, 95, 4, 2, 48, 4, 2, 49, 4, 2, 50, 4, + 2, 51, 4, 2, 52, 4, 2, 53, 4, 2, 54, 4, + 2, 55, 4, 2, 56, 4, 2, 57, 4, 2, 58, 4, + 2, 59, 4, 2, 60, 4, 2, 61, 4, 2, 62, 4, + 2, 63, 4, 2, 64, 4, 2, 65, 4, 2, 66, 4, + 2, 67, 4, 2, 68, 4, 2, 69, 4, 2, 70, 4, + 2, 71, 4, 2, 72, 4, 2, 73, 4, 2, 74, 4, + 2, 75, 4, 2, 76, 4, 2, 77, 4, 2, 78, 4, + 2, 79, 4, 2, 97, 4, 2, 99, 4, 2, 101, 4, + 2, 103, 4, 2, 105, 4, 2, 107, 4, 2, 109, 4, + 2, 111, 4, 2, 113, 4, 2, 115, 4, 2, 117, 4, + 2, 119, 4, 2, 121, 4, 2, 123, 4, 2, 125, 4, + 2, 127, 4, 2, 129, 4, 2, 139, 4, 2, 141, 4, + 2, 143, 4, 2, 145, 4, 2, 147, 4, 2, 149, 4, + 2, 151, 4, 2, 153, 4, 2, 155, 4, 2, 157, 4, + 2, 159, 4, 2, 161, 4, 2, 163, 4, 2, 165, 4, + 2, 167, 4, 2, 169, 4, 2, 171, 4, 2, 173, 4, + 2, 175, 4, 2, 177, 4, 2, 179, 4, 2, 181, 4, + 2, 183, 4, 2, 185, 4, 2, 187, 4, 2, 189, 4, + 2, 191, 4, 2, 194, 4, 2, 196, 4, 2, 198, 4, + 2, 200, 4, 2, 202, 4, 2, 204, 4, 2, 206, 4, + 2, 209, 4, 2, 211, 4, 2, 213, 4, 2, 215, 4, + 2, 217, 4, 2, 219, 4, 2, 221, 4, 2, 223, 4, + 2, 225, 4, 2, 227, 4, 2, 229, 4, 2, 231, 4, + 2, 233, 4, 2, 235, 4, 2, 237, 4, 2, 239, 4, + 2, 241, 4, 2, 243, 4, 2, 245, 4, 2, 249, 4, + 2, 1, 5, 2, 3, 5, 2, 5, 5, 2, 7, 5, + 2, 9, 5, 2, 11, 5, 2, 13, 5, 2, 15, 5, + 2, 97, 5, 2, 98, 5, 2, 99, 5, 2, 100, 5, + 2, 101, 5, 2, 102, 5, 2, 103, 5, 2, 104, 5, + 2, 105, 5, 2, 106, 5, 2, 107, 5, 2, 108, 5, + 2, 109, 5, 2, 110, 5, 2, 111, 5, 2, 112, 5, + 2, 113, 5, 2, 114, 5, 2, 115, 5, 2, 116, 5, + 2, 117, 5, 2, 118, 5, 2, 119, 5, 2, 120, 5, + 2, 121, 5, 2, 122, 5, 2, 123, 5, 2, 124, 5, + 2, 125, 5, 2, 126, 5, 2, 127, 5, 2, 128, 5, + 2, 129, 5, 2, 130, 5, 2, 131, 5, 2, 132, 5, + 2, 133, 5, 2, 134, 5, 6, 101, 5, 0, 0, 130, + 5, 2, 1, 30, 2, 3, 30, 2, 5, 30, 2, 7, + 30, 2, 9, 30, 2, 11, 30, 2, 13, 30, 2, 15, + 30, 2, 17, 30, 2, 19, 30, 2, 21, 30, 2, 23, + 30, 2, 25, 30, 2, 27, 30, 2, 29, 30, 2, 31, + 30, 2, 33, 30, 2, 35, 30, 2, 37, 30, 2, 39, + 30, 2, 41, 30, 2, 43, 30, 2, 45, 30, 2, 47, + 30, 2, 49, 30, 2, 51, 30, 2, 53, 30, 2, 55, + 30, 2, 57, 30, 2, 59, 30, 2, 61, 30, 2, 63, + 30, 2, 65, 30, 2, 67, 30, 2, 69, 30, 2, 71, + 30, 2, 73, 30, 2, 75, 30, 2, 77, 30, 2, 79, + 30, 2, 81, 30, 2, 83, 30, 2, 85, 30, 2, 87, + 30, 2, 89, 30, 2, 91, 30, 2, 93, 30, 2, 95, + 30, 2, 97, 30, 2, 99, 30, 2, 101, 30, 2, 103, + 30, 2, 105, 30, 2, 107, 30, 2, 109, 30, 2, 111, + 30, 2, 113, 30, 2, 115, 30, 2, 117, 30, 2, 119, + 30, 2, 121, 30, 2, 123, 30, 2, 125, 30, 2, 127, + 30, 2, 129, 30, 2, 131, 30, 2, 133, 30, 2, 135, + 30, 2, 137, 30, 2, 139, 30, 2, 141, 30, 2, 143, + 30, 2, 145, 30, 2, 147, 30, 2, 149, 30, 6, 104, + 0, 0, 0, 49, 3, 6, 116, 0, 0, 0, 8, 3, + 6, 119, 0, 0, 0, 10, 3, 6, 121, 0, 0, 0, + 10, 3, 6, 97, 0, 0, 0, 190, 2, 2, 161, 30, + 2, 163, 30, 2, 165, 30, 2, 167, 30, 2, 169, 30, + 2, 171, 30, 2, 173, 30, 2, 175, 30, 2, 177, 30, + 2, 179, 30, 2, 181, 30, 2, 183, 30, 2, 185, 30, + 2, 187, 30, 2, 189, 30, 2, 191, 30, 2, 193, 30, + 2, 195, 30, 2, 197, 30, 2, 199, 30, 2, 201, 30, + 2, 203, 30, 2, 205, 30, 2, 207, 30, 2, 209, 30, + 2, 211, 30, 2, 213, 30, 2, 215, 30, 2, 217, 30, + 2, 219, 30, 2, 221, 30, 2, 223, 30, 2, 225, 30, + 2, 227, 30, 2, 229, 30, 2, 231, 30, 2, 233, 30, + 2, 235, 30, 2, 237, 30, 2, 239, 30, 2, 241, 30, + 2, 243, 30, 2, 245, 30, 2, 247, 30, 2, 249, 30, + 2, 0, 31, 2, 1, 31, 2, 2, 31, 2, 3, 31, + 2, 4, 31, 2, 5, 31, 2, 6, 31, 2, 7, 31, + 2, 16, 31, 2, 17, 31, 2, 18, 31, 2, 19, 31, + 2, 20, 31, 2, 21, 31, 2, 32, 31, 2, 33, 31, + 2, 34, 31, 2, 35, 31, 2, 36, 31, 2, 37, 31, + 2, 38, 31, 2, 39, 31, 2, 48, 31, 2, 49, 31, + 2, 50, 31, 2, 51, 31, 2, 52, 31, 2, 53, 31, + 2, 54, 31, 2, 55, 31, 2, 64, 31, 2, 65, 31, + 2, 66, 31, 2, 67, 31, 2, 68, 31, 2, 69, 31, + 6, 197, 3, 0, 0, 19, 3, 10, 197, 3, 0, 0, + 19, 3, 0, 0, 0, 3, 10, 197, 3, 0, 0, 19, + 3, 0, 0, 1, 3, 10, 197, 3, 0, 0, 19, 3, + 0, 0, 66, 3, 2, 81, 31, 2, 83, 31, 2, 85, + 31, 2, 87, 31, 2, 96, 31, 2, 97, 31, 2, 98, + 31, 2, 99, 31, 2, 100, 31, 2, 101, 31, 2, 102, + 31, 2, 103, 31, 6, 0, 31, 0, 0, 185, 3, 6, + 1, 31, 0, 0, 185, 3, 6, 2, 31, 0, 0, 185, + 3, 6, 3, 31, 0, 0, 185, 3, 6, 4, 31, 0, + 0, 185, 3, 6, 5, 31, 0, 0, 185, 3, 6, 6, + 31, 0, 0, 185, 3, 6, 7, 31, 0, 0, 185, 3, + 6, 32, 31, 0, 0, 185, 3, 6, 33, 31, 0, 0, + 185, 3, 6, 34, 31, 0, 0, 185, 3, 6, 35, 31, + 0, 0, 185, 3, 6, 36, 31, 0, 0, 185, 3, 6, + 37, 31, 0, 0, 185, 3, 6, 38, 31, 0, 0, 185, + 3, 6, 39, 31, 0, 0, 185, 3, 6, 96, 31, 0, + 0, 185, 3, 6, 97, 31, 0, 0, 185, 3, 6, 98, + 31, 0, 0, 185, 3, 6, 99, 31, 0, 0, 185, 3, + 6, 100, 31, 0, 0, 185, 3, 6, 101, 31, 0, 0, + 185, 3, 6, 102, 31, 0, 0, 185, 3, 6, 103, 31, + 0, 0, 185, 3, 6, 112, 31, 0, 0, 185, 3, 6, + 177, 3, 0, 0, 185, 3, 6, 172, 3, 0, 0, 185, + 3, 6, 177, 3, 0, 0, 66, 3, 10, 177, 3, 0, + 0, 66, 3, 0, 0, 185, 3, 2, 176, 31, 2, 177, + 31, 2, 112, 31, 2, 113, 31, 6, 116, 31, 0, 0, + 185, 3, 6, 183, 3, 0, 0, 185, 3, 6, 174, 3, + 0, 0, 185, 3, 6, 183, 3, 0, 0, 66, 3, 10, + 183, 3, 0, 0, 66, 3, 0, 0, 185, 3, 2, 114, + 31, 2, 115, 31, 2, 116, 31, 2, 117, 31, 10, 185, + 3, 0, 0, 8, 3, 0, 0, 0, 3, 6, 185, 3, + 0, 0, 66, 3, 10, 185, 3, 0, 0, 8, 3, 0, + 0, 66, 3, 2, 208, 31, 2, 209, 31, 2, 118, 31, + 2, 119, 31, 10, 197, 3, 0, 0, 8, 3, 0, 0, + 0, 3, 6, 193, 3, 0, 0, 19, 3, 6, 197, 3, + 0, 0, 66, 3, 10, 197, 3, 0, 0, 8, 3, 0, + 0, 66, 3, 2, 224, 31, 2, 225, 31, 2, 122, 31, + 2, 123, 31, 2, 229, 31, 6, 124, 31, 0, 0, 185, + 3, 6, 201, 3, 0, 0, 185, 3, 6, 206, 3, 0, + 0, 185, 3, 6, 201, 3, 0, 0, 66, 3, 10, 201, + 3, 0, 0, 66, 3, 0, 0, 185, 3, 2, 120, 31, + 2, 121, 31, 2, 124, 31, 2, 125, 31, 5, 114, 0, + 0, 0, 115, 5, 176, 0, 0, 0, 99, 5, 176, 0, + 0, 0, 102, 5, 110, 0, 0, 0, 111, 5, 115, 0, + 0, 0, 109, 9, 116, 0, 0, 0, 101, 0, 0, 0, + 108, 5, 116, 0, 0, 0, 109, 2, 112, 33, 2, 113, + 33, 2, 114, 33, 2, 115, 33, 2, 116, 33, 2, 117, + 33, 2, 118, 33, 2, 119, 33, 2, 120, 33, 2, 121, + 33, 2, 122, 33, 2, 123, 33, 2, 124, 33, 2, 125, + 33, 2, 126, 33, 2, 127, 33, 2, 208, 36, 2, 209, + 36, 2, 210, 36, 2, 211, 36, 2, 212, 36, 2, 213, + 36, 2, 214, 36, 2, 215, 36, 2, 216, 36, 2, 217, + 36, 2, 218, 36, 2, 219, 36, 2, 220, 36, 2, 221, + 36, 2, 222, 36, 2, 223, 36, 2, 224, 36, 2, 225, + 36, 2, 226, 36, 2, 227, 36, 2, 228, 36, 2, 229, + 36, 2, 230, 36, 2, 231, 36, 2, 232, 36, 2, 233, + 36, 9, 104, 0, 0, 0, 112, 0, 0, 0, 97, 5, + 97, 0, 0, 0, 117, 5, 111, 0, 0, 0, 118, 5, + 112, 0, 0, 0, 97, 5, 110, 0, 0, 0, 97, 5, + 188, 3, 0, 0, 97, 5, 109, 0, 0, 0, 97, 5, + 107, 0, 0, 0, 97, 5, 107, 0, 0, 0, 98, 5, + 109, 0, 0, 0, 98, 5, 103, 0, 0, 0, 98, 5, + 112, 0, 0, 0, 102, 5, 110, 0, 0, 0, 102, 5, + 188, 3, 0, 0, 102, 5, 104, 0, 0, 0, 122, 9, + 107, 0, 0, 0, 104, 0, 0, 0, 122, 9, 109, 0, + 0, 0, 104, 0, 0, 0, 122, 9, 103, 0, 0, 0, + 104, 0, 0, 0, 122, 9, 116, 0, 0, 0, 104, 0, + 0, 0, 122, 9, 107, 0, 0, 0, 112, 0, 0, 0, + 97, 9, 109, 0, 0, 0, 112, 0, 0, 0, 97, 9, + 103, 0, 0, 0, 112, 0, 0, 0, 97, 5, 112, 0, + 0, 0, 118, 5, 110, 0, 0, 0, 118, 5, 188, 3, + 0, 0, 118, 5, 109, 0, 0, 0, 118, 5, 107, 0, + 0, 0, 118, 5, 112, 0, 0, 0, 119, 5, 110, 0, + 0, 0, 119, 5, 188, 3, 0, 0, 119, 5, 109, 0, + 0, 0, 119, 5, 107, 0, 0, 0, 119, 6, 107, 0, + 0, 0, 201, 3, 6, 109, 0, 0, 0, 201, 3, 5, + 98, 0, 0, 0, 113, 13, 99, 0, 0, 0, 21, 34, + 0, 0, 107, 0, 0, 0, 103, 9, 99, 0, 0, 0, + 111, 0, 0, 0, 46, 5, 100, 0, 0, 0, 98, 5, + 103, 0, 0, 0, 121, 5, 104, 0, 0, 0, 112, 5, + 107, 0, 0, 0, 107, 5, 107, 0, 0, 0, 109, 5, + 112, 0, 0, 0, 104, 9, 112, 0, 0, 0, 112, 0, + 0, 0, 109, 5, 112, 0, 0, 0, 114, 5, 115, 0, + 0, 0, 118, 5, 119, 0, 0, 0, 98, 5, 102, 0, + 0, 0, 102, 5, 102, 0, 0, 0, 105, 5, 102, 0, + 0, 0, 108, 9, 102, 0, 0, 0, 102, 0, 0, 0, + 105, 9, 102, 0, 0, 0, 102, 0, 0, 0, 108, 5, + 115, 0, 0, 0, 116, 6, 116, 5, 0, 0, 118, 5, + 6, 116, 5, 0, 0, 101, 5, 6, 116, 5, 0, 0, + 107, 5, 6, 126, 5, 0, 0, 118, 5, 6, 116, 5, + 0, 0, 109, 5, 2, 65, 255, 2, 66, 255, 2, 67, + 255, 2, 68, 255, 2, 69, 255, 2, 70, 255, 2, 71, + 255, 2, 72, 255, 2, 73, 255, 2, 74, 255, 2, 75, + 255, 2, 76, 255, 2, 77, 255, 2, 78, 255, 2, 79, + 255, 2, 80, 255, 2, 81, 255, 2, 82, 255, 2, 83, + 255, 2, 84, 255, 2, 85, 255, 2, 86, 255, 2, 87, + 255, 2, 88, 255, 2, 89, 255, 2, 90, 255, 3, 40, + 4, 1, 3, 41, 4, 1, 3, 42, 4, 1, 3, 43, + 4, 1, 3, 44, 4, 1, 3, 45, 4, 1, 3, 46, + 4, 1, 3, 47, 4, 1, 3, 48, 4, 1, 3, 49, + 4, 1, 3, 50, 4, 1, 3, 51, 4, 1, 3, 52, + 4, 1, 3, 53, 4, 1, 3, 54, 4, 1, 3, 55, + 4, 1, 3, 56, 4, 1, 3, 57, 4, 1, 3, 58, + 4, 1, 3, 59, 4, 1, 3, 60, 4, 1, 3, 61, + 4, 1, 3, 62, 4, 1, 3, 63, 4, 1, 3, 64, + 4, 1, 3, 65, 4, 1, 3, 66, 4, 1, 3, 67, + 4, 1, 3, 68, 4, 1, 3, 69, 4, 1, 3, 70, + 4, 1, 3, 71, 4, 1, 3, 72, 4, 1, 3, 73, + 4, 1, 3, 74, 4, 1, 3, 75, 4, 1, 3, 76, + 4, 1, 3, 77, 4, 1, +}; + +static const unsigned short nameprep_id11_prohibited_imap[] = { + 68, 196, 196, 324, 196, 196, 196, 452, + 196, 196, 196, 580, 196, 196, 196, 580, + 196, 196, 196, 580, 196, 196, 196, 580, + 196, 196, 196, 580, 196, 196, 196, 580, + 196, 196, 196, 580, 196, 196, 196, 580, + 196, 196, 196, 580, 196, 196, 196, 580, + 196, 196, 196, 580, 196, 196, 196, 580, + 708, 196, 196, 580, 836, 836, 836, 836, + 836, 836, 836, 836, 0, 1, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, + 0, 3, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 11, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, +}; + +static const struct { + unsigned char bm[16]; +} nameprep_id11_prohibited_bitmap[] = { + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 255,255,255,255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, + }}, + {{ + 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 255,199, 0, 0, 0,255, 0, 0, 0, 0, 0,128, 14,252, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 15, + }}, + {{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,255,255, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,254, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 7, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, + }}, + {{ + 2, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255, + }}, +}; + +static const unsigned short nameprep_id11_unassigned_imap[] = { + 68, 196, 324, 452, 580, 708, 708, 836, + 964, 964, 1092, 1220, 708, 708, 708, 1348, + 708, 708, 708, 1348, 708, 708, 708, 1348, + 708, 708, 708, 1348, 708, 708, 708, 1348, + 708, 708, 708, 1348, 708, 708, 708, 1348, + 708, 708, 708, 1348, 708, 708, 708, 1348, + 708, 708, 708, 1348, 708, 708, 708, 1348, + 1476, 708, 708, 1348, 964, 964, 964, 964, + 964, 964, 964, 964, 0, 0, 0, 0, + 1, 2, 3, 4, 0, 5, 6, 7, + 8, 9, 10, 11, 12, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 0, 0, 0, + 36, 37, 38, 39, 40, 41, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 0, 42, 43, 44, 45, 46, 47, 48, + 0, 0, 0, 49, 50, 51, 0, 0, + 52, 53, 54, 55, 0, 0, 0, 0, + 0, 0, 12, 12, 12, 12, 12, 12, + 12, 56, 0, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 66, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 68, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 70, 12, 71, 72, 0, 0, 73, 74, + 75, 76, 35, 77, 12, 12, 12, 12, + 12, 12, 78, 12, 79, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 0, 80, 81, 82, + 12, 12, 12, 12, 83, 84, 85, 0, + 0, 86, 0, 87, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 89, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 0, 0, 0, 0, + 90, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 88, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 88, 91, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, +}; + +static const struct { + unsigned char bm[16]; +} nameprep_id11_unassigned_bitmap[] = { + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 2, 0,240,255,255,255, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0,128,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0,207,187, + }}, + {{ + 15, 40, 0, 0, 4, 0, 0, 0, 0,128, 0, 0, 0, 0,128,255, + }}, + {{ + 128, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0, 0,192,252, + }}, + {{ + 0, 0,255,255,255,255, 1, 0, 0, 0,128, 1, 1, 0, 0, 0, + }}, + {{ + 0,249, 1, 0, 4, 0, 0, 4,224,255, 0, 0, 0,248,224,255, + }}, + {{ + 255,239,255,119, 1, 0, 0,248, 0, 0,192,255, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0,128, + }}, + {{ + 0, 64, 0, 0, 0,224, 0, 0, 0,248,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0,252,255,255,255,255,255,255,255,255,255, + }}, + {{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 17, 0, 0, 0, 0, 0, 0, 12, 0,192,224, 0, 0, 0,254,255, + }}, + {{ + 17, 96, 6, 0, 0, 2, 58, 44, 96,198,127, 79, 48, 0, 0,248, + }}, + {{ + 27,120, 6, 0, 0, 2,146, 44,120,198,255,161, 63, 0,224,255, + }}, + {{ + 17, 80, 4, 0, 0, 2, 18, 12, 64,196,254,255, 62, 0,255,255, + }}, + {{ + 17, 96, 6, 0, 0, 2, 50, 12,112,198, 63, 79, 60, 0,254,255, + }}, + {{ + 19, 56,194, 41,231, 56, 64, 60, 56,194,127,255,127, 0,248,255, + }}, + {{ + 17, 32, 2, 0, 0, 2, 16, 60, 32,194,159,255, 60, 0,255,255, + }}, + {{ + 19, 32, 2, 0, 0, 2, 16, 60, 32,194,159,191, 60, 0,255,255, + }}, + {{ + 19, 32, 2, 0, 0, 2, 0, 60, 48,194,127,255, 60, 0,255,255, + }}, + {{ + 19, 0,128, 3, 0, 0, 4,208,128,123,160, 0,255,255,227,255, + }}, + {{ + 1, 0, 0, 0, 0, 0, 0,120, 0, 0, 0,240,255,255,255,255, + }}, + {{ + 105,218, 15, 1, 81, 19, 0,196,160,192, 0,204,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,248, 1, 0, + }}, + {{ + 0,240, 0, 1, 0, 0, 0, 32, 0, 96,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 4, 9, 56,252, 0, 0, 0,252,255,255,255,255, + }}, + {{ + 255,255,255,255, 0, 0, 0, 0,192,255, 0, 0, 0, 0, 0,246, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, + }}, + {{ + 128, 0, 0, 0, 0, 0, 0, 0,128,194,128,194, 0, 0, 0, 0, + }}, + {{ + 128,194, 0, 0, 0,128,194,128,194,128,128, 0, 0,128, 0, 0, + }}, + {{ + 0,128,194,128, 0, 0, 0, 0,128, 0, 0,248, 1, 0, 0,224, + }}, + {{ + 255,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,224,255, + }}, + {{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,255, + }}, + {{ + 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,254,255, + }}, + {{ + 0, 32,224,255, 0, 0,128,255, 0, 0,240,255, 0, 32,242,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,224, 0,252,255,255, + }}, + {{ + 0,128, 0,252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, + }}, + {{ + 0, 0, 0, 0, 0,252,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, + }}, + {{ + 0, 0,192,192, 0, 0, 0, 0,192,192, 0, 85, 0, 0, 0,192, + }}, + {{ + 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 48, 16, 0, 0, 35,128, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,127,240, 3, 12, 0, + }}, + {{ + 0,128,255,255, 0, 0,252,255,255,255, 0, 0, 0,248,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 24, 0,240, 7, 0, 0, 0, 0, 0, + }}, + {{ + 240,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0,128,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0,128,255,255,255, 0,248,255,255, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, + }}, + {{ + 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, + }}, + {{ + 0,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 33, 12, 0, 0, 0, 1, 0, 0, 0, 80,184,128, 1, 0, 0, 0, + }}, + {{ + 0, 0,224, 0, 0, 0, 1,128,255,255, 0, 0, 0,240, 0, 0, + }}, + {{ + 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,255,255,255, 0,240, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0,128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 31, 0, 0, 0, 0,224, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0,128, 0, 0, 0, 0, 0,255,255,255,255,255,255,255, 0, 0, + }}, + {{ + 0, 0, 0,224, 0, 0, 0, 0,240,255, 1, 0, 0, 0, 0,112, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 0, 0, 0, 0, 0,128, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 7, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0, 0, 0,128, + }}, + {{ + 0, 0, 0, 0, 0, 0,192,255,255,255,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0,192,255,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 0,224, 0, 0, 0, 0, 0, 0,128,255,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0,240,255,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0,248,255,255, + }}, + {{ + 128,255, 7, 31, 0, 0,128,160, 36, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0,252,255,255,255, 7, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 3, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0,224, + }}, + {{ + 0, 0,255,255,240,255, 0, 0,128, 1, 8, 0,128,240, 32, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0,128, 3, 3, 3,227,128,128,255, 1, + }}, + {{ + 0, 0, 0,128,240,255, 0, 0, 0,248,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0,192, 0, 0, 0, 0,192,255,255,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,255, + }}, + {{ + 0, 0, 0, 0,128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,255,255,255,255, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 32,155, 33, 0, 20, 18, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 64, 24, 32, 32, 0, 0, 0,132,160, 3, 2, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, + }}, + {{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 63, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,255,255,255,255,255, + }}, + {{ + 0, 0, 0,192,255,255,255,255,255,255,255,255,255,255,255,255, + }}, + {{ + 253,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, +}; + +static const unsigned short nameprep_id11_bidi_imap[] = { + 272, 400, 528, 656, 784, 912, 912, 912, + 912, 1040, 1168, 912, 912, 1296, 912, 1424, + 1552, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1808, 1680, 1680, + 912, 912, 912, 912, 912, 912, 912, 912, + 912, 912, 1936, 1680, 1680, 1680, 1680, 2064, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, + 912, 912, 912, 912, 912, 912, 912, 912, + 912, 912, 912, 912, 912, 912, 912, 2192, + 912, 912, 912, 912, 912, 912, 912, 912, + 912, 912, 912, 912, 912, 912, 912, 2192, + 0, 0, 1, 1, 0, 2, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 5, 6, 4, 4, 7, 8, 9, + 0, 0, 0, 10, 11, 12, 13, 14, + 4, 4, 4, 4, 15, 4, 13, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 29, 30, 31, + 32, 33, 0, 0, 29, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, + 39, 51, 41, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 60, + 61, 64, 65, 60, 66, 67, 68, 69, + 20, 70, 71, 0, 72, 73, 74, 0, + 75, 76, 77, 78, 79, 80, 81, 0, + 4, 82, 83, 0, 0, 4, 84, 85, + 4, 4, 86, 4, 4, 87, 4, 88, + 89, 4, 90, 4, 91, 92, 93, 13, + 92, 4, 94, 95, 0, 4, 4, 96, + 20, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 97, 1, 4, 4, 98, + 99, 100, 101, 102, 4, 103, 104, 105, + 106, 4, 4, 83, 4, 107, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 108, 4, 4, 88, + 109, 4, 110, 111, 4, 112, 113, 114, + 115, 0, 0, 116, 0, 0, 0, 0, + 117, 118, 119, 4, 120, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 121, 4, 122, 123, 0, 0, 0, + 0, 0, 0, 0, 124, 4, 4, 105, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 125, 126, 20, 4, 127, 20, 4, 128, + 129, 130, 4, 4, 13, 83, 0, 6, + 131, 4, 120, 132, 4, 98, 133, 134, + 4, 4, 4, 135, 4, 4, 111, 134, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 14, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 136, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 137, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 120, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 138, 4, 139, 0, 0, 0, 0, + 140, 141, 142, 29, 29, 143, 144, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 29, 145, 146, 29, 147, 29, 148, 149, + 0, 0, 0, 150, 29, 29, 29, 151, + 0, 1, 1, 152, 4, 134, 153, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 134, 154, 139, 0, 0, 0, 0, 0, + 4, 155, 156, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 14, + 4, 157, 4, 158, 159, 160, 111, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 161, 4, 162, 163, 164, 4, + 165, 166, 167, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 168, 4, 4, + 4, 4, 4, 4, 4, 4, 105, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 97, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 111, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 111, +}; + +static const struct { + unsigned char tbl[32]; +} nameprep_id11_bidi_table[] = { + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 0, 2, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + }}, + {{ + 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, + }}, + {{ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, + }}, + {{ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, + }}, + {{ + 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 2, 0, 2, + }}, + {{ + 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 2, 2, + }}, + {{ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, + 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, + }}, + {{ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 0, + }}, + {{ + 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, + 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 0, 2, 0, 2, 2, + }}, + {{ + 0, 0, 0, 2, 2, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 2, 2, + }}, + {{ + 0, 2, 2, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 0, + }}, + {{ + 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, + }}, + {{ + 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + }}, + {{ + 0, 2, 2, 0, 2, 0, 0, 2, 2, 0, 2, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 0, 2, 2, 2, 0, 2, 0, 2, 0, 0, 2, 2, 0, 2, 2, 2, 2, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + }}, + {{ + 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, + }}, + {{ + 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, + 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, + }}, + {{ + 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, + 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, + }}, + {{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 0, 2, 0, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, + }}, + {{ + 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, + 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + }}, + {{ + 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, + }}, + {{ + 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 2, 2, 2, 0, 2, 2, + 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, + }}, + {{ + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, + }}, + {{ + 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, + }}, + {{ + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, + }}, + {{ + 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }}, + {{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + }}, + {{ + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, + 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }}, + {{ + 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, + }}, + {{ + 0, 0, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, + }}, + {{ + 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, + }}, + {{ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, + }}, + {{ + 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, + {{ + 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }}, +}; + +static const unsigned char nameprep_id11_bidi_data[] = { + idn_biditype_others, + idn_biditype_r_al, + idn_biditype_l, +}; + diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp new file mode 100644 index 000000000..05831139e --- /dev/null +++ b/netwerk/dns/nsDNSService2.cpp @@ -0,0 +1,1071 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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/. */ + +#include "nsDNSService2.h" +#include "nsIDNSRecord.h" +#include "nsIDNSListener.h" +#include "nsICancelable.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIServiceManager.h" +#include "nsIXPConnect.h" +#include "nsProxyRelease.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nsAutoPtr.h" +#include "nsNetCID.h" +#include "nsError.h" +#include "nsDNSPrefetch.h" +#include "nsThreadUtils.h" +#include "nsIProtocolProxyService.h" +#include "prsystem.h" +#include "prnetdb.h" +#include "prmon.h" +#include "prio.h" +#include "plstr.h" +#include "nsIOService.h" +#include "nsCharSeparatedTokenizer.h" +#include "nsNetAddr.h" +#include "nsProxyRelease.h" +#include "nsIObserverService.h" +#include "nsINetworkLinkService.h" + +#include "mozilla/Attributes.h" +#include "mozilla/net/NeckoCommon.h" +#include "mozilla/net/ChildDNSService.h" +#include "mozilla/net/DNSListenerProxy.h" +#include "mozilla/Services.h" + +using namespace mozilla; +using namespace mozilla::net; + +static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries"; +static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration"; +static const char kPrefDnsCacheGrace[] = "network.dnsCacheExpirationGracePeriod"; +static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains"; +static const char kPrefDisableIPv6[] = "network.dns.disableIPv6"; +static const char kPrefDisablePrefetch[] = "network.dns.disablePrefetch"; +static const char kPrefBlockDotOnion[] = "network.dns.blockDotOnion"; +static const char kPrefDnsLocalDomains[] = "network.dns.localDomains"; +static const char kPrefDnsOfflineLocalhost[] = "network.dns.offline-localhost"; +static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution"; + +//----------------------------------------------------------------------------- + +class nsDNSRecord : public nsIDNSRecord +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSRECORD + + explicit nsDNSRecord(nsHostRecord *hostRecord) + : mHostRecord(hostRecord) + , mIter(nullptr) + , mIterGenCnt(-1) + , mDone(false) {} + +private: + virtual ~nsDNSRecord() = default; + + RefPtr mHostRecord; + NetAddrElement *mIter; + int mIterGenCnt; // the generation count of + // mHostRecord->addr_info when we + // start iterating + bool mDone; +}; + +NS_IMPL_ISUPPORTS(nsDNSRecord, nsIDNSRecord) + +NS_IMETHODIMP +nsDNSRecord::GetCanonicalName(nsACString &result) +{ + // this method should only be called if we have a CNAME + NS_ENSURE_TRUE(mHostRecord->flags & nsHostResolver::RES_CANON_NAME, + NS_ERROR_NOT_AVAILABLE); + + // if the record is for an IP address literal, then the canonical + // host name is the IP address literal. + const char *cname; + { + MutexAutoLock lock(mHostRecord->addr_info_lock); + if (mHostRecord->addr_info) + cname = mHostRecord->addr_info->mCanonicalName ? + mHostRecord->addr_info->mCanonicalName : + mHostRecord->addr_info->mHostName; + else + cname = mHostRecord->host; + result.Assign(cname); + } + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) +{ + if (mDone) { + return NS_ERROR_NOT_AVAILABLE; + } + + mHostRecord->addr_info_lock.Lock(); + if (mHostRecord->addr_info) { + if (mIterGenCnt != mHostRecord->addr_info_gencnt) { + // mHostRecord->addr_info has changed, restart the iteration. + mIter = nullptr; + mIterGenCnt = mHostRecord->addr_info_gencnt; + } + + bool startedFresh = !mIter; + + do { + if (!mIter) { + mIter = mHostRecord->addr_info->mAddresses.getFirst(); + } else { + mIter = mIter->getNext(); + } + } + while (mIter && mHostRecord->Blacklisted(&mIter->mAddress)); + + if (!mIter && startedFresh) { + // If everything was blacklisted we want to reset the blacklist (and + // likely relearn it) and return the first address. That is better + // than nothing. + mHostRecord->ResetBlacklist(); + mIter = mHostRecord->addr_info->mAddresses.getFirst(); + } + + if (mIter) { + memcpy(addr, &mIter->mAddress, sizeof(NetAddr)); + } + + mHostRecord->addr_info_lock.Unlock(); + + if (!mIter) { + mDone = true; + return NS_ERROR_NOT_AVAILABLE; + } + } else { + mHostRecord->addr_info_lock.Unlock(); + + if (!mHostRecord->addr) { + // Both mHostRecord->addr_info and mHostRecord->addr are null. + // This can happen if mHostRecord->addr_info expired and the + // attempt to reresolve it failed. + return NS_ERROR_NOT_AVAILABLE; + } + memcpy(addr, mHostRecord->addr, sizeof(NetAddr)); + mDone = true; + } + + // set given port + port = htons(port); + if (addr->raw.family == AF_INET) { + addr->inet.port = port; + } else if (addr->raw.family == AF_INET6) { + addr->inet6.port = port; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::GetAddresses(nsTArray & aAddressArray) +{ + if (mDone) { + return NS_ERROR_NOT_AVAILABLE; + } + + mHostRecord->addr_info_lock.Lock(); + if (mHostRecord->addr_info) { + for (NetAddrElement *iter = mHostRecord->addr_info->mAddresses.getFirst(); + iter; iter = iter->getNext()) { + if (mHostRecord->Blacklisted(&iter->mAddress)) { + continue; + } + NetAddr *addr = aAddressArray.AppendElement(NetAddr()); + memcpy(addr, &iter->mAddress, sizeof(NetAddr)); + if (addr->raw.family == AF_INET) { + addr->inet.port = 0; + } else if (addr->raw.family == AF_INET6) { + addr->inet6.port = 0; + } + } + mHostRecord->addr_info_lock.Unlock(); + } else { + mHostRecord->addr_info_lock.Unlock(); + + if (!mHostRecord->addr) { + return NS_ERROR_NOT_AVAILABLE; + } + NetAddr *addr = aAddressArray.AppendElement(NetAddr()); + memcpy(addr, mHostRecord->addr, sizeof(NetAddr)); + if (addr->raw.family == AF_INET) { + addr->inet.port = 0; + } else if (addr->raw.family == AF_INET6) { + addr->inet6.port = 0; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr * *result) +{ + NetAddr addr; + nsresult rv = GetNextAddr(port, &addr); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = new nsNetAddr(&addr)); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::GetNextAddrAsString(nsACString &result) +{ + NetAddr addr; + nsresult rv = GetNextAddr(0, &addr); + if (NS_FAILED(rv)) return rv; + + char buf[kIPv6CStrBufSize]; + if (NetAddrToString(&addr, buf, sizeof(buf))) { + result.Assign(buf); + return NS_OK; + } + NS_ERROR("NetAddrToString failed unexpectedly"); + return NS_ERROR_FAILURE; // conversion failed for some reason +} + +NS_IMETHODIMP +nsDNSRecord::HasMore(bool *result) +{ + if (mDone) { + *result = false; + return NS_OK; + } + + NetAddrElement *iterCopy = mIter; + int iterGenCntCopy = mIterGenCnt; + + NetAddr addr; + *result = NS_SUCCEEDED(GetNextAddr(0, &addr)); + + mIter = iterCopy; + mIterGenCnt = iterGenCntCopy; + mDone = false; + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::Rewind() +{ + mIter = nullptr; + mIterGenCnt = -1; + mDone = false; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::ReportUnusable(uint16_t aPort) +{ + // right now we don't use the port in the blacklist + + MutexAutoLock lock(mHostRecord->addr_info_lock); + + // Check that we are using a real addr_info (as opposed to a single + // constant address), and that the generation count is valid. Otherwise, + // ignore the report. + + if (mHostRecord->addr_info && + mIterGenCnt == mHostRecord->addr_info_gencnt && + mIter) { + mHostRecord->ReportUnusable(&mIter->mAddress); + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- + +class nsDNSAsyncRequest final : public nsResolveHostCallback + , public nsICancelable +{ + ~nsDNSAsyncRequest() = default; + +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSICANCELABLE + + nsDNSAsyncRequest(nsHostResolver *res, + const nsACString &host, + nsIDNSListener *listener, + uint16_t flags, + uint16_t af, + const nsACString &netInterface) + : mResolver(res) + , mHost(host) + , mListener(listener) + , mFlags(flags) + , mAF(af) + , mNetworkInterface(netInterface) {} + + void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult) override; + // Returns TRUE if the DNS listener arg is the same as the member listener + // Used in Cancellations to remove DNS requests associated with a + // particular hostname and nsIDNSListener + bool EqualsAsyncListener(nsIDNSListener *aListener) override; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override; + + RefPtr mResolver; + nsCString mHost; // hostname we're resolving + nsCOMPtr mListener; + uint16_t mFlags; + uint16_t mAF; + nsCString mNetworkInterface; +}; + +void +nsDNSAsyncRequest::OnLookupComplete(nsHostResolver *resolver, + nsHostRecord *hostRecord, + nsresult status) +{ + // need to have an owning ref when we issue the callback to enable + // the caller to be able to addref/release multiple times without + // destroying the record prematurely. + nsCOMPtr rec; + if (NS_SUCCEEDED(status)) { + NS_ASSERTION(hostRecord, "no host record"); + rec = new nsDNSRecord(hostRecord); + } + + mListener->OnLookupComplete(this, rec, status); + mListener = nullptr; + + // release the reference to ourselves that was added before we were + // handed off to the host resolver. + NS_RELEASE_THIS(); +} + +bool +nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener *aListener) +{ + nsCOMPtr wrapper = do_QueryInterface(mListener); + if (wrapper) { + nsCOMPtr originalListener; + wrapper->GetOriginalListener(getter_AddRefs(originalListener)); + return aListener == originalListener; + } + return (aListener == mListener); +} + +size_t +nsDNSAsyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const +{ + size_t n = mallocSizeOf(this); + + // The following fields aren't measured. + // - mHost, because it's a non-owning pointer + // - mResolver, because it's a non-owning pointer + // - mListener, because it's a non-owning pointer + + return n; +} + +NS_IMPL_ISUPPORTS(nsDNSAsyncRequest, nsICancelable) + +NS_IMETHODIMP +nsDNSAsyncRequest::Cancel(nsresult reason) +{ + NS_ENSURE_ARG(NS_FAILED(reason)); + mResolver->DetachCallback(mHost.get(), mFlags, mAF, mNetworkInterface.get(), + this, reason); + return NS_OK; +} + +//----------------------------------------------------------------------------- + +class nsDNSSyncRequest : public nsResolveHostCallback +{ +public: + explicit nsDNSSyncRequest(PRMonitor *mon) + : mDone(false) + , mStatus(NS_OK) + , mMonitor(mon) {} + virtual ~nsDNSSyncRequest() = default; + + void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult) override; + bool EqualsAsyncListener(nsIDNSListener *aListener) override; + size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override; + + bool mDone; + nsresult mStatus; + RefPtr mHostRecord; + +private: + PRMonitor *mMonitor; +}; + +void +nsDNSSyncRequest::OnLookupComplete(nsHostResolver *resolver, + nsHostRecord *hostRecord, + nsresult status) +{ + // store results, and wake up nsDNSService::Resolve to process results. + PR_EnterMonitor(mMonitor); + mDone = true; + mStatus = status; + mHostRecord = hostRecord; + PR_Notify(mMonitor); + PR_ExitMonitor(mMonitor); +} + +bool +nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener *aListener) +{ + // Sync request: no listener to compare + return false; +} + +size_t +nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const +{ + size_t n = mallocSizeOf(this); + + // The following fields aren't measured. + // - mHostRecord, because it's a non-owning pointer + + // Measurement of the following members may be added later if DMD finds it + // is worthwhile: + // - mMonitor + + return n; +} + +class NotifyDNSResolution: public Runnable +{ +public: + explicit NotifyDNSResolution(const nsACString &aHostname) + : mHostname(aHostname) + { + } + + NS_IMETHOD Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr obs = services::GetObserverService(); + if (obs) { + obs->NotifyObservers(nullptr, + "dns-resolution-request", + NS_ConvertUTF8toUTF16(mHostname).get()); + } + return NS_OK; + } + +private: + nsCString mHostname; +}; + +//----------------------------------------------------------------------------- + +nsDNSService::nsDNSService() + : mLock("nsDNSServer.mLock") + , mDisableIPv6(false) + , mDisablePrefetch(false) + , mFirstTime(true) + , mNotifyResolution(false) + , mOfflineLocalhost(false) +{ +} + +nsDNSService::~nsDNSService() = default; + +NS_IMPL_ISUPPORTS(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver, + nsIMemoryReporter) + +/****************************************************************************** + * nsDNSService impl: + * singleton instance ctor/dtor methods + ******************************************************************************/ +static nsDNSService *gDNSService; + +nsIDNSService* +nsDNSService::GetXPCOMSingleton() +{ + if (IsNeckoChild()) { + return ChildDNSService::GetSingleton(); + } + + return GetSingleton(); +} + +nsDNSService* +nsDNSService::GetSingleton() +{ + NS_ASSERTION(!IsNeckoChild(), "not a parent process"); + + if (gDNSService) { + NS_ADDREF(gDNSService); + return gDNSService; + } + + gDNSService = new nsDNSService(); + if (gDNSService) { + NS_ADDREF(gDNSService); + if (NS_FAILED(gDNSService->Init())) { + NS_RELEASE(gDNSService); + } + } + + return gDNSService; +} + +NS_IMETHODIMP +nsDNSService::Init() +{ + if (mResolver) + return NS_OK; + NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED); + // prefs + uint32_t maxCacheEntries = 400; + uint32_t defaultCacheLifetime = 120; // seconds + uint32_t defaultGracePeriod = 60; // seconds + bool disableIPv6 = false; + bool offlineLocalhost = true; + bool disablePrefetch = false; + bool blockDotOnion = true; + int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT; + bool notifyResolution = false; + + nsAdoptingCString ipv4OnlyDomains; + nsAdoptingCString localDomains; + + // read prefs + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + int32_t val; + if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheEntries, &val))) + maxCacheEntries = (uint32_t) val; + if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheExpiration, &val))) + defaultCacheLifetime = val; + if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheGrace, &val))) + defaultGracePeriod = val; + + // ASSUMPTION: pref branch does not modify out params on failure + prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6); + prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains)); + prefs->GetCharPref(kPrefDnsLocalDomains, getter_Copies(localDomains)); + prefs->GetBoolPref(kPrefDnsOfflineLocalhost, &offlineLocalhost); + prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch); + prefs->GetBoolPref(kPrefBlockDotOnion, &blockDotOnion); + + // If a manual proxy is in use, disable prefetch implicitly + prefs->GetIntPref("network.proxy.type", &proxyType); + prefs->GetBoolPref(kPrefDnsNotifyResolution, ¬ifyResolution); + + if (mFirstTime) { + mFirstTime = false; + + // register as prefs observer + prefs->AddObserver(kPrefDnsCacheEntries, this, false); + prefs->AddObserver(kPrefDnsCacheExpiration, this, false); + prefs->AddObserver(kPrefDnsCacheGrace, this, false); + prefs->AddObserver(kPrefIPv4OnlyDomains, this, false); + prefs->AddObserver(kPrefDnsLocalDomains, this, false); + prefs->AddObserver(kPrefDisableIPv6, this, false); + prefs->AddObserver(kPrefDnsOfflineLocalhost, this, false); + prefs->AddObserver(kPrefDisablePrefetch, this, false); + prefs->AddObserver(kPrefBlockDotOnion, this, false); + prefs->AddObserver(kPrefDnsNotifyResolution, this, false); + + // Monitor these to see if there is a change in proxy configuration + // If a manual proxy is in use, disable prefetch implicitly + prefs->AddObserver("network.proxy.type", this, false); + } + } + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (observerService) { + observerService->AddObserver(this, "last-pb-context-exited", false); + observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false); + } + + nsDNSPrefetch::Initialize(this); + + nsCOMPtr idn = do_GetService(NS_IDNSERVICE_CONTRACTID); + + RefPtr res; + nsresult rv = nsHostResolver::Create(maxCacheEntries, + defaultCacheLifetime, + defaultGracePeriod, + getter_AddRefs(res)); + if (NS_SUCCEEDED(rv)) { + // now, set all of our member variables while holding the lock + MutexAutoLock lock(mLock); + mResolver = res; + mIDN = idn; + mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership + mOfflineLocalhost = offlineLocalhost; + mDisableIPv6 = disableIPv6; + mBlockDotOnion = blockDotOnion; + + // Disable prefetching either by explicit preference or if a manual proxy is configured + mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL); + + mLocalDomains.Clear(); + if (localDomains) { + nsCCharSeparatedTokenizer tokenizer(localDomains, ',', + nsCCharSeparatedTokenizer::SEPARATOR_OPTIONAL); + + while (tokenizer.hasMoreTokens()) { + mLocalDomains.PutEntry(tokenizer.nextToken()); + } + } + mNotifyResolution = notifyResolution; + } + + RegisterWeakMemoryReporter(this); + + return rv; +} + +NS_IMETHODIMP +nsDNSService::Shutdown() +{ + UnregisterWeakMemoryReporter(this); + + RefPtr res; + { + MutexAutoLock lock(mLock); + res = mResolver; + mResolver = nullptr; + } + if (res) { + res->Shutdown(); + } + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (observerService) { + observerService->RemoveObserver(this, NS_NETWORK_LINK_TOPIC); + observerService->RemoveObserver(this, "last-pb-context-exited"); + } + + return NS_OK; +} + +bool +nsDNSService::GetOffline() const +{ + bool offline = false; + nsCOMPtr io = do_GetService(NS_IOSERVICE_CONTRACTID); + if (io) { + io->GetOffline(&offline); + } + return offline; +} + +NS_IMETHODIMP +nsDNSService::GetPrefetchEnabled(bool *outVal) +{ + MutexAutoLock lock(mLock); + *outVal = !mDisablePrefetch; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSService::SetPrefetchEnabled(bool inVal) +{ + MutexAutoLock lock(mLock); + mDisablePrefetch = !inVal; + return NS_OK; +} + +nsresult +nsDNSService::PreprocessHostname(bool aLocalDomain, + const nsACString &aInput, + nsIIDNService *aIDN, + nsACString &aACE) +{ + // Enforce RFC 7686 + if (mBlockDotOnion && + StringEndsWith(aInput, NS_LITERAL_CSTRING(".onion"))) { + return NS_ERROR_UNKNOWN_HOST; + } + + if (aLocalDomain) { + aACE.AssignLiteral("localhost"); + return NS_OK; + } + + if (!aIDN || IsASCII(aInput)) { + aACE = aInput; + return NS_OK; + } + + if (!(IsUTF8(aInput) && NS_SUCCEEDED(aIDN->ConvertUTF8toACE(aInput, aACE)))) { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsDNSService::AsyncResolve(const nsACString &aHostname, + uint32_t flags, + nsIDNSListener *listener, + nsIEventTarget *target_, + nsICancelable **result) +{ + return AsyncResolveExtended(aHostname, flags, EmptyCString(), listener, target_, + result); +} + +NS_IMETHODIMP +nsDNSService::AsyncResolveExtended(const nsACString &aHostname, + uint32_t flags, + const nsACString &aNetworkInterface, + nsIDNSListener *listener, + nsIEventTarget *target_, + nsICancelable **result) +{ + // grab reference to global host resolver and IDN service. beware + // simultaneous shutdown!! + RefPtr res; + nsCOMPtr idn; + nsCOMPtr target = target_; + bool localDomain = false; + { + MutexAutoLock lock(mLock); + + if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) + return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + + res = mResolver; + idn = mIDN; + localDomain = mLocalDomains.GetEntry(aHostname); + } + + if (mNotifyResolution) { + NS_DispatchToMainThread(new NotifyDNSResolution(aHostname)); + } + + if (!res) + return NS_ERROR_OFFLINE; + + nsCString hostname; + nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname); + if (NS_FAILED(rv)) { + return rv; + } + + if (GetOffline() && + (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { + flags |= RESOLVE_OFFLINE; + } + + // make sure JS callers get notification on the main thread + nsCOMPtr wrappedListener = do_QueryInterface(listener); + if (wrappedListener && !target) { + nsCOMPtr mainThread; + NS_GetMainThread(getter_AddRefs(mainThread)); + target = do_QueryInterface(mainThread); + } + + if (target) { + listener = new DNSListenerProxy(listener, target); + } + + uint16_t af = GetAFForLookup(hostname, flags); + + auto *req = + new nsDNSAsyncRequest(res, hostname, listener, flags, af, + aNetworkInterface); + if (!req) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*result = req); + + // addref for resolver; will be released when OnLookupComplete is called. + NS_ADDREF(req); + rv = res->ResolveHost(req->mHost.get(), flags, af, + req->mNetworkInterface.get(), req); + if (NS_FAILED(rv)) { + NS_RELEASE(req); + NS_RELEASE(*result); + } + return rv; +} + +NS_IMETHODIMP +nsDNSService::CancelAsyncResolve(const nsACString &aHostname, + uint32_t aFlags, + nsIDNSListener *aListener, + nsresult aReason) +{ + return CancelAsyncResolveExtended(aHostname, aFlags, EmptyCString(), aListener, + aReason); +} + +NS_IMETHODIMP +nsDNSService::CancelAsyncResolveExtended(const nsACString &aHostname, + uint32_t aFlags, + const nsACString &aNetworkInterface, + nsIDNSListener *aListener, + nsresult aReason) +{ + // grab reference to global host resolver and IDN service. beware + // simultaneous shutdown!! + RefPtr res; + nsCOMPtr idn; + bool localDomain = false; + { + MutexAutoLock lock(mLock); + + if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) + return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + + res = mResolver; + idn = mIDN; + localDomain = mLocalDomains.GetEntry(aHostname); + } + if (!res) + return NS_ERROR_OFFLINE; + + nsCString hostname; + nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname); + if (NS_FAILED(rv)) { + return rv; + } + + uint16_t af = GetAFForLookup(hostname, aFlags); + + res->CancelAsyncRequest(hostname.get(), aFlags, af, + nsPromiseFlatCString(aNetworkInterface).get(), aListener, + aReason); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSService::Resolve(const nsACString &aHostname, + uint32_t flags, + nsIDNSRecord **result) +{ + // grab reference to global host resolver and IDN service. beware + // simultaneous shutdown!! + RefPtr res; + nsCOMPtr idn; + bool localDomain = false; + { + MutexAutoLock lock(mLock); + res = mResolver; + idn = mIDN; + localDomain = mLocalDomains.GetEntry(aHostname); + } + + if (mNotifyResolution) { + NS_DispatchToMainThread(new NotifyDNSResolution(aHostname)); + } + + NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE); + + nsCString hostname; + nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname); + if (NS_FAILED(rv)) { + return rv; + } + + if (GetOffline() && + (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { + flags |= RESOLVE_OFFLINE; + } + + // + // sync resolve: since the host resolver only works asynchronously, we need + // to use a mutex and a condvar to wait for the result. however, since the + // result may be in the resolvers cache, we might get called back recursively + // on the same thread. so, our mutex needs to be re-entrant. in other words, + // we need to use a monitor! ;-) + // + + PRMonitor *mon = PR_NewMonitor(); + if (!mon) + return NS_ERROR_OUT_OF_MEMORY; + + PR_EnterMonitor(mon); + nsDNSSyncRequest syncReq(mon); + + uint16_t af = GetAFForLookup(hostname, flags); + + rv = res->ResolveHost(hostname.get(), flags, af, "", &syncReq); + if (NS_SUCCEEDED(rv)) { + // wait for result + while (!syncReq.mDone) + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + + if (NS_FAILED(syncReq.mStatus)) + rv = syncReq.mStatus; + else { + NS_ASSERTION(syncReq.mHostRecord, "no host record"); + auto *rec = new nsDNSRecord(syncReq.mHostRecord); + if (!rec) + rv = NS_ERROR_OUT_OF_MEMORY; + else + NS_ADDREF(*result = rec); + } + } + + PR_ExitMonitor(mon); + PR_DestroyMonitor(mon); + return rv; +} + +NS_IMETHODIMP +nsDNSService::GetMyHostName(nsACString &result) +{ + char name[100]; + if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) { + result = name; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDNSService::Observe(nsISupports *subject, const char *topic, const char16_t *data) +{ + // We are only getting called if a preference has changed or there's a + // network link event. + NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0 || + strcmp(topic, "last-pb-context-exited") == 0 || + strcmp(topic, NS_NETWORK_LINK_TOPIC) == 0, + "unexpected observe call"); + + bool flushCache = false; + if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) { + nsAutoCString converted = NS_ConvertUTF16toUTF8(data); + if (mResolver && !strcmp(converted.get(), NS_NETWORK_LINK_DATA_CHANGED)) { + flushCache = true; + } + } else if (!strcmp(topic, "last-pb-context-exited")) { + flushCache = true; + } + if (flushCache) { + mResolver->FlushCache(); + return NS_OK; + } + + // + // Shutdown and this function are both only called on the UI thread, so we don't + // have to worry about mResolver being cleared out from under us. + // + // NOTE Shutting down and reinitializing the service like this is obviously + // suboptimal if Observe gets called several times in a row, but we don't + // expect that to be the case. + // + + if (mResolver) { + Shutdown(); + } + Init(); + return NS_OK; +} + +uint16_t +nsDNSService::GetAFForLookup(const nsACString &host, uint32_t flags) +{ + if (mDisableIPv6 || (flags & RESOLVE_DISABLE_IPV6)) + return PR_AF_INET; + + MutexAutoLock lock(mLock); + + uint16_t af = PR_AF_UNSPEC; + + if (!mIPv4OnlyDomains.IsEmpty()) { + const char *domain, *domainEnd, *end; + uint32_t hostLen, domainLen; + + // see if host is in one of the IPv4-only domains + domain = mIPv4OnlyDomains.BeginReading(); + domainEnd = mIPv4OnlyDomains.EndReading(); + + nsACString::const_iterator hostStart; + host.BeginReading(hostStart); + hostLen = host.Length(); + + do { + // skip any whitespace + while (*domain == ' ' || *domain == '\t') + ++domain; + + // find end of this domain in the string + end = strchr(domain, ','); + if (!end) + end = domainEnd; + + // to see if the hostname is in the domain, check if the domain + // matches the end of the hostname. + domainLen = end - domain; + if (domainLen && hostLen >= domainLen) { + const char *hostTail = hostStart.get() + hostLen - domainLen; + if (PL_strncasecmp(domain, hostTail, domainLen) == 0) { + // now, make sure either that the hostname is a direct match or + // that the hostname begins with a dot. + if (hostLen == domainLen || + *hostTail == '.' || *(hostTail - 1) == '.') { + af = PR_AF_INET; + break; + } + } + } + + domain = end + 1; + } while (*end); + } + + if ((af != PR_AF_INET) && (flags & RESOLVE_DISABLE_IPV4)) + af = PR_AF_INET6; + + return af; +} + +NS_IMETHODIMP +nsDNSService::GetDNSCacheEntries(nsTArray *args) +{ + NS_ENSURE_TRUE(mResolver, NS_ERROR_NOT_INITIALIZED); + mResolver->GetDNSCacheEntries(args); + return NS_OK; +} + +size_t +nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const +{ + // Measurement of the following members may be added later if DMD finds it + // is worthwhile: + // - mIDN + // - mLock + + size_t n = mallocSizeOf(this); + n += mResolver ? mResolver->SizeOfIncludingThis(mallocSizeOf) : 0; + n += mIPv4OnlyDomains.SizeOfExcludingThisIfUnshared(mallocSizeOf); + n += mLocalDomains.SizeOfExcludingThis(mallocSizeOf); + return n; +} + +MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf) + +NS_IMETHODIMP +nsDNSService::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) +{ + MOZ_COLLECT_REPORT( + "explicit/network/dns-service", KIND_HEAP, UNITS_BYTES, + SizeOfIncludingThis(DNSServiceMallocSizeOf), + "Memory used for the DNS service."); + + return NS_OK; +} + diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h new file mode 100644 index 000000000..79454b901 --- /dev/null +++ b/netwerk/dns/nsDNSService2.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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 nsDNSService2_h__ +#define nsDNSService2_h__ + +#include "nsPIDNSService.h" +#include "nsIIDNService.h" +#include "nsIMemoryReporter.h" +#include "nsIObserver.h" +#include "nsHostResolver.h" +#include "nsAutoPtr.h" +#include "nsString.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" +#include "mozilla/Mutex.h" +#include "mozilla/Attributes.h" + +class nsDNSService final : public nsPIDNSService + , public nsIObserver + , public nsIMemoryReporter +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSPIDNSSERVICE + NS_DECL_NSIDNSSERVICE + NS_DECL_NSIOBSERVER + NS_DECL_NSIMEMORYREPORTER + + nsDNSService(); + + static nsIDNSService* GetXPCOMSingleton(); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + bool GetOffline() const; + +private: + ~nsDNSService(); + + static nsDNSService* GetSingleton(); + + uint16_t GetAFForLookup(const nsACString &host, uint32_t flags); + + nsresult PreprocessHostname(bool aLocalDomain, + const nsACString &aInput, + nsIIDNService *aIDN, + nsACString &aACE); + + RefPtr mResolver; + nsCOMPtr mIDN; + + // mLock protects access to mResolver and mIPv4OnlyDomains + mozilla::Mutex mLock; + + // 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. + nsAdoptingCString mIPv4OnlyDomains; + bool mDisableIPv6; + bool mDisablePrefetch; + bool mBlockDotOnion; + bool mFirstTime; + bool mNotifyResolution; + bool mOfflineLocalhost; + nsTHashtable mLocalDomains; +}; + +#endif //nsDNSService2_h__ diff --git a/netwerk/dns/nsEffectiveTLDService.cpp b/netwerk/dns/nsEffectiveTLDService.cpp new file mode 100644 index 000000000..4dab2178f --- /dev/null +++ b/netwerk/dns/nsEffectiveTLDService.cpp @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +// This service reads a file of rules describing TLD-like domain names. For a +// complete description of the expected file format and parsing rules, see +// http://wiki.mozilla.org/Gecko:Effective_TLD_Service + +#include "mozilla/ArrayUtils.h" +#include "mozilla/MemoryReporting.h" + +#include "nsEffectiveTLDService.h" +#include "nsIIDNService.h" +#include "nsNetUtil.h" +#include "prnetdb.h" +#include "nsIURI.h" +#include "nsNetCID.h" +#include "nsServiceManagerUtils.h" + +using namespace mozilla; + +NS_IMPL_ISUPPORTS(nsEffectiveTLDService, nsIEffectiveTLDService, + nsIMemoryReporter) + +// ---------------------------------------------------------------------- + +#define ETLD_STR_NUM_1(line) str##line +#define ETLD_STR_NUM(line) ETLD_STR_NUM_1(line) +#define ETLD_ENTRY_OFFSET(name) offsetof(struct etld_string_list, ETLD_STR_NUM(__LINE__)) + +const ETLDEntry ETLDEntry::entries[] = { +#define ETLD_ENTRY(name, ex, wild) { ETLD_ENTRY_OFFSET(name), ex, wild }, +#include "etld_data.inc" +#undef ETLD_ENTRY +}; + +const union ETLDEntry::etld_strings ETLDEntry::strings = { + { +#define ETLD_ENTRY(name, ex, wild) name, +#include "etld_data.inc" +#undef ETLD_ENTRY + } +}; + +/* static */ const ETLDEntry* +ETLDEntry::GetEntry(const char* aDomain) +{ + size_t i; + if (BinarySearchIf(entries, 0, ArrayLength(ETLDEntry::entries), + Cmp(aDomain), &i)) { + return &entries[i]; + } + return nullptr; +} + +// Dummy function to statically ensure that our indices don't overflow +// the storage provided for them. +void +ETLDEntry::FuncForStaticAsserts(void) +{ +#define ETLD_ENTRY(name, ex, wild) \ + static_assert(ETLD_ENTRY_OFFSET(name) < (1 << ETLD_ENTRY_N_INDEX_BITS), \ + "invalid strtab index"); +#include "etld_data.inc" +#undef ETLD_ENTRY +} + +#undef ETLD_ENTRY_OFFSET +#undef ETLD_STR_NUM +#undef ETLD_STR_NUM1 + +// ---------------------------------------------------------------------- + +static nsEffectiveTLDService *gService = nullptr; + +nsEffectiveTLDService::nsEffectiveTLDService() +{ +} + +nsresult +nsEffectiveTLDService::Init() +{ + nsresult rv; + mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + +#ifdef DEBUG + // Sanity-check the eTLD entries. + for (uint32_t i = 0; i < ArrayLength(ETLDEntry::entries); i++) { + const char* domain = ETLDEntry::entries[i].GetEffectiveTLDName(); + nsDependentCString name(domain); + nsAutoCString normalizedName(domain); + MOZ_ASSERT(NS_SUCCEEDED(NormalizeHostname(normalizedName)), + "normalization failure!"); + MOZ_ASSERT(name.Equals(normalizedName), "domain not normalized!"); + + // Domains must be in sorted order for binary search to work. + if (i > 0) { + const char* domain0 = ETLDEntry::entries[i - 1].GetEffectiveTLDName(); + MOZ_ASSERT(strcmp(domain0, domain) < 0, "domains not in sorted order!"); + } + } +#endif + + MOZ_ASSERT(!gService); + gService = this; + RegisterWeakMemoryReporter(this); + + return NS_OK; +} + +nsEffectiveTLDService::~nsEffectiveTLDService() +{ + UnregisterWeakMemoryReporter(this); + gService = nullptr; +} + +MOZ_DEFINE_MALLOC_SIZE_OF(EffectiveTLDServiceMallocSizeOf) + +// The amount of heap memory measured here is tiny. It used to be bigger when +// nsEffectiveTLDService used a separate hash table instead of binary search. +// Nonetheless, we keep this code here in anticipation of bug 1083971 which will +// change ETLDEntries::entries to a heap-allocated array modifiable at runtime. +NS_IMETHODIMP +nsEffectiveTLDService::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) +{ + MOZ_COLLECT_REPORT( + "explicit/network/effective-TLD-service", KIND_HEAP, UNITS_BYTES, + SizeOfIncludingThis(EffectiveTLDServiceMallocSizeOf), + "Memory used by the effective TLD service."); + + return NS_OK; +} + +size_t +nsEffectiveTLDService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) +{ + size_t n = aMallocSizeOf(this); + + // Measurement of the following members may be added later if DMD finds it is + // worthwhile: + // - mIDNService + + return n; +} + +// External function for dealing with URI's correctly. +// Pulls out the host portion from an nsIURI, and calls through to +// GetPublicSuffixFromHost(). +NS_IMETHODIMP +nsEffectiveTLDService::GetPublicSuffix(nsIURI *aURI, + nsACString &aPublicSuffix) +{ + NS_ENSURE_ARG_POINTER(aURI); + + nsCOMPtr innerURI = NS_GetInnermostURI(aURI); + NS_ENSURE_ARG_POINTER(innerURI); + + nsAutoCString host; + nsresult rv = innerURI->GetAsciiHost(host); + if (NS_FAILED(rv)) return rv; + + return GetBaseDomainInternal(host, 0, aPublicSuffix); +} + +// External function for dealing with URI's correctly. +// Pulls out the host portion from an nsIURI, and calls through to +// GetBaseDomainFromHost(). +NS_IMETHODIMP +nsEffectiveTLDService::GetBaseDomain(nsIURI *aURI, + uint32_t aAdditionalParts, + nsACString &aBaseDomain) +{ + NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_TRUE( ((int32_t)aAdditionalParts) >= 0, NS_ERROR_INVALID_ARG); + + nsCOMPtr innerURI = NS_GetInnermostURI(aURI); + NS_ENSURE_ARG_POINTER(innerURI); + + nsAutoCString host; + nsresult rv = innerURI->GetAsciiHost(host); + if (NS_FAILED(rv)) return rv; + + return GetBaseDomainInternal(host, aAdditionalParts + 1, aBaseDomain); +} + +// External function for dealing with a host string directly: finds the public +// suffix (e.g. co.uk) for the given hostname. See GetBaseDomainInternal(). +NS_IMETHODIMP +nsEffectiveTLDService::GetPublicSuffixFromHost(const nsACString &aHostname, + nsACString &aPublicSuffix) +{ + // Create a mutable copy of the hostname and normalize it to ACE. + // This will fail if the hostname includes invalid characters. + nsAutoCString normHostname(aHostname); + nsresult rv = NormalizeHostname(normHostname); + if (NS_FAILED(rv)) return rv; + + return GetBaseDomainInternal(normHostname, 0, aPublicSuffix); +} + +// External function for dealing with a host string directly: finds the base +// domain (e.g. www.co.uk) for the given hostname and number of subdomain parts +// requested. See GetBaseDomainInternal(). +NS_IMETHODIMP +nsEffectiveTLDService::GetBaseDomainFromHost(const nsACString &aHostname, + uint32_t aAdditionalParts, + nsACString &aBaseDomain) +{ + NS_ENSURE_TRUE( ((int32_t)aAdditionalParts) >= 0, NS_ERROR_INVALID_ARG); + + // Create a mutable copy of the hostname and normalize it to ACE. + // This will fail if the hostname includes invalid characters. + nsAutoCString normHostname(aHostname); + nsresult rv = NormalizeHostname(normHostname); + if (NS_FAILED(rv)) return rv; + + return GetBaseDomainInternal(normHostname, aAdditionalParts + 1, aBaseDomain); +} + +NS_IMETHODIMP +nsEffectiveTLDService::GetNextSubDomain(const nsACString& aHostname, + nsACString& aBaseDomain) +{ + // Create a mutable copy of the hostname and normalize it to ACE. + // This will fail if the hostname includes invalid characters. + nsAutoCString normHostname(aHostname); + nsresult rv = NormalizeHostname(normHostname); + NS_ENSURE_SUCCESS(rv, rv); + + return GetBaseDomainInternal(normHostname, -1, aBaseDomain); +} + +// Finds the base domain for a host, with requested number of additional parts. +// This will fail, generating an error, if the host is an IPv4/IPv6 address, +// if more subdomain parts are requested than are available, or if the hostname +// includes characters that are not valid in a URL. Normalization is performed +// on the host string and the result will be in UTF8. +nsresult +nsEffectiveTLDService::GetBaseDomainInternal(nsCString &aHostname, + int32_t aAdditionalParts, + nsACString &aBaseDomain) +{ + if (aHostname.IsEmpty()) + return NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS; + + // chomp any trailing dot, and keep track of it for later + bool trailingDot = aHostname.Last() == '.'; + if (trailingDot) + aHostname.Truncate(aHostname.Length() - 1); + + // check the edge cases of the host being '.' or having a second trailing '.', + // since subsequent checks won't catch it. + if (aHostname.IsEmpty() || aHostname.Last() == '.') + return NS_ERROR_INVALID_ARG; + + // Check if we're dealing with an IPv4/IPv6 hostname, and return + PRNetAddr addr; + PRStatus result = PR_StringToNetAddr(aHostname.get(), &addr); + if (result == PR_SUCCESS) + return NS_ERROR_HOST_IS_IP_ADDRESS; + + // Walk up the domain tree, most specific to least specific, + // looking for matches at each level. Note that a given level may + // have multiple attributes (e.g. IsWild() and IsNormal()). + const char *prevDomain = nullptr; + const char *currDomain = aHostname.get(); + const char *nextDot = strchr(currDomain, '.'); + const char *end = currDomain + aHostname.Length(); + // Default value of *eTLD is currDomain as set in the while loop below + const char *eTLD = nullptr; + while (true) { + // sanity check the string we're about to look up: it should not begin with + // a '.'; this would mean the hostname began with a '.' or had an + // embedded '..' sequence. + if (*currDomain == '.') + return NS_ERROR_INVALID_ARG; + + // Perform the lookup. + const ETLDEntry* entry = ETLDEntry::GetEntry(currDomain); + if (entry) { + if (entry->IsWild() && prevDomain) { + // wildcard rules imply an eTLD one level inferior to the match. + eTLD = prevDomain; + break; + + } else if (entry->IsNormal() || !nextDot) { + // specific match, or we've hit the top domain level + eTLD = currDomain; + break; + + } else if (entry->IsException()) { + // exception rules imply an eTLD one level superior to the match. + eTLD = nextDot + 1; + break; + } + } + + if (!nextDot) { + // we've hit the top domain level; use it by default. + eTLD = currDomain; + break; + } + + prevDomain = currDomain; + currDomain = nextDot + 1; + nextDot = strchr(currDomain, '.'); + } + + const char *begin, *iter; + if (aAdditionalParts < 0) { + NS_ASSERTION(aAdditionalParts == -1, + "aAdditionalParts can't be negative and different from -1"); + + for (iter = aHostname.get(); iter != eTLD && *iter != '.'; iter++); + + if (iter != eTLD) { + iter++; + } + if (iter != eTLD) { + aAdditionalParts = 0; + } + } else { + // count off the number of requested domains. + begin = aHostname.get(); + iter = eTLD; + + while (true) { + if (iter == begin) + break; + + if (*(--iter) == '.' && aAdditionalParts-- == 0) { + ++iter; + ++aAdditionalParts; + break; + } + } + } + + if (aAdditionalParts != 0) + return NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS; + + aBaseDomain = Substring(iter, end); + // add on the trailing dot, if applicable + if (trailingDot) + aBaseDomain.Append('.'); + + return NS_OK; +} + +// Normalizes the given hostname, component by component. ASCII/ACE +// components are lower-cased, and UTF-8 components are normalized per +// RFC 3454 and converted to ACE. +nsresult +nsEffectiveTLDService::NormalizeHostname(nsCString &aHostname) +{ + if (!IsASCII(aHostname)) { + nsresult rv = mIDNService->ConvertUTF8toACE(aHostname, aHostname); + if (NS_FAILED(rv)) + return rv; + } + + ToLowerCase(aHostname); + return NS_OK; +} diff --git a/netwerk/dns/nsEffectiveTLDService.h b/netwerk/dns/nsEffectiveTLDService.h new file mode 100644 index 000000000..92e7abe05 --- /dev/null +++ b/netwerk/dns/nsEffectiveTLDService.h @@ -0,0 +1,98 @@ +//* -*- Mode: C++; tab-width: 2; 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 EffectiveTLDService_h +#define EffectiveTLDService_h + +#include "nsIEffectiveTLDService.h" + +#include "nsIMemoryReporter.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "mozilla/Attributes.h" +#include "mozilla/BinarySearch.h" +#include "mozilla/MemoryReporting.h" + +class nsIIDNService; + +// struct for static data generated from effective_tld_names.dat +struct ETLDEntry { + friend class nsEffectiveTLDService; + +public: + bool IsNormal() const { return wild || !exception; } + bool IsException() const { return exception; } + bool IsWild() const { return wild; } + + const char* GetEffectiveTLDName() const + { + return strings.strtab + strtab_index; + } + + static const ETLDEntry* GetEntry(const char* aDomain); + + static const size_t ETLD_ENTRY_N_INDEX_BITS = 30; + + // These fields must be public to allow static construction. + uint32_t strtab_index : ETLD_ENTRY_N_INDEX_BITS; + uint32_t exception : 1; + uint32_t wild : 1; + +private: + struct Cmp { + int operator()(const ETLDEntry aEntry) const + { + return strcmp(mName, aEntry.GetEffectiveTLDName()); + } + explicit Cmp(const char* aName) : mName(aName) {} + const char* mName; + }; + +#define ETLD_STR_NUM_1(line) str##line +#define ETLD_STR_NUM(line) ETLD_STR_NUM_1(line) + struct etld_string_list { +#define ETLD_ENTRY(name, ex, wild) char ETLD_STR_NUM(__LINE__)[sizeof(name)]; +#include "etld_data.inc" +#undef ETLD_ENTRY + }; + + // This static string table is all the eTLD domain names packed together. + static const union etld_strings { + struct etld_string_list list; + char strtab[1]; + } strings; + + // This is the static entries table. Each entry has an index into the string + // table. The entries are in sorted order so that binary search can be used. + static const ETLDEntry entries[]; + + void FuncForStaticAsserts(void); +#undef ETLD_STR_NUM +#undef ETLD_STR_NUM1 +}; + +class nsEffectiveTLDService final + : public nsIEffectiveTLDService + , public nsIMemoryReporter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIEFFECTIVETLDSERVICE + NS_DECL_NSIMEMORYREPORTER + + nsEffectiveTLDService(); + nsresult Init(); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); + +private: + nsresult GetBaseDomainInternal(nsCString &aHostname, int32_t aAdditionalParts, nsACString &aBaseDomain); + nsresult NormalizeHostname(nsCString &aHostname); + ~nsEffectiveTLDService(); + + nsCOMPtr mIDNService; +}; + +#endif // EffectiveTLDService_h diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp new file mode 100644 index 000000000..f2e26cadd --- /dev/null +++ b/netwerk/dns/nsHostResolver.cpp @@ -0,0 +1,1579 @@ +/* vim:set ts=4 sw=4 sts=4 et cin: */ +/* 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/. */ + +#if defined(HAVE_RES_NINIT) +#include +#include +#include +#include +#include +#define RES_RETRY_ON_FAILURE +#endif + +#include +#include +#include "nsHostResolver.h" +#include "nsError.h" +#include "nsISupportsBase.h" +#include "nsISupportsUtils.h" +#include "nsAutoPtr.h" +#include "nsPrintfCString.h" +#include "prthread.h" +#include "prerror.h" +#include "prtime.h" +#include "mozilla/Logging.h" +#include "PLDHashTable.h" +#include "plstr.h" +#include "nsURLHelper.h" +#include "nsThreadUtils.h" +#include "GetAddrInfo.h" + +#include "mozilla/HashFunctions.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/Telemetry.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/Preferences.h" + +using namespace mozilla; +using namespace mozilla::net; + +// None of our implementations expose a TTL for negative responses, so we use a +// constant always. +static const unsigned int NEGATIVE_RECORD_LIFETIME = 60; + +//---------------------------------------------------------------------------- + +// Use a persistent thread pool in order to avoid spinning up new threads all the time. +// In particular, thread creation results in a res_init() call from libc which is +// quite expensive. +// +// The pool dynamically grows between 0 and MAX_RESOLVER_THREADS in size. New requests +// go first to an idle thread. If that cannot be found and there are fewer than MAX_RESOLVER_THREADS +// currently in the pool a new thread is created for high priority requests. If +// the new request is at a lower priority a new thread will only be created if +// there are fewer than HighThreadThreshold currently outstanding. If a thread cannot be +// created or an idle thread located for the request it is queued. +// +// When the pool is greater than HighThreadThreshold in size a thread will be destroyed after +// ShortIdleTimeoutSeconds of idle time. Smaller pools use LongIdleTimeoutSeconds for a +// timeout period. + +#define HighThreadThreshold MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY +#define LongIdleTimeoutSeconds 300 // for threads 1 -> HighThreadThreshold +#define ShortIdleTimeoutSeconds 60 // for threads HighThreadThreshold+1 -> MAX_RESOLVER_THREADS + +static_assert(HighThreadThreshold <= MAX_RESOLVER_THREADS, + "High Thread Threshold should be less equal Maximum allowed thread"); + +//---------------------------------------------------------------------------- + +static LazyLogModule gHostResolverLog("nsHostResolver"); +#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) +#define LOG_ENABLED() MOZ_LOG_TEST(gHostResolverLog, mozilla::LogLevel::Debug) + +#define LOG_HOST(host, interface) host, \ + (interface && interface[0] != '\0') ? " on interface " : "", \ + (interface && interface[0] != '\0') ? interface : "" + +//---------------------------------------------------------------------------- + +static inline void +MoveCList(PRCList &from, PRCList &to) +{ + if (!PR_CLIST_IS_EMPTY(&from)) { + to.next = from.next; + to.prev = from.prev; + to.next->prev = &to; + to.prev->next = &to; + PR_INIT_CLIST(&from); + } +} + +//---------------------------------------------------------------------------- + +#if defined(RES_RETRY_ON_FAILURE) + +// this class represents the resolver state for a given thread. if we +// encounter a lookup failure, then we can invoke the Reset method on an +// instance of this class to reset the resolver (in case /etc/resolv.conf +// for example changed). this is mainly an issue on GNU systems since glibc +// only reads in /etc/resolv.conf once per thread. it may be an issue on +// other systems as well. + +class nsResState +{ +public: + nsResState() + // initialize mLastReset to the time when this object + // is created. this means that a reset will not occur + // if a thread is too young. the alternative would be + // to initialize this to the beginning of time, so that + // the first failure would cause a reset, but since the + // thread would have just started up, it likely would + // already have current /etc/resolv.conf info. + : mLastReset(PR_IntervalNow()) + { + } + + bool Reset() + { + // reset no more than once per second + if (PR_IntervalToSeconds(PR_IntervalNow() - mLastReset) < 1) + return false; + + LOG(("Calling 'res_ninit'.\n")); + + mLastReset = PR_IntervalNow(); + return (res_ninit(&_res) == 0); + } + +private: + PRIntervalTime mLastReset; +}; + +#endif // RES_RETRY_ON_FAILURE + +//---------------------------------------------------------------------------- + +static inline bool +IsHighPriority(uint16_t flags) +{ + return !(flags & (nsHostResolver::RES_PRIORITY_LOW | nsHostResolver::RES_PRIORITY_MEDIUM)); +} + +static inline bool +IsMediumPriority(uint16_t flags) +{ + return flags & nsHostResolver::RES_PRIORITY_MEDIUM; +} + +static inline bool +IsLowPriority(uint16_t flags) +{ + return flags & nsHostResolver::RES_PRIORITY_LOW; +} + +//---------------------------------------------------------------------------- +// this macro filters out any flags that are not used when constructing the +// host key. the significant flags are those that would affect the resulting +// host record (i.e., the flags that are passed down to PR_GetAddrInfoByName). +#define RES_KEY_FLAGS(_f) ((_f) & nsHostResolver::RES_CANON_NAME) + +nsHostRecord::nsHostRecord(const nsHostKey *key) + : addr_info_lock("nsHostRecord.addr_info_lock") + , addr_info_gencnt(0) + , addr_info(nullptr) + , addr(nullptr) + , negative(false) + , resolving(false) + , onQueue(false) + , usingAnyThread(false) + , mDoomed(false) +#if TTL_AVAILABLE + , mGetTtl(false) +#endif + , mBlacklistedCount(0) + , mResolveAgain(false) +{ + host = ((char *) this) + sizeof(nsHostRecord); + memcpy((char *) host, key->host, strlen(key->host) + 1); + flags = key->flags; + af = key->af; + netInterface = host + strlen(key->host) + 1; + memcpy((char *) netInterface, key->netInterface, + strlen(key->netInterface) + 1); + PR_INIT_CLIST(this); + PR_INIT_CLIST(&callbacks); +} + +nsresult +nsHostRecord::Create(const nsHostKey *key, nsHostRecord **result) +{ + size_t hostLen = strlen(key->host) + 1; + size_t netInterfaceLen = strlen(key->netInterface) + 1; + size_t size = hostLen + netInterfaceLen + sizeof(nsHostRecord); + + // Use placement new to create the object with room for the hostname and + // network interface name allocated after it. + void *place = ::operator new(size); + *result = new(place) nsHostRecord(key); + NS_ADDREF(*result); + + return NS_OK; +} + +void +nsHostRecord::SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, unsigned int grace) +{ + mValidStart = now; + mGraceStart = now + TimeDuration::FromSeconds(valid); + mValidEnd = now + TimeDuration::FromSeconds(valid + grace); +} + +void +nsHostRecord::CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecord) +{ + // This is used to copy information from a cache entry to a record. All + // information necessary for HasUsableRecord needs to be copied. + mValidStart = aFromHostRecord->mValidStart; + mValidEnd = aFromHostRecord->mValidEnd; + mGraceStart = aFromHostRecord->mGraceStart; + mDoomed = aFromHostRecord->mDoomed; +} + +nsHostRecord::~nsHostRecord() +{ + Telemetry::Accumulate(Telemetry::DNS_BLACKLIST_COUNT, mBlacklistedCount); + delete addr_info; + delete addr; +} + +bool +nsHostRecord::Blacklisted(NetAddr *aQuery) +{ + // must call locked + LOG(("Checking blacklist for host [%s%s%s], host record [%p].\n", + LOG_HOST(host, netInterface), this)); + + // skip the string conversion for the common case of no blacklist + if (!mBlacklistedItems.Length()) { + return false; + } + + char buf[kIPv6CStrBufSize]; + if (!NetAddrToString(aQuery, buf, sizeof(buf))) { + return false; + } + nsDependentCString strQuery(buf); + + for (uint32_t i = 0; i < mBlacklistedItems.Length(); i++) { + if (mBlacklistedItems.ElementAt(i).Equals(strQuery)) { + LOG(("Address [%s] is blacklisted for host [%s%s%s].\n", buf, + LOG_HOST(host, netInterface))); + return true; + } + } + + return false; +} + +void +nsHostRecord::ReportUnusable(NetAddr *aAddress) +{ + // must call locked + LOG(("Adding address to blacklist for host [%s%s%s], host record [%p].\n", + LOG_HOST(host, netInterface), this)); + + ++mBlacklistedCount; + + if (negative) + mDoomed = true; + + char buf[kIPv6CStrBufSize]; + if (NetAddrToString(aAddress, buf, sizeof(buf))) { + LOG(("Successfully adding address [%s] to blacklist for host " + "[%s%s%s].\n", buf, LOG_HOST(host, netInterface))); + mBlacklistedItems.AppendElement(nsCString(buf)); + } +} + +void +nsHostRecord::ResetBlacklist() +{ + // must call locked + LOG(("Resetting blacklist for host [%s%s%s], host record [%p].\n", + LOG_HOST(host, netInterface), this)); + mBlacklistedItems.Clear(); +} + +nsHostRecord::ExpirationStatus +nsHostRecord::CheckExpiration(const mozilla::TimeStamp& now) const { + if (!mGraceStart.IsNull() && now >= mGraceStart + && !mValidEnd.IsNull() && now < mValidEnd) { + return nsHostRecord::EXP_GRACE; + } else if (!mValidEnd.IsNull() && now < mValidEnd) { + return nsHostRecord::EXP_VALID; + } + + return nsHostRecord::EXP_EXPIRED; +} + + +bool +nsHostRecord::HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags) const +{ + if (mDoomed) { + return false; + } + + // don't use cached negative results for high priority queries. + if (negative && IsHighPriority(queryFlags)) { + return false; + } + + if (CheckExpiration(now) == EXP_EXPIRED) { + return false; + } + + return addr_info || addr || negative; +} + +static size_t +SizeOfResolveHostCallbackListExcludingHead(const PRCList *head, + MallocSizeOf mallocSizeOf) +{ + size_t n = 0; + PRCList *curr = head->next; + while (curr != head) { + nsResolveHostCallback *callback = + static_cast(curr); + n += callback->SizeOfIncludingThis(mallocSizeOf); + curr = curr->next; + } + return n; +} + +size_t +nsHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const +{ + size_t n = mallocSizeOf(this); + + // The |host| field (inherited from nsHostKey) actually points to extra + // memory that is allocated beyond the end of the nsHostRecord (see + // nsHostRecord::Create()). So it will be included in the + // |mallocSizeOf(this)| call above. + + n += SizeOfResolveHostCallbackListExcludingHead(&callbacks, mallocSizeOf); + n += addr_info ? addr_info->SizeOfIncludingThis(mallocSizeOf) : 0; + n += mallocSizeOf(addr); + + n += mBlacklistedItems.ShallowSizeOfExcludingThis(mallocSizeOf); + for (size_t i = 0; i < mBlacklistedItems.Length(); i++) { + n += mBlacklistedItems[i].SizeOfExcludingThisIfUnshared(mallocSizeOf); + } + return n; +} + +nsHostRecord::DnsPriority +nsHostRecord::GetPriority(uint16_t aFlags) +{ + if (IsHighPriority(aFlags)){ + return nsHostRecord::DNS_PRIORITY_HIGH; + } else if (IsMediumPriority(aFlags)) { + return nsHostRecord::DNS_PRIORITY_MEDIUM; + } + + return nsHostRecord::DNS_PRIORITY_LOW; +} + +// Returns true if the entry can be removed, or false if it should be left. +// Sets mResolveAgain true for entries being resolved right now. +bool +nsHostRecord::RemoveOrRefresh() +{ + if (resolving) { + if (!onQueue) { + // The request has been passed to the OS resolver. The resultant DNS + // record should be considered stale and not trusted; set a flag to + // ensure it is called again. + mResolveAgain = true; + } + // if Onqueue is true, the host entry is already added to the cache + // but is still pending to get resolved: just leave it in hash. + return false; + } + // Already resolved; not in a pending state; remove from cache. + return true; +} + +//---------------------------------------------------------------------------- + +struct nsHostDBEnt : PLDHashEntryHdr +{ + nsHostRecord *rec; +}; + +static PLDHashNumber +HostDB_HashKey(const void *key) +{ + const nsHostKey *hk = static_cast(key); + return AddToHash(HashString(hk->host), RES_KEY_FLAGS(hk->flags), hk->af, + HashString(hk->netInterface)); +} + +static bool +HostDB_MatchEntry(const PLDHashEntryHdr *entry, + const void *key) +{ + const nsHostDBEnt *he = static_cast(entry); + const nsHostKey *hk = static_cast(key); + + return !strcmp(he->rec->host ? he->rec->host : "", + hk->host ? hk->host : "") && + RES_KEY_FLAGS (he->rec->flags) == RES_KEY_FLAGS(hk->flags) && + he->rec->af == hk->af && + !strcmp(he->rec->netInterface, hk->netInterface); +} + +static void +HostDB_MoveEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + static_cast(to)->rec = + static_cast(from)->rec; +} + +static void +HostDB_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + nsHostDBEnt *he = static_cast(entry); + MOZ_ASSERT(he, "nsHostDBEnt is null!"); + + nsHostRecord *hr = he->rec; + MOZ_ASSERT(hr, "nsHostDBEnt has null host record!"); + + LOG(("Clearing cache db entry for host [%s%s%s].\n", + LOG_HOST(hr->host, hr->netInterface))); +#if defined(DEBUG) + { + MutexAutoLock lock(hr->addr_info_lock); + if (!hr->addr_info) { + LOG(("No address info for host [%s%s%s].\n", + LOG_HOST(hr->host, hr->netInterface))); + } else { + if (!hr->mValidEnd.IsNull()) { + TimeDuration diff = hr->mValidEnd - TimeStamp::NowLoRes(); + LOG(("Record for host [%s%s%s] expires in %f seconds.\n", + LOG_HOST(hr->host, hr->netInterface), + diff.ToSeconds())); + } else { + LOG(("Record for host [%s%s%s] not yet valid.\n", + LOG_HOST(hr->host, hr->netInterface))); + } + + NetAddrElement *addrElement = nullptr; + char buf[kIPv6CStrBufSize]; + do { + if (!addrElement) { + addrElement = hr->addr_info->mAddresses.getFirst(); + } else { + addrElement = addrElement->getNext(); + } + + if (addrElement) { + NetAddrToString(&addrElement->mAddress, buf, sizeof(buf)); + LOG((" [%s]\n", buf)); + } + } + while (addrElement); + } + } +#endif + NS_RELEASE(he->rec); +} + +static void +HostDB_InitEntry(PLDHashEntryHdr *entry, + const void *key) +{ + nsHostDBEnt *he = static_cast(entry); + nsHostRecord::Create(static_cast(key), &he->rec); +} + +static const PLDHashTableOps gHostDB_ops = +{ + HostDB_HashKey, + HostDB_MatchEntry, + HostDB_MoveEntry, + HostDB_ClearEntry, + HostDB_InitEntry, +}; + +//---------------------------------------------------------------------------- + +#if TTL_AVAILABLE +static const char kPrefGetTtl[] = "network.dns.get-ttl"; +static bool sGetTtlEnabled = false; + +static void DnsPrefChanged(const char* aPref, void* aClosure) +{ + MOZ_ASSERT(NS_IsMainThread(), + "Should be getting pref changed notification on main thread!"); + + if (strcmp(aPref, kPrefGetTtl) != 0) { + LOG(("DnsPrefChanged ignoring pref \"%s\"", aPref)); + return; + } + + auto self = static_cast(aClosure); + MOZ_ASSERT(self); + + sGetTtlEnabled = Preferences::GetBool(kPrefGetTtl); +} +#endif + +nsHostResolver::nsHostResolver(uint32_t maxCacheEntries, + uint32_t defaultCacheEntryLifetime, + uint32_t defaultGracePeriod) + : mMaxCacheEntries(maxCacheEntries) + , mDefaultCacheLifetime(defaultCacheEntryLifetime) + , mDefaultGracePeriod(defaultGracePeriod) + , mLock("nsHostResolver.mLock") + , mIdleThreadCV(mLock, "nsHostResolver.mIdleThreadCV") + , mDB(&gHostDB_ops, sizeof(nsHostDBEnt), 0) + , mEvictionQSize(0) + , mShutdown(true) + , mNumIdleThreads(0) + , mThreadCount(0) + , mActiveAnyThreadCount(0) + , mPendingCount(0) +{ + mCreationTime = PR_Now(); + PR_INIT_CLIST(&mHighQ); + PR_INIT_CLIST(&mMediumQ); + PR_INIT_CLIST(&mLowQ); + PR_INIT_CLIST(&mEvictionQ); + + mLongIdleTimeout = PR_SecondsToInterval(LongIdleTimeoutSeconds); + mShortIdleTimeout = PR_SecondsToInterval(ShortIdleTimeoutSeconds); +} + +nsHostResolver::~nsHostResolver() = default; + +nsresult +nsHostResolver::Init() +{ + if (NS_FAILED(GetAddrInfoInit())) { + return NS_ERROR_FAILURE; + } + + mShutdown = false; + +#if TTL_AVAILABLE + // The preferences probably haven't been loaded from the disk yet, so we + // need to register a callback that will set up the experiment once they + // are. We also need to explicitly set a value for the props otherwise the + // callback won't be called. + { + DebugOnly rv = Preferences::RegisterCallbackAndCall( + &DnsPrefChanged, kPrefGetTtl, this); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "Could not register DNS TTL pref callback."); + } +#endif + +#if defined(HAVE_RES_NINIT) + // We want to make sure the system is using the correct resolver settings, + // so we force it to reload those settings whenever we startup a subsequent + // nsHostResolver instance. We assume that there is no reason to do this + // for the first nsHostResolver instance since that is usually created + // during application startup. + static int initCount = 0; + if (initCount++ > 0) { + LOG(("Calling 'res_ninit'.\n")); + res_ninit(&_res); + } +#endif + return NS_OK; +} + +void +nsHostResolver::ClearPendingQueue(PRCList *aPendingQ) +{ + // loop through pending queue, erroring out pending lookups. + if (!PR_CLIST_IS_EMPTY(aPendingQ)) { + PRCList *node = aPendingQ->next; + while (node != aPendingQ) { + nsHostRecord *rec = static_cast(node); + node = node->next; + OnLookupComplete(rec, NS_ERROR_ABORT, nullptr); + } + } +} + +// +// FlushCache() is what we call when the network has changed. We must not +// trust names that were resolved before this change. They may resolve +// differently now. +// +// This function removes all existing resolved host entries from the hash. +// Names that are in the pending queues can be left there. Entries in the +// cache that have 'Resolve' set true but not 'onQueue' are being resolved +// right now, so we need to mark them to get re-resolved on completion! + +void +nsHostResolver::FlushCache() +{ + MutexAutoLock lock(mLock); + mEvictionQSize = 0; + + // Clear the evictionQ and remove all its corresponding entries from + // the cache first + if (!PR_CLIST_IS_EMPTY(&mEvictionQ)) { + PRCList *node = mEvictionQ.next; + while (node != &mEvictionQ) { + nsHostRecord *rec = static_cast(node); + node = node->next; + PR_REMOVE_AND_INIT_LINK(rec); + mDB.Remove((nsHostKey *) rec); + NS_RELEASE(rec); + } + } + + // Refresh the cache entries that are resolving RIGHT now, remove the rest. + for (auto iter = mDB.Iter(); !iter.Done(); iter.Next()) { + auto entry = static_cast(iter.Get()); + // Try to remove the record, or mark it for refresh. + if (entry->rec->RemoveOrRefresh()) { + PR_REMOVE_LINK(entry->rec); + iter.Remove(); + } + } +} + +void +nsHostResolver::Shutdown() +{ + LOG(("Shutting down host resolver.\n")); + +#if TTL_AVAILABLE + { + DebugOnly rv = Preferences::UnregisterCallback( + &DnsPrefChanged, kPrefGetTtl, this); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "Could not unregister DNS TTL pref callback."); + } +#endif + + PRCList pendingQHigh, pendingQMed, pendingQLow, evictionQ; + PR_INIT_CLIST(&pendingQHigh); + PR_INIT_CLIST(&pendingQMed); + PR_INIT_CLIST(&pendingQLow); + PR_INIT_CLIST(&evictionQ); + + { + MutexAutoLock lock(mLock); + + mShutdown = true; + + MoveCList(mHighQ, pendingQHigh); + MoveCList(mMediumQ, pendingQMed); + MoveCList(mLowQ, pendingQLow); + MoveCList(mEvictionQ, evictionQ); + mEvictionQSize = 0; + mPendingCount = 0; + + if (mNumIdleThreads) + mIdleThreadCV.NotifyAll(); + + // empty host database + mDB.Clear(); + } + + ClearPendingQueue(&pendingQHigh); + ClearPendingQueue(&pendingQMed); + ClearPendingQueue(&pendingQLow); + + if (!PR_CLIST_IS_EMPTY(&evictionQ)) { + PRCList *node = evictionQ.next; + while (node != &evictionQ) { + nsHostRecord *rec = static_cast(node); + node = node->next; + NS_RELEASE(rec); + } + } + +#ifdef NS_BUILD_REFCNT_LOGGING + + // Logically join the outstanding worker threads with a timeout. + // Use this approach instead of PR_JoinThread() because that does + // not allow a timeout which may be necessary for a semi-responsive + // shutdown if the thread is blocked on a very slow DNS resolution. + // mThreadCount is read outside of mLock, but the worst case + // scenario for that race is one extra 25ms sleep. + + PRIntervalTime delay = PR_MillisecondsToInterval(25); + PRIntervalTime stopTime = PR_IntervalNow() + PR_SecondsToInterval(20); + while (mThreadCount && PR_IntervalNow() < stopTime) + PR_Sleep(delay); +#endif + + { + mozilla::DebugOnly rv = GetAddrInfoShutdown(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), + "Failed to shutdown GetAddrInfo"); + } +} + +void +nsHostResolver::MoveQueue(nsHostRecord *aRec, PRCList &aDestQ) +{ + NS_ASSERTION(aRec->onQueue, "Moving Host Record Not Currently Queued"); + + PR_REMOVE_LINK(aRec); + PR_APPEND_LINK(aRec, &aDestQ); +} + +nsresult +nsHostResolver::ResolveHost(const char *host, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsResolveHostCallback *callback) +{ + NS_ENSURE_TRUE(host && *host, NS_ERROR_UNEXPECTED); + NS_ENSURE_TRUE(netInterface, NS_ERROR_UNEXPECTED); + + LOG(("Resolving host [%s%s%s]%s.\n", LOG_HOST(host, netInterface), + flags & RES_BYPASS_CACHE ? " - bypassing cache" : "")); + + // ensure that we are working with a valid hostname before proceeding. see + // bug 304904 for details. + if (!net_IsValidHostName(nsDependentCString(host))) + return NS_ERROR_UNKNOWN_HOST; + + // if result is set inside the lock, then we need to issue the + // callback before returning. + RefPtr result; + nsresult status = NS_OK, rv = NS_OK; + { + MutexAutoLock lock(mLock); + + if (mShutdown) + rv = NS_ERROR_NOT_INITIALIZED; + else { + // Used to try to parse to an IP address literal. + PRNetAddr tempAddr; + // Unfortunately, PR_StringToNetAddr does not properly initialize + // the output buffer in the case of IPv6 input. See bug 223145. + memset(&tempAddr, 0, sizeof(PRNetAddr)); + + // check to see if there is already an entry for this |host| + // in the hash table. if so, then check to see if we can't + // just reuse the lookup result. otherwise, if there are + // any pending callbacks, then add to pending callbacks queue, + // and return. otherwise, add ourselves as first pending + // callback, and proceed to do the lookup. + + nsHostKey key = { host, flags, af, netInterface }; + auto he = static_cast(mDB.Add(&key, fallible)); + + // if the record is null, the hash table OOM'd. + if (!he) { + LOG((" Out of memory: no cache entry for host [%s%s%s].\n", + LOG_HOST(host, netInterface))); + rv = NS_ERROR_OUT_OF_MEMORY; + } + // do we have a cached result that we can reuse? + else if (!(flags & RES_BYPASS_CACHE) && + he->rec->HasUsableResult(TimeStamp::NowLoRes(), flags)) { + LOG((" Using cached record for host [%s%s%s].\n", + LOG_HOST(host, netInterface))); + // put reference to host record on stack... + result = he->rec; + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, METHOD_HIT); + + // For entries that are in the grace period + // or all cached negative entries, use the cache but start a new + // lookup in the background + ConditionallyRefreshRecord(he->rec, host); + + if (he->rec->negative) { + LOG((" Negative cache entry for host [%s%s%s].\n", + LOG_HOST(host, netInterface))); + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_NEGATIVE_HIT); + status = NS_ERROR_UNKNOWN_HOST; + } + } + // if the host name is an IP address literal and has been parsed, + // go ahead and use it. + else if (he->rec->addr) { + LOG((" Using cached address for IP Literal [%s].\n", host)); + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_LITERAL); + result = he->rec; + } + // try parsing the host name as an IP address literal to short + // circuit full host resolution. (this is necessary on some + // platforms like Win9x. see bug 219376 for more details.) + else if (PR_StringToNetAddr(host, &tempAddr) == PR_SUCCESS) { + LOG((" Host is IP Literal [%s].\n", host)); + // ok, just copy the result into the host record, and be done + // with it! ;-) + he->rec->addr = new NetAddr(); + PRNetAddrToNetAddr(&tempAddr, he->rec->addr); + // put reference to host record on stack... + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_LITERAL); + result = he->rec; + } + else if (mPendingCount >= MAX_NON_PRIORITY_REQUESTS && + !IsHighPriority(flags) && + !he->rec->resolving) { + LOG((" Lookup queue full: dropping %s priority request for " + "host [%s%s%s].\n", + IsMediumPriority(flags) ? "medium" : "low", + LOG_HOST(host, netInterface))); + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_OVERFLOW); + // This is a lower priority request and we are swamped, so refuse it. + rv = NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + } + else if (flags & RES_OFFLINE) { + LOG((" Offline request for host [%s%s%s]; ignoring.\n", + LOG_HOST(host, netInterface))); + rv = NS_ERROR_OFFLINE; + } + + // If this is an IPV4 or IPV6 specific request, check if there is + // an AF_UNSPEC entry we can use. Otherwise, hit the resolver... + else if (!he->rec->resolving) { + if (!(flags & RES_BYPASS_CACHE) && + ((af == PR_AF_INET) || (af == PR_AF_INET6))) { + // First, search for an entry with AF_UNSPEC + const nsHostKey unspecKey = { host, flags, PR_AF_UNSPEC, + netInterface }; + auto unspecHe = + static_cast(mDB.Search(&unspecKey)); + NS_ASSERTION(!unspecHe || + (unspecHe && unspecHe->rec), + "Valid host entries should contain a record"); + TimeStamp now = TimeStamp::NowLoRes(); + if (unspecHe && + unspecHe->rec->HasUsableResult(now, flags)) { + + MOZ_ASSERT(unspecHe->rec->addr_info || unspecHe->rec->negative, + "Entry should be resolved or negative."); + + LOG((" Trying AF_UNSPEC entry for host [%s%s%s] af: %s.\n", + LOG_HOST(host, netInterface), + (af == PR_AF_INET) ? "AF_INET" : "AF_INET6")); + + he->rec->addr_info = nullptr; + if (unspecHe->rec->negative) { + he->rec->negative = unspecHe->rec->negative; + he->rec->CopyExpirationTimesAndFlagsFrom(unspecHe->rec); + } else if (unspecHe->rec->addr_info) { + // Search for any valid address in the AF_UNSPEC entry + // in the cache (not blacklisted and from the right + // family). + NetAddrElement *addrIter = + unspecHe->rec->addr_info->mAddresses.getFirst(); + while (addrIter) { + if ((af == addrIter->mAddress.inet.family) && + !unspecHe->rec->Blacklisted(&addrIter->mAddress)) { + if (!he->rec->addr_info) { + he->rec->addr_info = new AddrInfo( + unspecHe->rec->addr_info->mHostName, + unspecHe->rec->addr_info->mCanonicalName); + he->rec->CopyExpirationTimesAndFlagsFrom(unspecHe->rec); + } + he->rec->addr_info->AddAddress( + new NetAddrElement(*addrIter)); + } + addrIter = addrIter->getNext(); + } + } + // Now check if we have a new record. + if (he->rec->HasUsableResult(now, flags)) { + result = he->rec; + if (he->rec->negative) { + status = NS_ERROR_UNKNOWN_HOST; + } + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_HIT); + ConditionallyRefreshRecord(he->rec, host); + } + // For AF_INET6, a new lookup means another AF_UNSPEC + // lookup. We have already iterated through the + // AF_UNSPEC addresses, so we mark this record as + // negative. + else if (af == PR_AF_INET6) { + LOG((" No AF_INET6 in AF_UNSPEC entry: " + "host [%s%s%s] unknown host.", + LOG_HOST(host, netInterface))); + result = he->rec; + he->rec->negative = true; + status = NS_ERROR_UNKNOWN_HOST; + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_NEGATIVE_HIT); + } + } + } + // If no valid address was found in the cache or this is an + // AF_UNSPEC request, then start a new lookup. + if (!result) { + LOG((" No usable address in cache for host [%s%s%s].", + LOG_HOST(host, netInterface))); + + // Add callback to the list of pending callbacks. + PR_APPEND_LINK(callback, &he->rec->callbacks); + he->rec->flags = flags; + rv = IssueLookup(he->rec); + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_NETWORK_FIRST); + if (NS_FAILED(rv)) { + PR_REMOVE_AND_INIT_LINK(callback); + } + else { + LOG((" DNS lookup for host [%s%s%s] blocking " + "pending 'getaddrinfo' query: callback [%p]", + LOG_HOST(host, netInterface), callback)); + } + } + } + else { + LOG((" Host [%s%s%s] is being resolved. Appending callback " + "[%p].", LOG_HOST(host, netInterface), callback)); + + PR_APPEND_LINK(callback, &he->rec->callbacks); + if (he->rec->onQueue) { + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_NETWORK_SHARED); + + // Consider the case where we are on a pending queue of + // lower priority than the request is being made at. + // In that case we should upgrade to the higher queue. + + if (IsHighPriority(flags) && + !IsHighPriority(he->rec->flags)) { + // Move from (low|med) to high. + MoveQueue(he->rec, mHighQ); + he->rec->flags = flags; + ConditionallyCreateThread(he->rec); + } else if (IsMediumPriority(flags) && + IsLowPriority(he->rec->flags)) { + // Move from low to med. + MoveQueue(he->rec, mMediumQ); + he->rec->flags = flags; + mIdleThreadCV.Notify(); + } + } + } + } + } + if (result) { + callback->OnLookupComplete(this, result, status); + } + + return rv; +} + +void +nsHostResolver::DetachCallback(const char *host, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsResolveHostCallback *callback, + nsresult status) +{ + RefPtr rec; + { + MutexAutoLock lock(mLock); + + nsHostKey key = { host, flags, af, netInterface }; + auto he = static_cast(mDB.Search(&key)); + if (he) { + // walk list looking for |callback|... we cannot assume + // that it will be there! + PRCList *node = he->rec->callbacks.next; + while (node != &he->rec->callbacks) { + if (static_cast(node) == callback) { + PR_REMOVE_LINK(callback); + rec = he->rec; + break; + } + node = node->next; + } + } + } + + // complete callback with the given status code; this would only be done if + // the record was in the process of being resolved. + if (rec) + callback->OnLookupComplete(this, rec, status); +} + +nsresult +nsHostResolver::ConditionallyCreateThread(nsHostRecord *rec) +{ + if (mNumIdleThreads) { + // wake up idle thread to process this lookup + mIdleThreadCV.Notify(); + } + else if ((mThreadCount < HighThreadThreshold) || + (IsHighPriority(rec->flags) && mThreadCount < MAX_RESOLVER_THREADS)) { + // dispatch new worker thread + NS_ADDREF_THIS(); // owning reference passed to thread + + mThreadCount++; + PRThread *thr = PR_CreateThread(PR_SYSTEM_THREAD, + ThreadFunc, + this, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (!thr) { + mThreadCount--; + NS_RELEASE_THIS(); + return NS_ERROR_OUT_OF_MEMORY; + } + } + else { + LOG((" Unable to find a thread for looking up host [%s%s%s].\n", + LOG_HOST(rec->host, rec->netInterface))); + } + return NS_OK; +} + +nsresult +nsHostResolver::IssueLookup(nsHostRecord *rec) +{ + nsresult rv = NS_OK; + NS_ASSERTION(!rec->resolving, "record is already being resolved"); + + // Add rec to one of the pending queues, possibly removing it from mEvictionQ. + // If rec is on mEvictionQ, then we can just move the owning + // reference over to the new active queue. + if (rec->next == rec) + NS_ADDREF(rec); + else { + PR_REMOVE_LINK(rec); + mEvictionQSize--; + } + + switch (nsHostRecord::GetPriority(rec->flags)) { + case nsHostRecord::DNS_PRIORITY_HIGH: + PR_APPEND_LINK(rec, &mHighQ); + break; + + case nsHostRecord::DNS_PRIORITY_MEDIUM: + PR_APPEND_LINK(rec, &mMediumQ); + break; + + case nsHostRecord::DNS_PRIORITY_LOW: + PR_APPEND_LINK(rec, &mLowQ); + break; + } + mPendingCount++; + + rec->resolving = true; + rec->onQueue = true; + + rv = ConditionallyCreateThread(rec); + + LOG ((" DNS thread counters: total=%d any-live=%d idle=%d pending=%d\n", + static_cast(mThreadCount), + static_cast(mActiveAnyThreadCount), + static_cast(mNumIdleThreads), + static_cast(mPendingCount))); + + return rv; +} + +nsresult +nsHostResolver::ConditionallyRefreshRecord(nsHostRecord *rec, const char *host) +{ + if ((rec->CheckExpiration(TimeStamp::NowLoRes()) != nsHostRecord::EXP_VALID + || rec->negative) && !rec->resolving) { + LOG((" Using %s cache entry for host [%s] but starting async renewal.", + rec->negative ? "negative" :"positive", host)); + IssueLookup(rec); + + if (!rec->negative) { + // negative entries are constantly being refreshed, only + // track positive grace period induced renewals + Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, + METHOD_RENEWAL); + } + } + return NS_OK; +} + +void +nsHostResolver::DeQueue(PRCList &aQ, nsHostRecord **aResult) +{ + *aResult = static_cast(aQ.next); + PR_REMOVE_AND_INIT_LINK(*aResult); + mPendingCount--; + (*aResult)->onQueue = false; +} + +bool +nsHostResolver::GetHostToLookup(nsHostRecord **result) +{ + bool timedOut = false; + PRIntervalTime epoch, now, timeout; + + MutexAutoLock lock(mLock); + + timeout = (mNumIdleThreads >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout; + epoch = PR_IntervalNow(); + + while (!mShutdown) { + // remove next record from Q; hand over owning reference. Check high, then med, then low + +#if TTL_AVAILABLE + #define SET_GET_TTL(var, val) \ + (var)->mGetTtl = sGetTtlEnabled && (val) +#else + #define SET_GET_TTL(var, val) +#endif + + if (!PR_CLIST_IS_EMPTY(&mHighQ)) { + DeQueue (mHighQ, result); + SET_GET_TTL(*result, false); + return true; + } + + if (mActiveAnyThreadCount < HighThreadThreshold) { + if (!PR_CLIST_IS_EMPTY(&mMediumQ)) { + DeQueue (mMediumQ, result); + mActiveAnyThreadCount++; + (*result)->usingAnyThread = true; + SET_GET_TTL(*result, true); + return true; + } + + if (!PR_CLIST_IS_EMPTY(&mLowQ)) { + DeQueue (mLowQ, result); + mActiveAnyThreadCount++; + (*result)->usingAnyThread = true; + SET_GET_TTL(*result, true); + return true; + } + } + + // Determining timeout is racy, so allow one cycle through checking the queues + // before exiting. + if (timedOut) + break; + + // wait for one or more of the following to occur: + // (1) the pending queue has a host record to process + // (2) the shutdown flag has been set + // (3) the thread has been idle for too long + + mNumIdleThreads++; + mIdleThreadCV.Wait(timeout); + mNumIdleThreads--; + + now = PR_IntervalNow(); + + if ((PRIntervalTime)(now - epoch) >= timeout) + timedOut = true; + else { + // It is possible that PR_WaitCondVar() was interrupted and returned early, + // in which case we will loop back and re-enter it. In that case we want to + // do so with the new timeout reduced to reflect time already spent waiting. + timeout -= (PRIntervalTime)(now - epoch); + epoch = now; + } + } + + // tell thread to exit... + return false; +} + +void +nsHostResolver::PrepareRecordExpiration(nsHostRecord* rec) const +{ + MOZ_ASSERT(((bool)rec->addr_info) != rec->negative); + if (!rec->addr_info) { + rec->SetExpiration(TimeStamp::NowLoRes(), + NEGATIVE_RECORD_LIFETIME, 0); + LOG(("Caching host [%s%s%s] negative record for %u seconds.\n", + LOG_HOST(rec->host, rec->netInterface), + NEGATIVE_RECORD_LIFETIME)); + return; + } + + unsigned int lifetime = mDefaultCacheLifetime; + unsigned int grace = mDefaultGracePeriod; +#if TTL_AVAILABLE + unsigned int ttl = mDefaultCacheLifetime; + if (sGetTtlEnabled) { + MutexAutoLock lock(rec->addr_info_lock); + if (rec->addr_info && rec->addr_info->ttl != AddrInfo::NO_TTL_DATA) { + ttl = rec->addr_info->ttl; + } + lifetime = ttl; + grace = 0; + } +#endif + + rec->SetExpiration(TimeStamp::NowLoRes(), lifetime, grace); + LOG(("Caching host [%s%s%s] record for %u seconds (grace %d).", + LOG_HOST(rec->host, rec->netInterface), lifetime, grace)); +} + +static bool +different_rrset(AddrInfo *rrset1, AddrInfo *rrset2) +{ + if (!rrset1 || !rrset2) { + return true; + } + + LOG(("different_rrset %s\n", rrset1->mHostName)); + nsTArray orderedSet1; + nsTArray orderedSet2; + + for (NetAddrElement *element = rrset1->mAddresses.getFirst(); + element; element = element->getNext()) { + if (LOG_ENABLED()) { + char buf[128]; + NetAddrToString(&element->mAddress, buf, 128); + LOG(("different_rrset add to set 1 %s\n", buf)); + } + orderedSet1.InsertElementAt(orderedSet1.Length(), element->mAddress); + } + + for (NetAddrElement *element = rrset2->mAddresses.getFirst(); + element; element = element->getNext()) { + if (LOG_ENABLED()) { + char buf[128]; + NetAddrToString(&element->mAddress, buf, 128); + LOG(("different_rrset add to set 2 %s\n", buf)); + } + orderedSet2.InsertElementAt(orderedSet2.Length(), element->mAddress); + } + + if (orderedSet1.Length() != orderedSet2.Length()) { + LOG(("different_rrset true due to length change\n")); + return true; + } + orderedSet1.Sort(); + orderedSet2.Sort(); + + for (uint32_t i = 0; i < orderedSet1.Length(); ++i) { + if (!(orderedSet1[i] == orderedSet2[i])) { + LOG(("different_rrset true due to content change\n")); + return true; + } + } + LOG(("different_rrset false\n")); + return false; +} + +// +// OnLookupComplete() checks if the resolving should be redone and if so it +// returns LOOKUP_RESOLVEAGAIN, but only if 'status' is not NS_ERROR_ABORT. +// takes ownership of AddrInfo parameter +nsHostResolver::LookupStatus +nsHostResolver::OnLookupComplete(nsHostRecord* rec, nsresult status, AddrInfo* newRRSet) +{ + // get the list of pending callbacks for this lookup, and notify + // them that the lookup is complete. + PRCList cbs; + PR_INIT_CLIST(&cbs); + { + MutexAutoLock lock(mLock); + + if (rec->mResolveAgain && (status != NS_ERROR_ABORT)) { + LOG(("nsHostResolver record %p resolve again due to flushcache\n", rec)); + rec->mResolveAgain = false; + delete newRRSet; + return LOOKUP_RESOLVEAGAIN; + } + + // grab list of callbacks to notify + MoveCList(rec->callbacks, cbs); + + // update record fields. We might have a rec->addr_info already if a + // previous lookup result expired and we're reresolving it.. + AddrInfo *old_addr_info; + { + MutexAutoLock lock(rec->addr_info_lock); + if (different_rrset(rec->addr_info, newRRSet)) { + LOG(("nsHostResolver record %p new gencnt\n", rec)); + old_addr_info = rec->addr_info; + rec->addr_info = newRRSet; + rec->addr_info_gencnt++; + } else { + if (rec->addr_info && newRRSet) { + rec->addr_info->ttl = newRRSet->ttl; + } + old_addr_info = newRRSet; + } + } + delete old_addr_info; + + rec->negative = !rec->addr_info; + PrepareRecordExpiration(rec); + rec->resolving = false; + + if (rec->usingAnyThread) { + mActiveAnyThreadCount--; + rec->usingAnyThread = false; + } + + if (!mShutdown) { + // add to mEvictionQ + PR_APPEND_LINK(rec, &mEvictionQ); + NS_ADDREF(rec); + if (mEvictionQSize < mMaxCacheEntries) + mEvictionQSize++; + else { + // remove first element on mEvictionQ + nsHostRecord *head = + static_cast(PR_LIST_HEAD(&mEvictionQ)); + PR_REMOVE_AND_INIT_LINK(head); + mDB.Remove((nsHostKey *) head); + + if (!head->negative) { + // record the age of the entry upon eviction. + TimeDuration age = TimeStamp::NowLoRes() - head->mValidStart; + Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE, + static_cast(age.ToSeconds() / 60)); + } + + // release reference to rec owned by mEvictionQ + NS_RELEASE(head); + } +#if TTL_AVAILABLE + if (!rec->mGetTtl && !rec->resolving && sGetTtlEnabled) { + LOG(("Issuing second async lookup for TTL for host [%s%s%s].", + LOG_HOST(rec->host, rec->netInterface))); + rec->flags = + (rec->flags & ~RES_PRIORITY_MEDIUM) | RES_PRIORITY_LOW; + DebugOnly rv = IssueLookup(rec); + NS_WARNING_ASSERTION( + NS_SUCCEEDED(rv), + "Could not issue second async lookup for TTL."); + } +#endif + } + } + + if (!PR_CLIST_IS_EMPTY(&cbs)) { + PRCList *node = cbs.next; + while (node != &cbs) { + nsResolveHostCallback *callback = + static_cast(node); + node = node->next; + callback->OnLookupComplete(this, rec, status); + // NOTE: callback must not be dereferenced after this point!! + } + } + + NS_RELEASE(rec); + + return LOOKUP_OK; +} + +void +nsHostResolver::CancelAsyncRequest(const char *host, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsIDNSListener *aListener, + nsresult status) + +{ + MutexAutoLock lock(mLock); + + // Lookup the host record associated with host, flags & address family + nsHostKey key = { host, flags, af, netInterface }; + auto he = static_cast(mDB.Search(&key)); + if (he) { + nsHostRecord* recPtr = nullptr; + PRCList *node = he->rec->callbacks.next; + // Remove the first nsDNSAsyncRequest callback which matches the + // supplied listener object + while (node != &he->rec->callbacks) { + nsResolveHostCallback *callback + = static_cast(node); + if (callback && (callback->EqualsAsyncListener(aListener))) { + // Remove from the list of callbacks + PR_REMOVE_LINK(callback); + recPtr = he->rec; + callback->OnLookupComplete(this, recPtr, status); + break; + } + node = node->next; + } + + // If there are no more callbacks, remove the hash table entry + if (recPtr && PR_CLIST_IS_EMPTY(&recPtr->callbacks)) { + mDB.Remove((nsHostKey *)recPtr); + // If record is on a Queue, remove it and then deref it + if (recPtr->next != recPtr) { + PR_REMOVE_LINK(recPtr); + NS_RELEASE(recPtr); + } + } + } +} + +size_t +nsHostResolver::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const +{ + MutexAutoLock lock(mLock); + + size_t n = mallocSizeOf(this); + + n += mDB.ShallowSizeOfExcludingThis(mallocSizeOf); + for (auto iter = mDB.ConstIter(); !iter.Done(); iter.Next()) { + auto entry = static_cast(iter.Get()); + n += entry->rec->SizeOfIncludingThis(mallocSizeOf); + } + + // The following fields aren't measured. + // - mHighQ, mMediumQ, mLowQ, mEvictionQ, because they just point to + // nsHostRecords that also pointed to by entries |mDB|, and measured when + // |mDB| is measured. + + return n; +} + +void +nsHostResolver::ThreadFunc(void *arg) +{ + LOG(("DNS lookup thread - starting execution.\n")); + + static nsThreadPoolNaming naming; + naming.SetThreadPoolName(NS_LITERAL_CSTRING("DNS Resolver")); + +#if defined(RES_RETRY_ON_FAILURE) + nsResState rs; +#endif + nsHostResolver *resolver = (nsHostResolver *)arg; + nsHostRecord *rec = nullptr; + AddrInfo *ai = nullptr; + + while (rec || resolver->GetHostToLookup(&rec)) { + LOG(("DNS lookup thread - Calling getaddrinfo for host [%s%s%s].\n", + LOG_HOST(rec->host, rec->netInterface))); + + TimeStamp startTime = TimeStamp::Now(); +#if TTL_AVAILABLE + bool getTtl = rec->mGetTtl; +#else + bool getTtl = false; +#endif + + nsresult status = GetAddrInfo(rec->host, rec->af, rec->flags, rec->netInterface, + &ai, getTtl); +#if defined(RES_RETRY_ON_FAILURE) + if (NS_FAILED(status) && rs.Reset()) { + status = GetAddrInfo(rec->host, rec->af, rec->flags, rec->netInterface, &ai, + getTtl); + } +#endif + + { // obtain lock to check shutdown and manage inter-module telemetry + MutexAutoLock lock(resolver->mLock); + + if (!resolver->mShutdown) { + TimeDuration elapsed = TimeStamp::Now() - startTime; + uint32_t millis = static_cast(elapsed.ToMilliseconds()); + + if (NS_SUCCEEDED(status)) { + Telemetry::ID histogramID; + if (!rec->addr_info_gencnt) { + // Time for initial lookup. + histogramID = Telemetry::DNS_LOOKUP_TIME; + } else if (!getTtl) { + // Time for renewal; categorized by expiration strategy. + histogramID = Telemetry::DNS_RENEWAL_TIME; + } else { + // Time to get TTL; categorized by expiration strategy. + histogramID = Telemetry::DNS_RENEWAL_TIME_FOR_TTL; + } + Telemetry::Accumulate(histogramID, millis); + } else { + Telemetry::Accumulate(Telemetry::DNS_FAILED_LOOKUP_TIME, millis); + } + } + } + + // OnLookupComplete may release "rec", long before we lose it. + LOG(("DNS lookup thread - lookup completed for host [%s%s%s]: %s.\n", + LOG_HOST(rec->host, rec->netInterface), + ai ? "success" : "failure: unknown host")); + + if (LOOKUP_RESOLVEAGAIN == resolver->OnLookupComplete(rec, status, ai)) { + // leave 'rec' assigned and loop to make a renewed host resolve + LOG(("DNS lookup thread - Re-resolving host [%s%s%s].\n", + LOG_HOST(rec->host, rec->netInterface))); + } else { + rec = nullptr; + } + } + resolver->mThreadCount--; + NS_RELEASE(resolver); + LOG(("DNS lookup thread - queue empty, thread finished.\n")); +} + +nsresult +nsHostResolver::Create(uint32_t maxCacheEntries, + uint32_t defaultCacheEntryLifetime, + uint32_t defaultGracePeriod, + nsHostResolver **result) +{ + auto *res = new nsHostResolver(maxCacheEntries, defaultCacheEntryLifetime, + defaultGracePeriod); + NS_ADDREF(res); + + nsresult rv = res->Init(); + if (NS_FAILED(rv)) + NS_RELEASE(res); + + *result = res; + return rv; +} + +void +nsHostResolver::GetDNSCacheEntries(nsTArray *args) +{ + for (auto iter = mDB.Iter(); !iter.Done(); iter.Next()) { + // We don't pay attention to address literals, only resolved domains. + // Also require a host. + auto entry = static_cast(iter.Get()); + nsHostRecord* rec = entry->rec; + MOZ_ASSERT(rec, "rec should never be null here!"); + if (!rec || !rec->addr_info || !rec->host) { + continue; + } + + DNSCacheEntries info; + info.hostname = rec->host; + info.family = rec->af; + info.netInterface = rec->netInterface; + info.expiration = + (int64_t)(rec->mValidEnd - TimeStamp::NowLoRes()).ToSeconds(); + if (info.expiration <= 0) { + // We only need valid DNS cache entries + continue; + } + + { + MutexAutoLock lock(rec->addr_info_lock); + + NetAddr *addr = nullptr; + NetAddrElement *addrElement = rec->addr_info->mAddresses.getFirst(); + if (addrElement) { + addr = &addrElement->mAddress; + } + while (addr) { + char buf[kIPv6CStrBufSize]; + if (NetAddrToString(addr, buf, sizeof(buf))) { + info.hostaddr.AppendElement(buf); + } + addr = nullptr; + addrElement = addrElement->getNext(); + if (addrElement) { + addr = &addrElement->mAddress; + } + } + } + + args->AppendElement(info); + } +} diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h new file mode 100644 index 000000000..4c37ff0d3 --- /dev/null +++ b/netwerk/dns/nsHostResolver.h @@ -0,0 +1,372 @@ +/* vim:set ts=4 sw=4 sts=4 et cin: */ +/* 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 nsHostResolver_h__ +#define nsHostResolver_h__ + +#include "nscore.h" +#include "prclist.h" +#include "prnetdb.h" +#include "PLDHashTable.h" +#include "mozilla/CondVar.h" +#include "mozilla/Mutex.h" +#include "nsISupportsImpl.h" +#include "nsIDNSListener.h" +#include "nsIDNSService.h" +#include "nsString.h" +#include "nsTArray.h" +#include "GetAddrInfo.h" +#include "mozilla/net/DNS.h" +#include "mozilla/net/DashboardTypes.h" +#include "mozilla/TimeStamp.h" + +class nsHostResolver; +class nsHostRecord; +class nsResolveHostCallback; + +#define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3 +#define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5 +#define MAX_NON_PRIORITY_REQUESTS 150 + +#define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \ + MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY) + +struct nsHostKey +{ + const char *host; + uint16_t flags; + uint16_t af; + const char *netInterface; +}; + +/** + * nsHostRecord - ref counted object type stored in host resolver cache. + */ +class nsHostRecord : public PRCList, public nsHostKey +{ + typedef mozilla::Mutex Mutex; + +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostRecord) + + /* instantiates a new host record */ + static nsresult Create(const nsHostKey *key, nsHostRecord **record); + + /* a fully resolved host record has either a non-null |addr_info| or |addr| + * field. if |addr_info| is null, it implies that the |host| is an IP + * address literal. in which case, |addr| contains the parsed address. + * otherwise, if |addr_info| is non-null, then it contains one or many + * IP addresses corresponding to the given host name. if both |addr_info| + * 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. + */ + + /* the lock protects |addr_info| and |addr_info_gencnt| because they + * are mutable and accessed by the resolver worker thread and the + * nsDNSService2 class. |addr| doesn't change after it has been + * assigned a value. only the resolver worker thread modifies + * nsHostRecord (and only in nsHostResolver::OnLookupComplete); + * the other threads just read it. therefore the resolver worker + * thread doesn't need to lock when reading |addr_info|. + */ + Mutex addr_info_lock; + int addr_info_gencnt; /* generation count of |addr_info| */ + mozilla::net::AddrInfo *addr_info; + mozilla::net::NetAddr *addr; + bool negative; /* True if this record is a cache of a failed lookup. + Negative cache entries are valid just like any other + (though never for more than 60 seconds), but a use + of that negative entry forces an asynchronous refresh. */ + + enum ExpirationStatus { + EXP_VALID, + EXP_GRACE, + EXP_EXPIRED, + }; + + ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const; + + // When the record began being valid. Used mainly for bookkeeping. + mozilla::TimeStamp mValidStart; + + // When the record is no longer valid (it's time of expiration) + mozilla::TimeStamp mValidEnd; + + // When the record enters its grace period. This must be before mValidEnd. + // If a record is in its grace period (and not expired), it will be used + // but a request to refresh it will be made. + mozilla::TimeStamp mGraceStart; + + // Convenience function for setting the timestamps above (mValidStart, + // mValidEnd, and mGraceStart). valid and grace are durations in seconds. + void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, + unsigned int grace); + void CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecord); + + // Checks if the record is usable (not expired and has a value) + bool HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags = 0) const; + + // hold addr_info_lock when calling the blacklist functions + bool Blacklisted(mozilla::net::NetAddr *query); + void ResetBlacklist(); + void ReportUnusable(mozilla::net::NetAddr *addr); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + enum DnsPriority { + DNS_PRIORITY_LOW, + DNS_PRIORITY_MEDIUM, + DNS_PRIORITY_HIGH, + }; + static DnsPriority GetPriority(uint16_t aFlags); + + bool RemoveOrRefresh(); // Mark records currently being resolved as needed + // to resolve again. + +private: + friend class nsHostResolver; + + + PRCList callbacks; /* list of callbacks */ + + bool resolving; /* true if this record is being resolved, which means + * that it is either on the pending queue or owned by + * one of the worker threads. */ + + bool onQueue; /* true if pending and on the queue (not yet given to getaddrinfo())*/ + bool usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */ + bool mDoomed; /* explicitly expired */ + +#if TTL_AVAILABLE + bool mGetTtl; +#endif + + // The number of times ReportUnusable() has been called in the record's + // lifetime. + uint32_t mBlacklistedCount; + + // when the results from this resolve is returned, it is not to be + // trusted, but instead a new resolve must be made! + bool mResolveAgain; + + // a list of addresses associated with this record that have been reported + // as unusable. the list is kept as a set of strings to make it independent + // of gencnt. + nsTArray mBlacklistedItems; + + explicit nsHostRecord(const nsHostKey *key); /* use Create() instead */ + ~nsHostRecord(); +}; + +/** + * ResolveHost callback object. It's PRCList members are used by + * the nsHostResolver and should not be used by anything else. + */ +class NS_NO_VTABLE nsResolveHostCallback : public PRCList +{ +public: + /** + * OnLookupComplete + * + * this function is called to complete a host lookup initiated by + * nsHostResolver::ResolveHost. it may be invoked recursively from + * ResolveHost or on an unspecified background thread. + * + * NOTE: it is the responsibility of the implementor of this method + * to handle the callback in a thread safe manner. + * + * @param resolver + * nsHostResolver object associated with this result + * @param record + * the host record containing the results of the lookup + * @param status + * if successful, |record| contains non-null results + */ + virtual void OnLookupComplete(nsHostResolver *resolver, + nsHostRecord *record, + nsresult status) = 0; + /** + * EqualsAsyncListener + * + * Determines if the listener argument matches the listener member var. + * For subclasses not implementing a member listener, should return false. + * For subclasses having a member listener, the function should check if + * they are the same. Used for cases where a pointer to an object + * implementing nsResolveHostCallback is unknown, but a pointer to + * the original listener is known. + * + * @param aListener + * nsIDNSListener object associated with the original request + */ + virtual bool EqualsAsyncListener(nsIDNSListener *aListener) = 0; + + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0; +}; + +/** + * nsHostResolver - an asynchronous host name resolver. + */ +class nsHostResolver +{ + typedef mozilla::CondVar CondVar; + typedef mozilla::Mutex Mutex; + +public: + /** + * host resolver instances are reference counted. + */ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostResolver) + + /** + * creates an addref'd instance of a nsHostResolver object. + */ + static nsresult Create(uint32_t maxCacheEntries, // zero disables cache + uint32_t defaultCacheEntryLifetime, // seconds + uint32_t defaultGracePeriod, // seconds + nsHostResolver **resolver); + + /** + * puts the resolver in the shutdown state, which will cause any pending + * callbacks to be detached. any future calls to ResolveHost will fail. + */ + void Shutdown(); + + /** + * resolve the given hostname asynchronously. the caller can synthesize + * a synchronous host lookup using a lock and a cvar. as noted above + * the callback will occur re-entrantly from an unspecified thread. the + * host lookup cannot be canceled (cancelation can be layered above this + * by having the callback implementation return without doing anything). + */ + nsresult ResolveHost(const char *hostname, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsResolveHostCallback *callback); + + /** + * removes the specified callback from the nsHostRecord for the given + * hostname, flags, and address family. these parameters should correspond + * to the parameters passed to ResolveHost. this function executes the + * callback if the callback is still pending with the given status. + */ + void DetachCallback(const char *hostname, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsResolveHostCallback *callback, + nsresult status); + + /** + * Cancels an async request associated with the hostname, flags, + * address family and listener. Cancels first callback found which matches + * these criteria. These parameters should correspond to the parameters + * passed to ResolveHost. If this is the last callback associated with the + * host record, it is removed from any request queues it might be on. + */ + void CancelAsyncRequest(const char *host, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsIDNSListener *aListener, + nsresult status); + /** + * values for the flags parameter passed to ResolveHost and DetachCallback + * that may be bitwise OR'd together. + * + * NOTE: in this implementation, these flags correspond exactly in value + * to the flags defined on nsIDNSService. + */ + enum { + RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE, + RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME, + RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM, + RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW, + RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE, + //RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used + RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE, + //RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used + RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION + }; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + /** + * Flush the DNS cache. + */ + void FlushCache(); + +private: + explicit nsHostResolver(uint32_t maxCacheEntries, + uint32_t defaultCacheEntryLifetime, + uint32_t defaultGracePeriod); + ~nsHostResolver(); + + nsresult Init(); + nsresult IssueLookup(nsHostRecord *); + bool GetHostToLookup(nsHostRecord **m); + + enum LookupStatus { + LOOKUP_OK, + LOOKUP_RESOLVEAGAIN, + }; + + LookupStatus OnLookupComplete(nsHostRecord *, nsresult, mozilla::net::AddrInfo *); + void DeQueue(PRCList &aQ, nsHostRecord **aResult); + void ClearPendingQueue(PRCList *aPendingQueue); + nsresult ConditionallyCreateThread(nsHostRecord *rec); + + /** + * Starts a new lookup in the background for entries that are in the grace + * period with a failed connect or all cached entries are negative. + */ + nsresult ConditionallyRefreshRecord(nsHostRecord *rec, const char *host); + + static void MoveQueue(nsHostRecord *aRec, PRCList &aDestQ); + + static void ThreadFunc(void *); + + enum { + METHOD_HIT = 1, + METHOD_RENEWAL = 2, + METHOD_NEGATIVE_HIT = 3, + METHOD_LITERAL = 4, + METHOD_OVERFLOW = 5, + METHOD_NETWORK_FIRST = 6, + METHOD_NETWORK_SHARED = 7 + }; + + uint32_t mMaxCacheEntries; + uint32_t mDefaultCacheLifetime; // granularity seconds + uint32_t mDefaultGracePeriod; // granularity seconds + mutable Mutex mLock; // mutable so SizeOfIncludingThis can be const + CondVar mIdleThreadCV; + PLDHashTable mDB; + PRCList mHighQ; + PRCList mMediumQ; + PRCList mLowQ; + PRCList mEvictionQ; + uint32_t mEvictionQSize; + PRTime mCreationTime; + PRIntervalTime mLongIdleTimeout; + PRIntervalTime mShortIdleTimeout; + + mozilla::Atomic mShutdown; + mozilla::Atomic mNumIdleThreads; + mozilla::Atomic mThreadCount; + mozilla::Atomic mActiveAnyThreadCount; + mozilla::Atomic mPendingCount; + + // Set the expiration time stamps appropriately. + void PrepareRecordExpiration(nsHostRecord* rec) const; + +public: + /* + * Called by the networking dashboard via the DnsService2 + */ + void GetDNSCacheEntries(nsTArray *); +}; + +#endif // nsHostResolver_h__ diff --git a/netwerk/dns/nsIDNKitInterface.h b/netwerk/dns/nsIDNKitInterface.h new file mode 100644 index 000000000..3e1ae7a73 --- /dev/null +++ b/netwerk/dns/nsIDNKitInterface.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved. + * + * By using this file, you agree to the terms and conditions set forth bellow. + * + * LICENSE TERMS AND CONDITIONS + * + * The following License Terms and Conditions apply, unless a different + * license is obtained from Japan Network Information Center ("JPNIC"), + * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, + * Chiyoda-ku, Tokyo 101-0047, Japan. + + * 1. Use, Modification and Redistribution (including distribution of any + * modified or derived work) in source and/or binary forms is permitted + * under this License Terms and Conditions. + * + * 2. Redistribution of source code must retain the copyright notices as they + * appear in each source code file, this License Terms and Conditions. + * + * 3. Redistribution in binary form must reproduce the Copyright Notice, + * this License Terms and Conditions, in the documentation and/or other + * materials provided with the distribution. For the purposes of binary + * distribution the "Copyright Notice" refers to the following language: + * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." + * + * 4. The name of JPNIC may not be used to endorse or promote products + * derived from this Software without specific prior written approval of + * JPNIC. + * + * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef nsIDNKitWrapper_h__ +#define nsIDNKitWrapper_h__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * libidnkit result code. + */ +typedef enum { + idn_success, + idn_notfound, + idn_invalid_encoding, + idn_invalid_syntax, + idn_invalid_name, + idn_invalid_message, + idn_invalid_action, + idn_invalid_codepoint, + idn_invalid_length, + idn_buffer_overflow, + idn_noentry, + idn_nomemory, + idn_nofile, + idn_nomapping, + idn_context_required, + idn_prohibited, + idn_failure /* !!This must be the last one!! */ +} idn_result_t; + +/* + * BIDI type codes. + */ +typedef enum { + idn_biditype_r_al, + idn_biditype_l, + idn_biditype_others +} idn_biditype_t; + +/* + * A Handle for nameprep operations. + */ +typedef struct idn_nameprep *idn_nameprep_t; + + +/* + * The latest version of nameprep. + */ +#define IDN_NAMEPREP_CURRENT "nameprep-11" + +#undef assert +#define assert(a) +#define TRACE(a) + + +/* race.c */ +idn_result_t race_decode_decompress(const char *from, + uint16_t *buf, + size_t buflen); +idn_result_t race_compress_encode(const uint16_t *p, + int compress_mode, + char *to, size_t tolen); +int get_compress_mode(uint16_t *p); + + +/* nameprep.c */ + +/* + * Create a handle for nameprep operations. + * The handle is stored in '*handlep', which is used other functions + * in this module. + * The version of the NAMEPREP specification can be specified with + * 'version' parameter. If 'version' is nullptr, the latest version + * is used. + * + * Returns: + * idn_success -- ok. + * idn_notfound -- specified version not found. + */ +idn_result_t +idn_nameprep_create(const char *version, idn_nameprep_t *handlep); + +/* + * Close a handle, which was created by 'idn_nameprep_create'. + */ +void +idn_nameprep_destroy(idn_nameprep_t handle); + +/* + * Perform character mapping on an UCS4 string specified by 'from', and + * store the result into 'to', whose length is specified by 'tolen'. + * + * Returns: + * idn_success -- ok. + * idn_buffer_overflow -- result buffer is too small. + */ +idn_result_t +idn_nameprep_map(idn_nameprep_t handle, const uint32_t *from, + uint32_t *to, size_t tolen); + +/* + * Check if an UCS4 string 'str' contains any prohibited characters specified + * by the draft. If found, the pointer to the first such character is stored + * into '*found'. Otherwise '*found' will be nullptr. + * + * Returns: + * idn_success -- check has been done properly. (But this + * does not mean that no prohibited character + * was found. Check '*found' to see the + * result.) + */ +idn_result_t +idn_nameprep_isprohibited(idn_nameprep_t handle, const uint32_t *str, + const uint32_t **found); + +/* + * Check if an UCS4 string 'str' contains any unassigned characters specified + * by the draft. If found, the pointer to the first such character is stored + * into '*found'. Otherwise '*found' will be nullptr. + * + * Returns: + * idn_success -- check has been done properly. (But this + * does not mean that no unassinged character + * was found. Check '*found' to see the + * result.) + */ +idn_result_t +idn_nameprep_isunassigned(idn_nameprep_t handle, const uint32_t *str, + const uint32_t **found); + +/* + * Check if an UCS4 string 'str' is valid string specified by ``bidi check'' + * of the draft. If it is not valid, the pointer to the first invalid + * character is stored into '*found'. Otherwise '*found' will be nullptr. + * + * Returns: + * idn_success -- check has been done properly. (But this + * does not mean that the string was valid. + * Check '*found' to see the result.) + */ +idn_result_t +idn_nameprep_isvalidbidi(idn_nameprep_t handle, const uint32_t *str, + const uint32_t **found); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* nsIDNKitWrapper_h__ */ diff --git a/netwerk/dns/nsIDNSListener.idl b/netwerk/dns/nsIDNSListener.idl new file mode 100644 index 000000000..46c241005 --- /dev/null +++ b/netwerk/dns/nsIDNSListener.idl @@ -0,0 +1,46 @@ +/* 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/. */ + +#include "nsISupports.idl" + +interface nsICancelable; +interface nsIDNSRecord; + +/** + * nsIDNSListener + */ +[scriptable, function, uuid(27d49bfe-280c-49e0-bbaa-f6200c232c3d)] +interface nsIDNSListener : nsISupports +{ + /** + * called when an asynchronous host lookup completes. + * + * @param aRequest + * the value returned from asyncResolve. + * @param aRecord + * the DNS record corresponding to the hostname that was resolved. + * this parameter is null if there was an error. + * @param aStatus + * if the lookup failed, this parameter gives the reason. + */ + void onLookupComplete(in nsICancelable aRequest, + in nsIDNSRecord aRecord, + in nsresult aStatus); +}; + +/** + * nsIDNSListenerProxy: + * + * Must be implemented by classes that wrap the original listener passed to + * nsIDNSService.AsyncResolve, so we have access to original listener for + * comparison purposes. + */ +[uuid(60eff0e4-6f7c-493c-add9-1cbea59063ad)] +interface nsIDNSListenerProxy : nsISupports +{ + /* + * The original nsIDNSListener which requested hostname resolution. + */ + readonly attribute nsIDNSListener originalListener; +}; diff --git a/netwerk/dns/nsIDNSRecord.idl b/netwerk/dns/nsIDNSRecord.idl new file mode 100644 index 000000000..b3158bd3b --- /dev/null +++ b/netwerk/dns/nsIDNSRecord.idl @@ -0,0 +1,100 @@ +/* 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/. */ + +#include "nsISupports.idl" + +%{ C++ +namespace mozilla { +namespace net { +union NetAddr; +} +} +#include "nsTArrayForwardDeclare.h" +%} +native NetAddr(mozilla::net::NetAddr); +[ref] native nsNetAddrTArrayRef(nsTArray); +interface nsINetAddr; + +/** + * nsIDNSRecord + * + * this interface represents the result of a DNS lookup. since a DNS + * query may return more than one resolved IP address, the record acts + * like an enumerator, allowing the caller to easily step through the + * list of IP addresses. + */ +[scriptable, uuid(f92228ae-c417-4188-a604-0830a95e7eb9)] +interface nsIDNSRecord : nsISupports +{ + /** + * @return the canonical hostname for this record. this value is empty if + * the record was not fetched with the RESOLVE_CANONICAL_NAME flag. + * + * e.g., www.mozilla.org --> rheet.mozilla.org + */ + readonly attribute ACString canonicalName; + + /** + * this function copies the value of the next IP address into the + * given NetAddr struct and increments the internal address iterator. + * + * @param aPort + * A port number to initialize the NetAddr with. + * + * @throws NS_ERROR_NOT_AVAILABLE if there is not another IP address in + * the record. + */ + [noscript] NetAddr getNextAddr(in uint16_t aPort); + + /** + * this function copies the value of all working members of the RR + * set into the output array. + * + * @param aAddressArray + * The result set + */ + [noscript] void getAddresses(out nsNetAddrTArrayRef aAddressArray); + + /** + * this function returns the value of the next IP address as a + * scriptable address and increments the internal address iterator. + * + * @param aPort + * A port number to initialize the nsINetAddr with. + * + * @throws NS_ERROR_NOT_AVAILABLE if there is not another IP address in + * the record. + */ + nsINetAddr getScriptableNextAddr(in uint16_t aPort); + + /** + * this function returns the value of the next IP address as a + * string and increments the internal address iterator. + * + * @throws NS_ERROR_NOT_AVAILABLE if there is not another IP address in + * the record. + */ + ACString getNextAddrAsString(); + + /** + * this function returns true if there is another address in the record. + */ + boolean hasMore(); + + /** + * this function resets the internal address iterator to the first + * address in the record. + */ + void rewind(); + + /** + * This function indicates that the last address obtained via getNextAddr*() + * was not usuable and should be skipped in future uses of this + * record if other addresses are available. + * + * @param aPort is the port number associated with the failure, if any. + * It may be zero if not applicable. + */ + void reportUnusable(in uint16_t aPort); +}; diff --git a/netwerk/dns/nsIDNSService.idl b/netwerk/dns/nsIDNSService.idl new file mode 100644 index 000000000..2704790dc --- /dev/null +++ b/netwerk/dns/nsIDNSService.idl @@ -0,0 +1,171 @@ +/* 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/. */ + +#include "nsISupports.idl" + +interface nsICancelable; +interface nsIEventTarget; +interface nsIDNSRecord; +interface nsIDNSListener; + +%{C++ +#include "nsTArrayForwardDeclare.h" +namespace mozilla { namespace net { + struct DNSCacheEntries; +} } +%} + +[ptr] native EntriesArray(nsTArray); + +/** + * nsIDNSService + */ +[scriptable, uuid(de5642c6-61fc-4fcf-9a47-03226b0d4e21)] +interface nsIDNSService : nsISupports +{ + /** + * kicks off an asynchronous host lookup. + * + * @param aHostName + * the hostname or IP-address-literal to resolve. + * @param aFlags + * a bitwise OR of the RESOLVE_ prefixed constants defined below. + * @param aListener + * the listener to be notified when the result is available. + * @param aListenerTarget + * optional parameter (may be null). if non-null, this parameter + * specifies the nsIEventTarget of the thread on which the + * listener's onLookupComplete should be called. however, if this + * parameter is null, then onLookupComplete will be called on an + * unspecified thread (possibly recursively). + * + * @return An object that can be used to cancel the host lookup. + */ + nsICancelable asyncResolve(in AUTF8String aHostName, + in unsigned long aFlags, + in nsIDNSListener aListener, + in nsIEventTarget aListenerTarget); + + /** + * Attempts to cancel a previously requested async DNS lookup + * + * @param aHostName + * the hostname or IP-address-literal to resolve. + * @param aFlags + * a bitwise OR of the RESOLVE_ prefixed constants defined below. + * @param aListener + * the original listener which was to be notified about the host lookup + * result - used to match request information to requestor. + * @param aReason + * nsresult reason for the cancellation + * + * @return An object that can be used to cancel the host lookup. + */ + void cancelAsyncResolve(in AUTF8String aHostName, + in unsigned long aFlags, + in nsIDNSListener aListener, + in nsresult aReason); + + /** + * called to synchronously resolve a hostname. warning this method may + * block the calling thread for a long period of time. it is extremely + * unwise to call this function on the UI thread of an application. + * + * @param aHostName + * the hostname or IP-address-literal to resolve. + * @param aFlags + * a bitwise OR of the RESOLVE_ prefixed constants defined below. + * + * @return DNS record corresponding to the given hostname. + * @throws NS_ERROR_UNKNOWN_HOST if host could not be resolved. + */ + nsIDNSRecord resolve(in AUTF8String aHostName, + in unsigned long aFlags); + + /** + * kicks off an asynchronous host lookup. + * + * This function is identical to asyncResolve except an additional + * parameter aNetwortInterface. If parameter aNetworkInterface is an empty + * string function will return the same result as asyncResolve. + * Setting aNetworkInterface value make only sense for gonk,because it + * an per networking interface query is possible. + */ + nsICancelable asyncResolveExtended(in AUTF8String aHostName, + in unsigned long aFlags, + in AUTF8String aNetworkInterface, + in nsIDNSListener aListener, + in nsIEventTarget aListenerTarget); + + /** + * Attempts to cancel a previously requested async DNS lookup + * This is an extended versin with a additional parameter aNetworkInterface + */ + void cancelAsyncResolveExtended(in AUTF8String aHostName, + in unsigned long aFlags, + in AUTF8String aNetworkInterface, + in nsIDNSListener aListener, + in nsresult aReason); + + /** + * The method takes a pointer to an nsTArray + * and fills it with cache entry data + * Called by the networking dashboard + */ + [noscript] void getDNSCacheEntries(in EntriesArray args); + + /** + * @return the hostname of the operating system. + */ + readonly attribute AUTF8String myHostName; + + /************************************************************************* + * Listed below are the various flags that may be OR'd together to form + * the aFlags parameter passed to asyncResolve() and resolve(). + */ + + /** + * if set, this flag suppresses the internal DNS lookup cache. + */ + const unsigned long RESOLVE_BYPASS_CACHE = (1 << 0); + + /** + * if set, the canonical name of the specified host will be queried. + */ + const unsigned long RESOLVE_CANONICAL_NAME = (1 << 1); + + /** + * if set, the query is given lower priority. Medium takes precedence + * if both are used. + */ + const unsigned long RESOLVE_PRIORITY_MEDIUM = (1 << 2); + const unsigned long RESOLVE_PRIORITY_LOW = (1 << 3); + + /** + * if set, indicates request is speculative. Speculative requests + * return errors if prefetching is disabled by configuration. + */ + const unsigned long RESOLVE_SPECULATE = (1 << 4); + + /** + * If set, only IPv4 addresses will be returned from resolve/asyncResolve. + */ + const unsigned long RESOLVE_DISABLE_IPV6 = (1 << 5); + + /** + * If set, only literals and cached entries will be returned from resolve/ + * asyncResolve. + */ + const unsigned long RESOLVE_OFFLINE = (1 << 6); + + /** + * If set, only IPv6 addresses will be returned from resolve/asyncResolve. + */ + const unsigned long RESOLVE_DISABLE_IPV4 = (1 << 7); + + /** + * If set, allow name collision results (127.0.53.53) which are normally filtered. + */ + const unsigned long RESOLVE_ALLOW_NAME_COLLISION = (1 << 8); +}; diff --git a/netwerk/dns/nsIDNService.cpp b/netwerk/dns/nsIDNService.cpp new file mode 100644 index 000000000..d4f31027e --- /dev/null +++ b/netwerk/dns/nsIDNService.cpp @@ -0,0 +1,959 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "nsIDNService.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsUnicharUtils.h" +#include "nsUnicodeProperties.h" +#include "nsUnicodeScriptCodes.h" +#include "harfbuzz/hb.h" +#include "nsIServiceManager.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIObserverService.h" +#include "nsISupportsPrimitives.h" +#include "punycode.h" + +#ifdef IDNA2008 +// Currently we use the non-transitional processing option -- see +// http://unicode.org/reports/tr46/ +// To switch to transitional processing, change the value of this flag +// and kTransitionalProcessing in netwerk/test/unit/test_idna2008.js to true +// (revert bug 1218179). +const bool kIDNA2008_TransitionalProcessing = false; + +#include "ICUUtils.h" +#endif + +using namespace mozilla::unicode; + +//----------------------------------------------------------------------------- +// RFC 1034 - 3.1. Name space specifications and terminology +static const uint32_t kMaxDNSNodeLen = 63; +// RFC 3490 - 5. ACE prefix +static const char kACEPrefix[] = "xn--"; +#define kACEPrefixLen 4 + +//----------------------------------------------------------------------------- + +#define NS_NET_PREF_IDNBLACKLIST "network.IDN.blacklist_chars" +#define NS_NET_PREF_SHOWPUNYCODE "network.IDN_show_punycode" +#define NS_NET_PREF_IDNWHITELIST "network.IDN.whitelist." +#define NS_NET_PREF_IDNUSEWHITELIST "network.IDN.use_whitelist" +#define NS_NET_PREF_IDNRESTRICTION "network.IDN.restriction_profile" + +inline bool isOnlySafeChars(const nsAFlatString& in, + const nsAFlatString& blacklist) +{ + return (blacklist.IsEmpty() || + in.FindCharInSet(blacklist) == kNotFound); +} + +//----------------------------------------------------------------------------- +// nsIDNService +//----------------------------------------------------------------------------- + +/* Implementation file */ +NS_IMPL_ISUPPORTS(nsIDNService, + nsIIDNService, + nsIObserver, + nsISupportsWeakReference) + +nsresult nsIDNService::Init() +{ + nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) + prefs->GetBranch(NS_NET_PREF_IDNWHITELIST, getter_AddRefs(mIDNWhitelistPrefBranch)); + + nsCOMPtr prefInternal(do_QueryInterface(prefs)); + if (prefInternal) { + prefInternal->AddObserver(NS_NET_PREF_IDNBLACKLIST, this, true); + prefInternal->AddObserver(NS_NET_PREF_SHOWPUNYCODE, this, true); + prefInternal->AddObserver(NS_NET_PREF_IDNRESTRICTION, this, true); + prefInternal->AddObserver(NS_NET_PREF_IDNUSEWHITELIST, this, true); + prefsChanged(prefInternal, nullptr); + } + + return NS_OK; +} + +NS_IMETHODIMP nsIDNService::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { + nsCOMPtr prefBranch( do_QueryInterface(aSubject) ); + if (prefBranch) + prefsChanged(prefBranch, aData); + } + return NS_OK; +} + +void nsIDNService::prefsChanged(nsIPrefBranch *prefBranch, const char16_t *pref) +{ + if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNBLACKLIST).Equals(pref)) { + nsCOMPtr blacklist; + nsresult rv = prefBranch->GetComplexValue(NS_NET_PREF_IDNBLACKLIST, + NS_GET_IID(nsISupportsString), + getter_AddRefs(blacklist)); + if (NS_SUCCEEDED(rv)) + blacklist->ToString(getter_Copies(mIDNBlacklist)); + else + mIDNBlacklist.Truncate(); + } + if (!pref || NS_LITERAL_STRING(NS_NET_PREF_SHOWPUNYCODE).Equals(pref)) { + bool val; + if (NS_SUCCEEDED(prefBranch->GetBoolPref(NS_NET_PREF_SHOWPUNYCODE, &val))) + mShowPunycode = val; + } + if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNUSEWHITELIST).Equals(pref)) { + bool val; + if (NS_SUCCEEDED(prefBranch->GetBoolPref(NS_NET_PREF_IDNUSEWHITELIST, + &val))) + mIDNUseWhitelist = val; + } + if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNRESTRICTION).Equals(pref)) { + nsXPIDLCString profile; + if (NS_FAILED(prefBranch->GetCharPref(NS_NET_PREF_IDNRESTRICTION, + getter_Copies(profile)))) { + profile.Truncate(); + } + if (profile.EqualsLiteral("moderate")) { + mRestrictionProfile = eModeratelyRestrictiveProfile; + } else if (profile.EqualsLiteral("high")) { + mRestrictionProfile = eHighlyRestrictiveProfile; + } else { + mRestrictionProfile = eASCIIOnlyProfile; + } + } +} + +nsIDNService::nsIDNService() + : mShowPunycode(false) + , mIDNUseWhitelist(false) +{ +#ifdef IDNA2008 + uint32_t IDNAOptions = UIDNA_CHECK_BIDI | UIDNA_CHECK_CONTEXTJ; + if (!kIDNA2008_TransitionalProcessing) { + IDNAOptions |= UIDNA_NONTRANSITIONAL_TO_UNICODE; + } + UErrorCode errorCode = U_ZERO_ERROR; + mIDNA = uidna_openUTS46(IDNAOptions, &errorCode); +#else + if (idn_success != idn_nameprep_create(nullptr, &mNamePrepHandle)) + mNamePrepHandle = nullptr; + + mNormalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID); + /* member initializers and constructor code */ +#endif +} + +nsIDNService::~nsIDNService() +{ +#ifdef IDNA2008 + uidna_close(mIDNA); +#else + idn_nameprep_destroy(mNamePrepHandle); +#endif +} + +#ifdef IDNA2008 +nsresult +nsIDNService::IDNA2008ToUnicode(const nsACString& input, nsAString& output) +{ + NS_ConvertUTF8toUTF16 inputStr(input); + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + UErrorCode errorCode = U_ZERO_ERROR; + int32_t inLen = inputStr.Length(); + int32_t outMaxLen = kMaxDNSNodeLen + 1; + UChar outputBuffer[kMaxDNSNodeLen + 1]; + + int32_t outLen = uidna_labelToUnicode(mIDNA, (const UChar*)inputStr.get(), + inLen, outputBuffer, outMaxLen, + &info, &errorCode); + if (info.errors != 0) { + return NS_ERROR_MALFORMED_URI; + } + + if (U_SUCCESS(errorCode)) { + ICUUtils::AssignUCharArrayToString(outputBuffer, outLen, output); + } + + nsresult rv = ICUUtils::UErrorToNsResult(errorCode); + if (rv == NS_ERROR_FAILURE) { + rv = NS_ERROR_MALFORMED_URI; + } + return rv; +} + +nsresult +nsIDNService::IDNA2008StringPrep(const nsAString& input, + nsAString& output, + stringPrepFlag flag) +{ + UIDNAInfo info = UIDNA_INFO_INITIALIZER; + UErrorCode errorCode = U_ZERO_ERROR; + int32_t inLen = input.Length(); + int32_t outMaxLen = kMaxDNSNodeLen + 1; + UChar outputBuffer[kMaxDNSNodeLen + 1]; + + int32_t outLen = + uidna_labelToUnicode(mIDNA, (const UChar*)PromiseFlatString(input).get(), + inLen, outputBuffer, outMaxLen, &info, &errorCode); + nsresult rv = ICUUtils::UErrorToNsResult(errorCode); + if (rv == NS_ERROR_FAILURE) { + rv = NS_ERROR_MALFORMED_URI; + } + NS_ENSURE_SUCCESS(rv, rv); + + // Output the result of nameToUnicode even if there were errors + ICUUtils::AssignUCharArrayToString(outputBuffer, outLen, output); + + if (flag == eStringPrepIgnoreErrors) { + return NS_OK; + } + + if (info.errors != 0) { + if (flag == eStringPrepForDNS) { + output.Truncate(); + } + rv = NS_ERROR_MALFORMED_URI; + } + + return rv; +} +#endif + +NS_IMETHODIMP nsIDNService::ConvertUTF8toACE(const nsACString & input, nsACString & ace) +{ + return UTF8toACE(input, ace, eStringPrepForDNS); +} + +nsresult nsIDNService::UTF8toACE(const nsACString & input, nsACString & ace, + stringPrepFlag flag) +{ + nsresult rv; + NS_ConvertUTF8toUTF16 ustr(input); + + // map ideographic period to ASCII period etc. + normalizeFullStops(ustr); + + uint32_t len, offset; + len = 0; + offset = 0; + nsAutoCString encodedBuf; + + nsAString::const_iterator start, end; + ustr.BeginReading(start); + ustr.EndReading(end); + ace.Truncate(); + + // encode nodes if non ASCII + while (start != end) { + len++; + if (*start++ == (char16_t)'.') { + rv = stringPrepAndACE(Substring(ustr, offset, len - 1), encodedBuf, flag); + NS_ENSURE_SUCCESS(rv, rv); + + ace.Append(encodedBuf); + ace.Append('.'); + offset += len; + len = 0; + } + } + + // encode the last node if non ASCII + if (len) { + rv = stringPrepAndACE(Substring(ustr, offset, len), encodedBuf, flag); + NS_ENSURE_SUCCESS(rv, rv); + + ace.Append(encodedBuf); + } + + return NS_OK; +} + +NS_IMETHODIMP nsIDNService::ConvertACEtoUTF8(const nsACString & input, nsACString & _retval) +{ + return ACEtoUTF8(input, _retval, eStringPrepForDNS); +} + +nsresult nsIDNService::ACEtoUTF8(const nsACString & input, nsACString & _retval, + stringPrepFlag flag) +{ + // RFC 3490 - 4.2 ToUnicode + // ToUnicode never fails. If any step fails, then the original input + // sequence is returned immediately in that step. + + uint32_t len = 0, offset = 0; + nsAutoCString decodedBuf; + + nsACString::const_iterator start, end; + input.BeginReading(start); + input.EndReading(end); + _retval.Truncate(); + + // loop and decode nodes + while (start != end) { + len++; + if (*start++ == '.') { + if (NS_FAILED(decodeACE(Substring(input, offset, len - 1), decodedBuf, + flag))) { + _retval.Assign(input); + return NS_OK; + } + + _retval.Append(decodedBuf); + _retval.Append('.'); + offset += len; + len = 0; + } + } + // decode the last node + if (len) { + if (NS_FAILED(decodeACE(Substring(input, offset, len), decodedBuf, + flag))) + _retval.Assign(input); + else + _retval.Append(decodedBuf); + } + + return NS_OK; +} + +NS_IMETHODIMP nsIDNService::IsACE(const nsACString & input, bool *_retval) +{ + const char *data = input.BeginReading(); + uint32_t dataLen = input.Length(); + + // look for the ACE prefix in the input string. it may occur + // at the beginning of any segment in the domain name. for + // example: "www.xn--ENCODED.com" + + const char *p = PL_strncasestr(data, kACEPrefix, dataLen); + + *_retval = p && (p == data || *(p - 1) == '.'); + return NS_OK; +} + +NS_IMETHODIMP nsIDNService::Normalize(const nsACString & input, + nsACString & output) +{ + // protect against bogus input + NS_ENSURE_TRUE(IsUTF8(input), NS_ERROR_UNEXPECTED); + + NS_ConvertUTF8toUTF16 inUTF16(input); + normalizeFullStops(inUTF16); + + // pass the domain name to stringprep label by label + nsAutoString outUTF16, outLabel; + + uint32_t len = 0, offset = 0; + nsresult rv; + nsAString::const_iterator start, end; + inUTF16.BeginReading(start); + inUTF16.EndReading(end); + + while (start != end) { + len++; + if (*start++ == char16_t('.')) { + rv = stringPrep(Substring(inUTF16, offset, len - 1), outLabel, + eStringPrepIgnoreErrors); + NS_ENSURE_SUCCESS(rv, rv); + + outUTF16.Append(outLabel); + outUTF16.Append(char16_t('.')); + offset += len; + len = 0; + } + } + if (len) { + rv = stringPrep(Substring(inUTF16, offset, len), outLabel, + eStringPrepIgnoreErrors); + NS_ENSURE_SUCCESS(rv, rv); + + outUTF16.Append(outLabel); + } + + CopyUTF16toUTF8(outUTF16, output); + return NS_OK; +} + +NS_IMETHODIMP nsIDNService::ConvertToDisplayIDN(const nsACString & input, bool * _isASCII, nsACString & _retval) +{ + // If host is ACE, then convert to UTF-8 if the host is in the IDN whitelist. + // Else, if host is already UTF-8, then make sure it is normalized per IDN. + + nsresult rv = NS_OK; + + // Even if the hostname is not ASCII, individual labels may still be ACE, so + // test IsACE before testing IsASCII + bool isACE; + IsACE(input, &isACE); + + if (IsASCII(input)) { + // first, canonicalize the host to lowercase, for whitelist lookup + _retval = input; + ToLowerCase(_retval); + + if (isACE && !mShowPunycode) { + // ACEtoUTF8() can't fail, but might return the original ACE string + nsAutoCString temp(_retval); + // If the domain is in the whitelist, return the host in UTF-8. + // Otherwise convert from ACE to UTF8 only those labels which are + // considered safe for display + ACEtoUTF8(temp, _retval, isInWhitelist(temp) ? + eStringPrepIgnoreErrors : eStringPrepForUI); + *_isASCII = IsASCII(_retval); + } else { + *_isASCII = true; + } + } else { + // We have to normalize the hostname before testing against the domain + // whitelist (see bug 315411), and to ensure the entire string gets + // normalized. + // + // Normalization and the tests for safe display below, assume that the + // input is Unicode, so first convert any ACE labels to UTF8 + if (isACE) { + nsAutoCString temp; + ACEtoUTF8(input, temp, eStringPrepIgnoreErrors); + rv = Normalize(temp, _retval); + } else { + rv = Normalize(input, _retval); + } + if (NS_FAILED(rv)) return rv; + + if (mShowPunycode && NS_SUCCEEDED(UTF8toACE(_retval, _retval, + eStringPrepIgnoreErrors))) { + *_isASCII = true; + return NS_OK; + } + + // normalization could result in an ASCII-only hostname. alternatively, if + // the host is converted to ACE by the normalizer, then the host may contain + // unsafe characters, so leave it ACE encoded. see bug 283016, bug 301694, and bug 309311. + *_isASCII = IsASCII(_retval); + if (!*_isASCII && !isInWhitelist(_retval)) { + // UTF8toACE with eStringPrepForUI may return a domain name where + // some labels are in UTF-8 and some are in ACE, depending on + // whether they are considered safe for display + rv = UTF8toACE(_retval, _retval, eStringPrepForUI); + *_isASCII = IsASCII(_retval); + return rv; + } + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- + +static nsresult utf16ToUcs4(const nsAString& in, + uint32_t *out, + uint32_t outBufLen, + uint32_t *outLen) +{ + uint32_t i = 0; + nsAString::const_iterator start, end; + in.BeginReading(start); + in.EndReading(end); + + while (start != end) { + char16_t curChar; + + curChar= *start++; + + if (start != end && + NS_IS_HIGH_SURROGATE(curChar) && + NS_IS_LOW_SURROGATE(*start)) { + out[i] = SURROGATE_TO_UCS4(curChar, *start); + ++start; + } + else + out[i] = curChar; + + i++; + if (i >= outBufLen) + return NS_ERROR_MALFORMED_URI; + } + out[i] = (uint32_t)'\0'; + *outLen = i; + return NS_OK; +} + +#ifndef IDNA2008 +static void ucs4toUtf16(const uint32_t *in, nsAString& out) +{ + while (*in) { + if (!IS_IN_BMP(*in)) { + out.Append((char16_t) H_SURROGATE(*in)); + out.Append((char16_t) L_SURROGATE(*in)); + } + else + out.Append((char16_t) *in); + in++; + } +} +#endif + +static nsresult punycode(const nsAString& in, nsACString& out) +{ + uint32_t ucs4Buf[kMaxDNSNodeLen + 1]; + uint32_t ucs4Len = 0u; + nsresult rv = utf16ToUcs4(in, ucs4Buf, kMaxDNSNodeLen, &ucs4Len); + NS_ENSURE_SUCCESS(rv, rv); + + // need maximum 20 bits to encode 16 bit Unicode character + // (include null terminator) + const uint32_t kEncodedBufSize = kMaxDNSNodeLen * 20 / 8 + 1 + 1; + char encodedBuf[kEncodedBufSize]; + punycode_uint encodedLength = kEncodedBufSize; + + enum punycode_status status = punycode_encode(ucs4Len, + ucs4Buf, + nullptr, + &encodedLength, + encodedBuf); + + if (punycode_success != status || + encodedLength >= kEncodedBufSize) + return NS_ERROR_MALFORMED_URI; + + encodedBuf[encodedLength] = '\0'; + out.Assign(nsDependentCString(kACEPrefix) + nsDependentCString(encodedBuf)); + + return rv; +} + +// RFC 3454 +// +// 1) Map -- For each character in the input, check if it has a mapping +// and, if so, replace it with its mapping. This is described in section 3. +// +// 2) Normalize -- Possibly normalize the result of step 1 using Unicode +// normalization. This is described in section 4. +// +// 3) Prohibit -- Check for any characters that are not allowed in the +// output. If any are found, return an error. This is described in section +// 5. +// +// 4) Check bidi -- Possibly check for right-to-left characters, and if any +// are found, make sure that the whole string satisfies the requirements +// for bidirectional strings. If the string does not satisfy the requirements +// for bidirectional strings, return an error. This is described in section 6. +// +// 5) Check unassigned code points -- If allowUnassigned is false, check for +// any unassigned Unicode points and if any are found return an error. +// This is described in section 7. +// +nsresult nsIDNService::stringPrep(const nsAString& in, nsAString& out, + stringPrepFlag flag) +{ +#ifdef IDNA2008 + return IDNA2008StringPrep(in, out, flag); +#else + if (!mNamePrepHandle || !mNormalizer) + return NS_ERROR_FAILURE; + + uint32_t ucs4Buf[kMaxDNSNodeLen + 1]; + uint32_t ucs4Len; + nsresult rv = utf16ToUcs4(in, ucs4Buf, kMaxDNSNodeLen, &ucs4Len); + NS_ENSURE_SUCCESS(rv, rv); + + // map + idn_result_t idn_err; + + uint32_t namePrepBuf[kMaxDNSNodeLen * 3]; // map up to three characters + idn_err = idn_nameprep_map(mNamePrepHandle, (const uint32_t *) ucs4Buf, + (uint32_t *) namePrepBuf, kMaxDNSNodeLen * 3); + NS_ENSURE_TRUE(idn_err == idn_success, NS_ERROR_MALFORMED_URI); + + nsAutoString namePrepStr; + ucs4toUtf16(namePrepBuf, namePrepStr); + if (namePrepStr.Length() >= kMaxDNSNodeLen) + return NS_ERROR_MALFORMED_URI; + + // normalize + nsAutoString normlizedStr; + rv = mNormalizer->NormalizeUnicodeNFKC(namePrepStr, normlizedStr); + if (normlizedStr.Length() >= kMaxDNSNodeLen) + return NS_ERROR_MALFORMED_URI; + + // set the result string + out.Assign(normlizedStr); + + if (flag == eStringPrepIgnoreErrors) { + return NS_OK; + } + + // prohibit + const uint32_t *found = nullptr; + idn_err = idn_nameprep_isprohibited(mNamePrepHandle, + (const uint32_t *) ucs4Buf, &found); + if (idn_err != idn_success || found) { + rv = NS_ERROR_MALFORMED_URI; + } else { + // check bidi + idn_err = idn_nameprep_isvalidbidi(mNamePrepHandle, + (const uint32_t *) ucs4Buf, &found); + if (idn_err != idn_success || found) { + rv = NS_ERROR_MALFORMED_URI; + } else if (flag == eStringPrepForUI) { + // check unassigned code points + idn_err = idn_nameprep_isunassigned(mNamePrepHandle, + (const uint32_t *) ucs4Buf, &found); + if (idn_err != idn_success || found) { + rv = NS_ERROR_MALFORMED_URI; + } + } + } + + if (flag == eStringPrepForDNS && NS_FAILED(rv)) { + out.Truncate(); + } + + return rv; +#endif +} + +nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out, + stringPrepFlag flag) +{ + nsresult rv = NS_OK; + + out.Truncate(); + + if (in.Length() > kMaxDNSNodeLen) { + NS_WARNING("IDN node too large"); + return NS_ERROR_MALFORMED_URI; + } + + if (IsASCII(in)) { + LossyCopyUTF16toASCII(in, out); + return NS_OK; + } + + nsAutoString strPrep; + rv = stringPrep(in, strPrep, flag); + if (flag == eStringPrepForDNS) { + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsASCII(strPrep)) { + LossyCopyUTF16toASCII(strPrep, out); + return NS_OK; + } + + if (flag == eStringPrepForUI && NS_SUCCEEDED(rv) && isLabelSafe(in)) { + CopyUTF16toUTF8(strPrep, out); + return NS_OK; + } + + rv = punycode(strPrep, out); + // Check that the encoded output isn't larger than the maximum length + // of a DNS node per RFC 1034. + // This test isn't necessary in the code paths above where the input + // is ASCII (since the output will be the same length as the input) or + // where we convert to UTF-8 (since the output is only used for + // display in the UI and not passed to DNS and can legitimately be + // longer than the limit). + if (out.Length() > kMaxDNSNodeLen) { + NS_WARNING("IDN node too large"); + return NS_ERROR_MALFORMED_URI; + } + + return rv; +} + +// RFC 3490 +// 1) Whenever dots are used as label separators, the following characters +// MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full +// stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full +// stop). + +void nsIDNService::normalizeFullStops(nsAString& s) +{ + nsAString::const_iterator start, end; + s.BeginReading(start); + s.EndReading(end); + int32_t index = 0; + + while (start != end) { + switch (*start) { + case 0x3002: + case 0xFF0E: + case 0xFF61: + s.Replace(index, 1, NS_LITERAL_STRING(".")); + break; + default: + break; + } + start++; + index++; + } +} + +nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out, + stringPrepFlag flag) +{ + bool isAce; + IsACE(in, &isAce); + if (!isAce) { + out.Assign(in); + return NS_OK; + } + + nsAutoString utf16; +#ifdef IDNA2008 + nsresult result = IDNA2008ToUnicode(in, utf16); + NS_ENSURE_SUCCESS(result, result); +#else + // RFC 3490 - 4.2 ToUnicode + // The ToUnicode output never contains more code points than its input. + punycode_uint output_length = in.Length() - kACEPrefixLen + 1; + auto *output = new punycode_uint[output_length]; + NS_ENSURE_TRUE(output, NS_ERROR_OUT_OF_MEMORY); + + enum punycode_status status = punycode_decode(in.Length() - kACEPrefixLen, + PromiseFlatCString(in).get() + kACEPrefixLen, + &output_length, + output, + nullptr); + if (status != punycode_success) { + delete [] output; + return NS_ERROR_MALFORMED_URI; + } + + // UCS4 -> UTF8 + output[output_length] = 0; + ucs4toUtf16(output, utf16); + delete [] output; +#endif + if (flag != eStringPrepForUI || isLabelSafe(utf16)) { + CopyUTF16toUTF8(utf16, out); + } else { + out.Assign(in); + return NS_OK; + } + + // Validation: encode back to ACE and compare the strings + nsAutoCString ace; + nsresult rv = UTF8toACE(out, ace, flag); + NS_ENSURE_SUCCESS(rv, rv); + + if (flag == eStringPrepForDNS && + !ace.Equals(in, nsCaseInsensitiveCStringComparator())) { + return NS_ERROR_MALFORMED_URI; + } + + return NS_OK; +} + +bool nsIDNService::isInWhitelist(const nsACString &host) +{ + if (mIDNUseWhitelist && mIDNWhitelistPrefBranch) { + nsAutoCString tld(host); + // make sure the host is ACE for lookup and check that there are no + // unassigned codepoints + if (!IsASCII(tld) && NS_FAILED(UTF8toACE(tld, tld, eStringPrepForDNS))) { + return false; + } + + // truncate trailing dots first + tld.Trim("."); + int32_t pos = tld.RFind("."); + if (pos == kNotFound) + return false; + + tld.Cut(0, pos + 1); + + bool safe; + if (NS_SUCCEEDED(mIDNWhitelistPrefBranch->GetBoolPref(tld.get(), &safe))) + return safe; + } + + return false; +} + +bool nsIDNService::isLabelSafe(const nsAString &label) +{ + if (!isOnlySafeChars(PromiseFlatString(label), mIDNBlacklist)) { + return false; + } + + // We should never get here if the label is ASCII + NS_ASSERTION(!IsASCII(label), "ASCII label in IDN checking"); + if (mRestrictionProfile == eASCIIOnlyProfile) { + return false; + } + + nsAString::const_iterator current, end; + label.BeginReading(current); + label.EndReading(end); + + Script lastScript = Script::INVALID; + uint32_t previousChar = 0; + uint32_t savedNumberingSystem = 0; +// Simplified/Traditional Chinese check temporarily disabled -- bug 857481 +#if 0 + HanVariantType savedHanVariant = HVT_NotHan; +#endif + + int32_t savedScript = -1; + + while (current != end) { + uint32_t ch = *current++; + + if (NS_IS_HIGH_SURROGATE(ch) && current != end && + NS_IS_LOW_SURROGATE(*current)) { + ch = SURROGATE_TO_UCS4(ch, *current++); + } + + // Check for restricted characters; aspirational scripts are NOT permitted, + // in anticipation of the category being merged into Limited-Use scripts + // in the upcoming (Unicode 10.0-based) revision of UAX #31. + XidmodType xm = GetIdentifierModification(ch); + if (xm != XIDMOD_RECOMMENDED && + xm != XIDMOD_INCLUSION) { + return false; + } + + // Check for mixed script + Script script = GetScriptCode(ch); + if (script != Script::COMMON && + script != Script::INHERITED && + script != lastScript) { + if (illegalScriptCombo(script, savedScript)) { + return false; + } + lastScript = script; + } + + // Check for mixed numbering systems + if (GetGeneralCategory(ch) == + HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) { + uint32_t zeroCharacter = ch - GetNumericValue(ch); + if (savedNumberingSystem == 0) { + // If we encounter a decimal number, save the zero character from that + // numbering system. + savedNumberingSystem = zeroCharacter; + } else if (zeroCharacter != savedNumberingSystem) { + return false; + } + } + + // Check for consecutive non-spacing marks + if (previousChar != 0 && + previousChar == ch && + GetGeneralCategory(ch) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) { + return false; + } + + // Simplified/Traditional Chinese check temporarily disabled -- bug 857481 +#if 0 + + // Check for both simplified-only and traditional-only Chinese characters + HanVariantType hanVariant = GetHanVariant(ch); + if (hanVariant == HVT_SimplifiedOnly || hanVariant == HVT_TraditionalOnly) { + if (savedHanVariant == HVT_NotHan) { + savedHanVariant = hanVariant; + } else if (hanVariant != savedHanVariant) { + return false; + } + } +#endif + + previousChar = ch; + } + return true; +} + +// Scripts that we care about in illegalScriptCombo +static const Script scriptTable[] = { + Script::BOPOMOFO, Script::CYRILLIC, Script::GREEK, + Script::HANGUL, Script::HAN, Script::HIRAGANA, + Script::KATAKANA, Script::LATIN }; + +#define BOPO 0 +#define CYRL 1 +#define GREK 2 +#define HANG 3 +#define HANI 4 +#define HIRA 5 +#define KATA 6 +#define LATN 7 +#define OTHR 8 +#define JPAN 9 // Latin + Han + Hiragana + Katakana +#define CHNA 10 // Latin + Han + Bopomofo +#define KORE 11 // Latin + Han + Hangul +#define HNLT 12 // Latin + Han (could be any of the above combinations) +#define FAIL 13 + +static inline int32_t findScriptIndex(Script aScript) +{ + int32_t tableLength = sizeof(scriptTable) / sizeof(int32_t); + for (int32_t index = 0; index < tableLength; ++index) { + if (aScript == scriptTable[index]) { + return index; + } + } + return OTHR; +} + +static const int32_t scriptComboTable[13][9] = { +/* thisScript: BOPO CYRL GREK HANG HANI HIRA KATA LATN OTHR + * savedScript */ + /* BOPO */ { BOPO, FAIL, FAIL, FAIL, CHNA, FAIL, FAIL, CHNA, FAIL }, + /* CYRL */ { FAIL, CYRL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL }, + /* GREK */ { FAIL, FAIL, GREK, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL }, + /* HANG */ { FAIL, FAIL, FAIL, HANG, KORE, FAIL, FAIL, KORE, FAIL }, + /* HANI */ { CHNA, FAIL, FAIL, KORE, HANI, JPAN, JPAN, HNLT, FAIL }, + /* HIRA */ { FAIL, FAIL, FAIL, FAIL, JPAN, HIRA, JPAN, JPAN, FAIL }, + /* KATA */ { FAIL, FAIL, FAIL, FAIL, JPAN, JPAN, KATA, JPAN, FAIL }, + /* LATN */ { CHNA, FAIL, FAIL, KORE, HNLT, JPAN, JPAN, LATN, OTHR }, + /* OTHR */ { FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, OTHR, FAIL }, + /* JPAN */ { FAIL, FAIL, FAIL, FAIL, JPAN, JPAN, JPAN, JPAN, FAIL }, + /* CHNA */ { CHNA, FAIL, FAIL, FAIL, CHNA, FAIL, FAIL, CHNA, FAIL }, + /* KORE */ { FAIL, FAIL, FAIL, KORE, KORE, FAIL, FAIL, KORE, FAIL }, + /* HNLT */ { CHNA, FAIL, FAIL, KORE, HNLT, JPAN, JPAN, HNLT, FAIL } +}; + +bool nsIDNService::illegalScriptCombo(Script script, int32_t& savedScript) +{ + if (savedScript == -1) { + savedScript = findScriptIndex(script); + return false; + } + + savedScript = scriptComboTable[savedScript] [findScriptIndex(script)]; + /* + * Special case combinations that depend on which profile is in use + * In the Highly Restrictive profile Latin is not allowed with any + * other script + * + * In the Moderately Restrictive profile Latin mixed with any other + * single script is allowed. + */ + return ((savedScript == OTHR && + mRestrictionProfile == eHighlyRestrictiveProfile) || + savedScript == FAIL); +} + +#undef BOPO +#undef CYRL +#undef GREK +#undef HANG +#undef HANI +#undef HIRA +#undef KATA +#undef LATN +#undef OTHR +#undef JPAN +#undef CHNA +#undef KORE +#undef HNLT +#undef FAIL diff --git a/netwerk/dns/nsIDNService.h b/netwerk/dns/nsIDNService.h new file mode 100644 index 000000000..19aa94da0 --- /dev/null +++ b/netwerk/dns/nsIDNService.h @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 2; 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 nsIDNService_h__ +#define nsIDNService_h__ + +#include "nsIIDNService.h" +#include "nsCOMPtr.h" +#include "nsIObserver.h" +#include "nsUnicodeScriptCodes.h" +#include "nsWeakReference.h" + +#ifdef IDNA2008 +#include "unicode/uidna.h" +#else +#include "nsIUnicodeNormalizer.h" +#include "nsIDNKitInterface.h" +#endif + +#include "nsString.h" + +class nsIPrefBranch; + +//----------------------------------------------------------------------------- +// nsIDNService +//----------------------------------------------------------------------------- + +class nsIDNService final : public nsIIDNService, + public nsIObserver, + public nsSupportsWeakReference +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIDNSERVICE + NS_DECL_NSIOBSERVER + + nsIDNService(); + + nsresult Init(); + +protected: + virtual ~nsIDNService(); + +private: + enum stringPrepFlag { + eStringPrepForDNS, + eStringPrepForUI, + eStringPrepIgnoreErrors + }; + + /** + * Convert the following characters that must be recognized as label + * separators per RFC 3490 to ASCII full stop characters + * + * U+3002 (ideographic full stop) + * U+FF0E (fullwidth full stop) + * U+FF61 (halfwidth ideographic full stop) + */ + void normalizeFullStops(nsAString& s); + + /** + * Convert and encode a DNS label in ACE/punycode. + * @param flag + * if eStringPrepIgnoreErrors, all non-ASCII labels are + * converted to punycode. + * if eStringPrepForUI, only labels that are considered safe + * for display are converted. + * @see isLabelSafe + * if eStringPrepForDNS and stringPrep finds an illegal + * character, returns NS_FAILURE and out is empty + */ + nsresult stringPrepAndACE(const nsAString& in, nsACString& out, + stringPrepFlag flag); + + /** + * Convert a DNS label using the stringprep profile defined in RFC 3454 + */ + nsresult stringPrep(const nsAString& in, nsAString& out, stringPrepFlag flag); + + /** + * Decode an ACE-encoded DNS label to UTF-8 + * + * @param flag + * if eStringPrepForUI and the label is not considered safe to + * display, the output is the same as the input + * @see isLabelSafe + */ + nsresult decodeACE(const nsACString& in, nsACString& out, + stringPrepFlag flag); + + /** + * Convert complete domain names between UTF8 and ACE and vice versa + * + * @param flag is passed to decodeACE or stringPrepAndACE for each + * label individually, so the output may contain some labels in + * punycode and some in UTF-8 + */ + nsresult UTF8toACE(const nsACString& input, nsACString& ace, + stringPrepFlag flag); + nsresult ACEtoUTF8(const nsACString& input, nsACString& _retval, + stringPrepFlag flag); + + bool isInWhitelist(const nsACString &host); + void prefsChanged(nsIPrefBranch *prefBranch, const char16_t *pref); + + /** + * Determine whether a label is considered safe to display to the user + * according to the algorithm defined in UTR 39 and the profile + * selected in mRestrictionProfile. + * + * For the ASCII-only profile, returns false for all labels containing + * non-ASCII characters. + * + * For the other profiles, returns false for labels containing any of + * the following: + * + * Characters in scripts other than the "recommended scripts" and + * "aspirational scripts" defined in + * http://www.unicode.org/reports/tr31/#Table_Recommended_Scripts + * and http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts + * This includes codepoints that are not defined as Unicode + * characters + * + * Illegal combinations of scripts (@see illegalScriptCombo) + * + * Numbers from more than one different numbering system + * + * Sequences of the same non-spacing mark + * + * Both simplified-only and traditional-only Chinese characters + * XXX this test was disabled by bug 857481 + */ + bool isLabelSafe(const nsAString &label); + + /** + * Determine whether a combination of scripts in a single label is + * permitted according to the algorithm defined in UTR 39 and the + * profile selected in mRestrictionProfile. + * + * For the "Highly restrictive" profile, all characters in each + * identifier must be from a single script, or from the combinations: + * Latin + Han + Hiragana + Katakana; + * Latin + Han + Bopomofo; or + * Latin + Han + Hangul + * + * For the "Moderately restrictive" profile, Latin is also allowed + * with other scripts except Cyrillic and Greek + */ + bool illegalScriptCombo(mozilla::unicode::Script script, + int32_t& savedScript); + +#ifdef IDNA2008 + /** + * Convert a DNS label from ASCII to Unicode using IDNA2008 + */ + nsresult IDNA2008ToUnicode(const nsACString& input, nsAString& output); + + /** + * Convert a DNS label to a normalized form conforming to IDNA2008 + */ + nsresult IDNA2008StringPrep(const nsAString& input, nsAString& output, + stringPrepFlag flag); + + UIDNA* mIDNA; +#else + idn_nameprep_t mNamePrepHandle; + nsCOMPtr mNormalizer; +#endif + nsXPIDLString mIDNBlacklist; + + /** + * Flag set by the pref network.IDN_show_punycode. When it is true, + * IDNs containing non-ASCII characters are always displayed to the + * user in punycode + */ + bool mShowPunycode; + + /** + * Restriction-level Detection profiles defined in UTR 39 + * http://www.unicode.org/reports/tr39/#Restriction_Level_Detection, + * and selected by the pref network.IDN.restriction_profile + */ + enum restrictionProfile { + eASCIIOnlyProfile, + eHighlyRestrictiveProfile, + eModeratelyRestrictiveProfile + }; + restrictionProfile mRestrictionProfile; + nsCOMPtr mIDNWhitelistPrefBranch; + bool mIDNUseWhitelist; +}; + +#endif // nsIDNService_h__ diff --git a/netwerk/dns/nsIEffectiveTLDService.idl b/netwerk/dns/nsIEffectiveTLDService.idl new file mode 100644 index 000000000..adfbae8a0 --- /dev/null +++ b/netwerk/dns/nsIEffectiveTLDService.idl @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "nsISupports.idl" + +interface nsIURI; + +[scriptable, uuid(68067eb5-ad8d-43cb-a043-1cc85ebe06e7)] +interface nsIEffectiveTLDService : nsISupports +{ + /** + * Returns the public suffix of a URI. A public suffix is the highest-level domain + * under which individual domains may be registered; it may therefore contain one + * or more dots. For example, the public suffix for "www.bbc.co.uk" is "co.uk", + * because the .uk TLD does not allow the registration of domains at the + * second level ("bbc.uk" is forbidden). + * + * The public suffix will be returned encoded in ASCII/ACE and will be normalized + * according to RFC 3454, i.e. the same encoding returned by nsIURI::GetAsciiHost(). + * If consumers wish to compare the result of this method against the host from + * another nsIURI, the host should be obtained using nsIURI::GetAsciiHost(). + * In the case of nested URIs, the innermost URI will be used. + * + * @param aURI The URI to be analyzed + * + * @returns the public suffix + * + * @throws NS_ERROR_UNEXPECTED + * or other error returned by nsIIDNService::normalize when + * the hostname contains characters disallowed in URIs + * @throws NS_ERROR_HOST_IS_IP_ADDRESS + * if the host is a numeric IPv4 or IPv6 address (as determined by + * the success of a call to PR_StringToNetAddr()). + */ + ACString getPublicSuffix(in nsIURI aURI); + + /** + * Returns the base domain of a URI; that is, the public suffix with a given + * number of additional domain name parts. For example, the result of this method + * for "www.bbc.co.uk", depending on the value of aAdditionalParts parameter, will + * be: + * + * 0 (default) -> bbc.co.uk + * 1 -> www.bbc.co.uk + * + * Similarly, the public suffix for "www.developer.mozilla.org" is "org", and the base + * domain will be: + * + * 0 (default) -> mozilla.org + * 1 -> developer.mozilla.org + * 2 -> www.developer.mozilla.org + * + * The base domain will be returned encoded in ASCII/ACE and will be normalized + * according to RFC 3454, i.e. the same encoding returned by nsIURI::GetAsciiHost(). + * If consumers wish to compare the result of this method against the host from + * another nsIURI, the host should be obtained using nsIURI::GetAsciiHost(). + * In the case of nested URIs, the innermost URI will be used. + * + * @param aURI The URI to be analyzed + * @param aAdditionalParts Number of domain name parts to be + * returned in addition to the public suffix + * + * @returns the base domain (public suffix plus the requested number of additional parts) + * + * @throws NS_ERROR_UNEXPECTED + * or other error returned by nsIIDNService::normalize when + * the hostname contains characters disallowed in URIs + * @throws NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS + * when there are insufficient subdomain levels in the hostname to satisfy the + * requested aAdditionalParts value. + * @throws NS_ERROR_HOST_IS_IP_ADDRESS + * if aHost is a numeric IPv4 or IPv6 address (as determined by + * the success of a call to PR_StringToNetAddr()). + * + * @see getPublicSuffix() + */ + ACString getBaseDomain(in nsIURI aURI, [optional] in uint32_t aAdditionalParts); + + /** + * NOTE: It is strongly recommended to use getPublicSuffix() above if a suitable + * nsIURI is available. Only use this method if this is not the case. + * + * Returns the public suffix of a host string. Otherwise identical to getPublicSuffix(). + * + * @param aHost The host to be analyzed. Any additional parts (e.g. scheme, + * port, or path) will cause this method to throw. ASCII/ACE and + * UTF8 encodings are acceptable as input; normalization will + * be performed as specified in getBaseDomain(). + * + * @see getPublicSuffix() + */ + ACString getPublicSuffixFromHost(in AUTF8String aHost); + + /** + * NOTE: It is strongly recommended to use getBaseDomain() above if a suitable + * nsIURI is available. Only use this method if this is not the case. + * + * Returns the base domain of a host string. Otherwise identical to getBaseDomain(). + * + * @param aHost The host to be analyzed. Any additional parts (e.g. scheme, + * port, or path) will cause this method to throw. ASCII/ACE and + * UTF8 encodings are acceptable as input; normalization will + * be performed as specified in getBaseDomain(). + * + * @see getBaseDomain() + */ + ACString getBaseDomainFromHost(in AUTF8String aHost, [optional] in uint32_t aAdditionalParts); + + /** + * Returns the parent sub-domain of a host string. If the host is a base + * domain, it will throw NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS. + * + * For example: "player.bbc.co.uk" would return "bbc.co.uk" and + * "bbc.co.uk" would throw NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS. + * + * @param aHost The host to be analyzed. Any additional parts (e.g. scheme, + * port, or path) will cause this method to throw. ASCII/ACE and + * UTF8 encodings are acceptable as input; normalization will + * be performed as specified in getBaseDomain(). + */ + ACString getNextSubDomain(in AUTF8String aHost); +}; + diff --git a/netwerk/dns/nsIIDNService.idl b/netwerk/dns/nsIIDNService.idl new file mode 100644 index 000000000..47ef56123 --- /dev/null +++ b/netwerk/dns/nsIIDNService.idl @@ -0,0 +1,58 @@ +/* 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/. */ + +#include "nsISupports.idl" + +/** + * nsIIDNService interface. + * + * IDN (Internationalized Domain Name) support. Provides facilities + * for manipulating IDN hostnames according to the specification set + * forth by the IETF. + * + * IDN effort: + * http://www.ietf.org/html.characters/idn-charter.html + * http://www.i-dns.net + * + * IDNA specification: + * http://search.ietf.org/internet-drafts/draft-ietf-idn-idna-06.txt + */ + +[scriptable, uuid(a592a60e-3621-4f19-a318-2bf233cfad3e)] +interface nsIIDNService : nsISupports +{ + /** + * Prepares the input hostname according to IDNA ToASCII operation, + * the input hostname is assumed to be UTF8-encoded. + */ + ACString convertUTF8toACE(in AUTF8String input); + + + /** + * This is the ToUnicode operation as specified in the IDNA proposal, + * with an additional step to encode the result in UTF-8. + * It takes an ACE-encoded hostname and performs ToUnicode to it, then + * encodes the resulting string into UTF8. + */ + AUTF8String convertACEtoUTF8(in ACString input); + + /** + * Checks if the input string is ACE encoded or not. + */ + boolean isACE(in ACString input); + + /** + * Performs the unicode normalization needed for hostnames in IDN, + * for callers that want early normalization. + */ + AUTF8String normalize(in AUTF8String input); + + /** + * Normalizes and converts a host to UTF-8 if the host is in the IDN + * whitelist, otherwise converts it to ACE. This is useful for display + * purposes and to ensure an encoding consistent with nsIURI::GetHost(). + * If the result is ASCII or ACE encoded, |isASCII| will be true. + */ + AUTF8String convertToDisplayIDN(in AUTF8String input, out boolean isASCII); +}; diff --git a/netwerk/dns/nsPIDNSService.idl b/netwerk/dns/nsPIDNSService.idl new file mode 100644 index 000000000..9bed0555c --- /dev/null +++ b/netwerk/dns/nsPIDNSService.idl @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#include "nsIDNSService.idl" + +/** + * This is a private interface used by the internals of the networking library. + * It will never be frozen. Do not use it in external code. + */ +[scriptable, uuid(24e598fd-7b1a-436c-9154-14d8b38df8a5)] +interface nsPIDNSService : nsIDNSService +{ + /** + * called to initialize the DNS service. + */ + void init(); + + /** + * called to shutdown the DNS service. any pending asynchronous + * requests will be canceled, and the local cache of DNS records + * will be cleared. NOTE: the operating system may still have + * its own cache of DNS records, which would be unaffected by + * this method. + */ + void shutdown(); + + /** + * Whether or not DNS prefetching (aka RESOLVE_SPECULATE) is enabled + */ + attribute boolean prefetchEnabled; +}; diff --git a/netwerk/dns/prepare_tlds.py b/netwerk/dns/prepare_tlds.py new file mode 100644 index 000000000..a97b20948 --- /dev/null +++ b/netwerk/dns/prepare_tlds.py @@ -0,0 +1,121 @@ +# 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/. + +import codecs +import encodings.idna +import re +import sys + +""" +Processes a file containing effective TLD data. See the following URL for a +description of effective TLDs and of the file format that this script +processes (although for the latter you're better off just reading this file's +short source code). + +http://wiki.mozilla.org/Gecko:Effective_TLD_Service +""" + +def getEffectiveTLDs(path): + file = codecs.open(path, "r", "UTF-8") + entries = [] + domains = set() + for line in file: + # line always contains a line terminator unless the file is empty + if len(line) == 0: + raise StopIteration + line = line.rstrip() + # comment, empty, or superfluous line for explicitness purposes + if line.startswith("//") or "." not in line: + continue + line = re.split(r"[ \t\n]", line, 1)[0] + entry = EffectiveTLDEntry(line) + domain = entry.domain() + assert domain not in domains, \ + "repeating domain %s makes no sense" % domain + domains.add(domain) + entries.append(entry) + + # Sort the entries so we can use binary search on them. + entries.sort(key=EffectiveTLDEntry.domain) + + return entries + +def _normalizeHostname(domain): + """ + Normalizes the given domain, component by component. ASCII components are + lowercased, while non-ASCII components are processed using the ToASCII + algorithm. + """ + def convertLabel(label): + if _isASCII(label): + return label.lower() + return encodings.idna.ToASCII(label) + return ".".join(map(convertLabel, domain.split("."))) + +def _isASCII(s): + "True if s consists entirely of ASCII characters, false otherwise." + for c in s: + if ord(c) > 127: + return False + return True + +class EffectiveTLDEntry: + """ + Stores an entry in an effective-TLD name file. + """ + + _exception = False + _wild = False + + def __init__(self, line): + """ + Creates a TLD entry from a line of data, which must have been stripped of + the line ending. + """ + if line.startswith("!"): + self._exception = True + domain = line[1:] + elif line.startswith("*."): + self._wild = True + domain = line[2:] + else: + domain = line + self._domain = _normalizeHostname(domain) + + def domain(self): + "The domain this represents." + return self._domain + + def exception(self): + "True if this entry's domain denotes does not denote an effective TLD." + return self._exception + + def wild(self): + "True if this entry represents a class of effective TLDs." + return self._wild + + +################# +# DO EVERYTHING # +################# + +def main(output, effective_tld_filename): + """ + effective_tld_filename is the effective TLD file to parse. + A C++ array of { domain, exception, wild } entries representing the + eTLD file is then printed to output. + """ + + def boolStr(b): + if b: + return "true" + return "false" + + for etld in getEffectiveTLDs(effective_tld_filename): + exception = boolStr(etld.exception()) + wild = boolStr(etld.wild()) + output.write('ETLD_ENTRY("%s", %s, %s)\n' % (etld.domain(), exception, wild)) + +if __name__ == '__main__': + main(sys.stdout, sys.argv[1]) diff --git a/netwerk/dns/punycode.c b/netwerk/dns/punycode.c new file mode 100644 index 000000000..f905e5272 --- /dev/null +++ b/netwerk/dns/punycode.c @@ -0,0 +1,289 @@ +/* +punycode.c from RFC 3492 +http://www.nicemice.net/idn/ +Adam M. Costello +http://www.nicemice.net/amc/ + +This is ANSI C code (C89) implementing Punycode (RFC 3492). + + +C. Disclaimer and license + + Regarding this entire document or any portion of it (including + the pseudocode and C code), the author makes no guarantees and + is not responsible for any damage resulting from its use. The + author grants irrevocable permission to anyone to use, modify, + and distribute it in any way that does not diminish the rights + of anyone else to use, modify, and distribute it, provided that + redistributed derivative works do not contain misleading author or + version information. Derivative works need not be licensed under + similar terms. +*/ + +#include "punycode.h" + +/**********************************************************/ +/* Implementation (would normally go in its own .c file): */ + +#include + +/*** Bootstring parameters for Punycode ***/ + +enum { base = 36, tmin = 1, tmax = 26, skew = 38, damp = 700, + initial_bias = 72, initial_n = 0x80, delimiter = 0x2D }; + +/* basic(cp) tests whether cp is a basic code point: */ +#define basic(cp) ((punycode_uint)(cp) < 0x80) + +/* delim(cp) tests whether cp is a delimiter: */ +#define delim(cp) ((cp) == delimiter) + +/* decode_digit(cp) returns the numeric value of a basic code */ +/* point (for use in representing integers) in the range 0 to */ +/* base-1, or base if cp is does not represent a value. */ + +static punycode_uint decode_digit(punycode_uint cp) +{ + return cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 : + cp - 97 < 26 ? cp - 97 : base; +} + +/* encode_digit(d,flag) returns the basic code point whose value */ +/* (when used for representing integers) is d, which needs to be in */ +/* the range 0 to base-1. The lowercase form is used unless flag is */ +/* nonzero, in which case the uppercase form is used. The behavior */ +/* is undefined if flag is nonzero and digit d has no uppercase form. */ + +static char encode_digit(punycode_uint d, int flag) +{ + return d + 22 + 75 * (d < 26) - ((flag != 0) << 5); + /* 0..25 map to ASCII a..z or A..Z */ + /* 26..35 map to ASCII 0..9 */ +} + +/* flagged(bcp) tests whether a basic code point is flagged */ +/* (uppercase). The behavior is undefined if bcp is not a */ +/* basic code point. */ + +#define flagged(bcp) ((punycode_uint)(bcp) - 65 < 26) + +/* encode_basic(bcp,flag) forces a basic code point to lowercase */ +/* if flag is zero, uppercase if flag is nonzero, and returns */ +/* the resulting code point. The code point is unchanged if it */ +/* is caseless. The behavior is undefined if bcp is not a basic */ +/* code point. */ + +static char encode_basic(punycode_uint bcp, int flag) +{ + bcp -= (bcp - 97 < 26) << 5; + return bcp + ((!flag && (bcp - 65 < 26)) << 5); +} + +/*** Platform-specific constants ***/ + +/* maxint is the maximum value of a punycode_uint variable: */ +static const punycode_uint maxint = (punycode_uint) -1; +/* Because maxint is unsigned, -1 becomes the maximum value. */ + +/*** Bias adaptation function ***/ + +static punycode_uint adapt( + punycode_uint delta, punycode_uint numpoints, int firsttime ) +{ + punycode_uint k; + + delta = firsttime ? delta / damp : delta >> 1; + /* delta >> 1 is a faster way of doing delta / 2 */ + delta += delta / numpoints; + + for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) { + delta /= base - tmin; + } + + return k + (base - tmin + 1) * delta / (delta + skew); +} + +/*** Main encode function ***/ + +enum punycode_status punycode_encode( + punycode_uint input_length, + const punycode_uint input[], + const unsigned char case_flags[], + punycode_uint *output_length, + char output[] ) +{ + punycode_uint n, delta, h, b, out, max_out, bias, j, m, q, k, t; + + /* Initialize the state: */ + + n = initial_n; + delta = out = 0; + max_out = *output_length; + bias = initial_bias; + + /* Handle the basic code points: */ + + for (j = 0; j < input_length; ++j) { + if (basic(input[j])) { + if (max_out - out < 2) return punycode_big_output; + output[out++] = + case_flags ? encode_basic(input[j], case_flags[j]) : (char)input[j]; + } + /* else if (input[j] < n) return punycode_bad_input; */ + /* (not needed for Punycode with unsigned code points) */ + } + + h = b = out; + + /* h is the number of code points that have been handled, b is the */ + /* number of basic code points, and out is the number of characters */ + /* that have been output. */ + + if (b > 0) output[out++] = delimiter; + + /* Main encoding loop: */ + + while (h < input_length) { + /* All non-basic code points < n have been */ + /* handled already. Find the next larger one: */ + + for (m = maxint, j = 0; j < input_length; ++j) { + /* if (basic(input[j])) continue; */ + /* (not needed for Punycode) */ + if (input[j] >= n && input[j] < m) m = input[j]; + } + + /* Increase delta enough to advance the decoder's */ + /* state to , but guard against overflow: */ + + if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow; + delta += (m - n) * (h + 1); + n = m; + + for (j = 0; j < input_length; ++j) { + /* Punycode does not need to check whether input[j] is basic: */ + if (input[j] < n /* || basic(input[j]) */ ) { + if (++delta == 0) return punycode_overflow; + } + + if (input[j] == n) { + /* Represent delta as a generalized variable-length integer: */ + + for (q = delta, k = base; ; k += base) { + if (out >= max_out) return punycode_big_output; + t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */ + k >= bias + tmax ? tmax : k - bias; + if (q < t) break; + output[out++] = encode_digit(t + (q - t) % (base - t), 0); + q = (q - t) / (base - t); + } + + output[out++] = encode_digit(q, case_flags && case_flags[j]); + bias = adapt(delta, h + 1, h == b); + delta = 0; + ++h; + } + } + + ++delta, ++n; + } + + *output_length = out; + return punycode_success; +} + +/*** Main decode function ***/ + +enum punycode_status punycode_decode( + punycode_uint input_length, + const char input[], + punycode_uint *output_length, + punycode_uint output[], + unsigned char case_flags[] ) +{ + punycode_uint n, out, i, max_out, bias, + b, j, in, oldi, w, k, digit, t; + + if (!input_length) { + return punycode_bad_input; + } + + /* Initialize the state: */ + + n = initial_n; + out = i = 0; + max_out = *output_length; + bias = initial_bias; + + /* Handle the basic code points: Let b be the number of input code */ + /* points before the last delimiter, or 0 if there is none, then */ + /* copy the first b code points to the output. */ + + for (b = 0, j = input_length - 1 ; j > 0; --j) { + if (delim(input[j])) { + b = j; + break; + } + } + if (b > max_out) return punycode_big_output; + + for (j = 0; j < b; ++j) { + if (case_flags) case_flags[out] = flagged(input[j]); + if (!basic(input[j])) return punycode_bad_input; + output[out++] = input[j]; + } + + /* Main decoding loop: Start just after the last delimiter if any */ + /* basic code points were copied; start at the beginning otherwise. */ + + for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) { + + /* in is the index of the next character to be consumed, and */ + /* out is the number of code points in the output array. */ + + /* Decode a generalized variable-length integer into delta, */ + /* which gets added to i. The overflow checking is easier */ + /* if we increase i as we go, then subtract off its starting */ + /* value at the end to obtain delta. */ + + for (oldi = i, w = 1, k = base; ; k += base) { + if (in >= input_length) return punycode_bad_input; + digit = decode_digit(input[in++]); + if (digit >= base) return punycode_bad_input; + if (digit > (maxint - i) / w) return punycode_overflow; + i += digit * w; + t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */ + k >= bias + tmax ? tmax : k - bias; + if (digit < t) break; + if (w > maxint / (base - t)) return punycode_overflow; + w *= (base - t); + } + + bias = adapt(i - oldi, out + 1, oldi == 0); + + /* i was supposed to wrap around from out+1 to 0, */ + /* incrementing n each time, so we'll fix that now: */ + + if (i / (out + 1) > maxint - n) return punycode_overflow; + n += i / (out + 1); + i %= (out + 1); + + /* Insert n at position i of the output: */ + + /* not needed for Punycode: */ + /* if (decode_digit(n) <= base) return punycode_invalid_input; */ + if (out >= max_out) return punycode_big_output; + + if (case_flags) { + memmove(case_flags + i + 1, case_flags + i, out - i); + /* Case of last character determines uppercase flag: */ + case_flags[i] = flagged(input[in - 1]); + } + + memmove(output + i + 1, output + i, (out - i) * sizeof *output); + output[i++] = n; + } + + *output_length = out; + return punycode_success; +} diff --git a/netwerk/dns/punycode.h b/netwerk/dns/punycode.h new file mode 100644 index 000000000..459c6fd75 --- /dev/null +++ b/netwerk/dns/punycode.h @@ -0,0 +1,108 @@ +/* +punycode.c from RFC 3492 +http://www.nicemice.net/idn/ +Adam M. Costello +http://www.nicemice.net/amc/ + +This is ANSI C code (C89) implementing Punycode (RFC 3492). + + + +C. Disclaimer and license + + Regarding this entire document or any portion of it (including + the pseudocode and C code), the author makes no guarantees and + is not responsible for any damage resulting from its use. The + author grants irrevocable permission to anyone to use, modify, + and distribute it in any way that does not diminish the rights + of anyone else to use, modify, and distribute it, provided that + redistributed derivative works do not contain misleading author or + version information. Derivative works need not be licensed under + similar terms. +*/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/************************************************************/ +/* Public interface (would normally go in its own .h file): */ + +#include + +enum punycode_status { + punycode_success, + punycode_bad_input, /* Input is invalid. */ + punycode_big_output, /* Output would exceed the space provided. */ + punycode_overflow /* Input needs wider integers to process. */ +}; + +#if UINT_MAX >= (1 << 26) - 1 +typedef unsigned int punycode_uint; +#else +typedef unsigned long punycode_uint; +#endif + +enum punycode_status punycode_encode( + punycode_uint input_length, + const punycode_uint input[], + const unsigned char case_flags[], + punycode_uint *output_length, + char output[] ); + + /* punycode_encode() converts Unicode to Punycode. The input */ + /* is represented as an array of Unicode code points (not code */ + /* units; surrogate pairs are not allowed), and the output */ + /* will be represented as an array of ASCII code points. The */ + /* output string is *not* null-terminated; it will contain */ + /* zeros if and only if the input contains zeros. (Of course */ + /* the caller can leave room for a terminator and add one if */ + /* needed.) The input_length is the number of code points in */ + /* the input. The output_length is an in/out argument: the */ + /* caller passes in the maximum number of code points that it */ + /* can receive, and on successful return it will contain the */ + /* number of code points actually output. The case_flags array */ + /* holds input_length boolean values, where nonzero suggests that */ + /* the corresponding Unicode character be forced to uppercase */ + /* after being decoded (if possible), and zero suggests that */ + /* it be forced to lowercase (if possible). ASCII code points */ + /* are encoded literally, except that ASCII letters are forced */ + /* to uppercase or lowercase according to the corresponding */ + /* uppercase flags. If case_flags is a null pointer then ASCII */ + /* letters are left as they are, and other code points are */ + /* treated as if their uppercase flags were zero. The return */ + /* value can be any of the punycode_status values defined above */ + /* except punycode_bad_input; if not punycode_success, then */ + /* output_size and output might contain garbage. */ + +enum punycode_status punycode_decode( + punycode_uint input_length, + const char input[], + punycode_uint *output_length, + punycode_uint output[], + unsigned char case_flags[] ); + + /* punycode_decode() converts Punycode to Unicode. The input is */ + /* represented as an array of ASCII code points, and the output */ + /* will be represented as an array of Unicode code points. The */ + /* input_length is the number of code points in the input. The */ + /* output_length is an in/out argument: the caller passes in */ + /* the maximum number of code points that it can receive, and */ + /* on successful return it will contain the actual number of */ + /* code points output. The case_flags array needs room for at */ + /* least output_length values, or it can be a null pointer if the */ + /* case information is not needed. A nonzero flag suggests that */ + /* the corresponding Unicode character be forced to uppercase */ + /* by the caller (if possible), while zero suggests that it be */ + /* forced to lowercase (if possible). ASCII code points are */ + /* output already in the proper case, but their flags will be set */ + /* appropriately so that applying the flags would be harmless. */ + /* The return value can be any of the punycode_status values */ + /* defined above; if not punycode_success, then output_length, */ + /* output, and case_flags might contain garbage. On success, the */ + /* decoder will never need to write an output_length greater than */ + /* input_length, because of how the encoding is defined. */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ -- cgit v1.2.3