Support resolution of IPv6 STUN/TURN addresses
https://bugs.webkit.org/show_bug.cgi?id=209808

Reviewed by Eric Carlson.

Source/WebCore:

Add family access to IPAddress to support both IPv4 and IPv6.
Store IPAddress internal value as IPv6 and cast them to IPv4 on demand.

* platform/network/DNS.h:
* platform/network/soup/DNSResolveQueueSoup.cpp:
(WebCore::resolvedWithObserverCallback):

Source/WebKit:

Update code to support IPv6 addresses when doing DNS resolution of TURN/STUN servers.
Refactor code to share more code between Cocoa ports and non Cocoa ports.
Manually tested with external IPv6 TURN servers.

* NetworkProcess/webrtc/NetworkRTCProvider.cpp:
(WebKit::NetworkRTCProvider::createResolver):
* NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp:
(WebKit::resolvedName):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@259338 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 6276b96..001be76 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,17 @@
+2020-04-01  youenn fablet  <youenn@apple.com>
+
+        Support resolution of IPv6 STUN/TURN addresses
+        https://bugs.webkit.org/show_bug.cgi?id=209808
+
+        Reviewed by Eric Carlson.
+
+        Add family access to IPAddress to support both IPv4 and IPv6.
+        Store IPAddress internal value as IPv6 and cast them to IPv4 on demand.
+
+        * platform/network/DNS.h:
+        * platform/network/soup/DNSResolveQueueSoup.cpp:
+        (WebCore::resolvedWithObserverCallback):
+
 2020-03-31  Simon Fraser  <simon.fraser@apple.com>
 
         Make FrameView and Frame TextStream-loggable
diff --git a/Source/WebCore/platform/network/DNS.h b/Source/WebCore/platform/network/DNS.h
index bae4a2d..e63a7b0 100644
--- a/Source/WebCore/platform/network/DNS.h
+++ b/Source/WebCore/platform/network/DNS.h
@@ -27,35 +27,56 @@
 
 #if OS(WINDOWS)
 #include <winsock2.h>
+#include <ws2tcpip.h>
 #else
 #include <netinet/in.h>
 #endif
 
 #include <wtf/Forward.h>
+#include <wtf/Optional.h>
+#include <wtf/Variant.h>
 
 namespace WebCore {
 
-class WEBCORE_EXPORT IPAddress {
+class IPAddress {
 public:
-    explicit IPAddress(const struct sockaddr_in& address)
+    static Optional<IPAddress> fromSockAddrIn6(const struct sockaddr_in6&);
+    explicit IPAddress(const struct in_addr& address)
+        : m_address(address)
     {
-        memset(&m_address, 0, sizeof(struct sockaddr_in));
-        m_address = address;
     }
 
-    const struct in_addr& getSinAddr() { return m_address.sin_addr; };
+    explicit IPAddress(const struct in6_addr& address)
+        : m_address(address)
+    {
+    }
+
+    bool isIPv4() const { return WTF::holds_alternative<struct in_addr>(m_address); }
+    bool isIPv6() const { return WTF::holds_alternative<struct in6_addr>(m_address); }
+
+    const struct in_addr& ipv4Address() const { return WTF::get<struct in_addr>(m_address); }
+    const struct in6_addr& ipv6Address() const { return WTF::get<struct in6_addr>(m_address); }
 
 private:
-    struct sockaddr_in m_address;
+    Variant<struct in_addr, struct in6_addr> m_address;
 };
 
 enum class DNSError { Unknown, CannotResolve, Cancelled };
 
-using DNSAddressesOrError = Expected<Vector<WebCore::IPAddress>, DNSError>;
-using DNSCompletionHandler = WTF::CompletionHandler<void(DNSAddressesOrError&&)>;
+using DNSAddressesOrError = Expected<Vector<IPAddress>, DNSError>;
+using DNSCompletionHandler = CompletionHandler<void(DNSAddressesOrError&&)>;
 
 WEBCORE_EXPORT void prefetchDNS(const String& hostname);
 WEBCORE_EXPORT void resolveDNS(const String& hostname, uint64_t identifier, DNSCompletionHandler&&);
 WEBCORE_EXPORT void stopResolveDNS(uint64_t identifier);
 
+inline Optional<IPAddress> IPAddress::fromSockAddrIn6(const struct sockaddr_in6& address)
+{
+    if (address.sin6_family == AF_INET6)
+        return IPAddress { address.sin6_addr };
+    if (address.sin6_family == AF_INET)
+        return IPAddress {reinterpret_cast<const struct sockaddr_in&>(address).sin_addr };
+    return { };
+}
+
 }
diff --git a/Source/WebCore/platform/network/soup/DNSResolveQueueSoup.cpp b/Source/WebCore/platform/network/soup/DNSResolveQueueSoup.cpp
index d4ba4e9..9f696e7 100644
--- a/Source/WebCore/platform/network/soup/DNSResolveQueueSoup.cpp
+++ b/Source/WebCore/platform/network/soup/DNSResolveQueueSoup.cpp
@@ -143,9 +143,16 @@
     Vector<WebCore::IPAddress> addresses;
     addresses.reserveInitialCapacity(1);
     int len;
-    auto* ipAddress = reinterpret_cast<const struct sockaddr_in*>(soup_address_get_sockaddr(address, &len));
-    for (unsigned i = 0; i < sizeof(*ipAddress) / len; i++)
-        addresses.uncheckedAppend(WebCore::IPAddress(ipAddress[i]));
+    // FIXME: Support multiple addresses, IPv6 and IPv4.
+    auto* ipAddress = soup_address_get_sockaddr(address, &len);
+    if (ipAddress) {
+        if (auto address = IPAddress::fromSockAddrIn6(reinterpret_cast<const struct sockaddr_in6&>(*ipAddress)))
+            addresses.uncheckedAppend(*address);
+    }
+    if (addresses.isEmpty()) {
+        completionHandler(makeUnexpected(WebCore::DNSError::CannotResolve));
+        return;
+    }
 
     completionHandler(addresses);
 }
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index bb9fb60..4d5ae6c 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,19 @@
+2020-04-01  youenn fablet  <youenn@apple.com>
+
+        Support resolution of IPv6 STUN/TURN addresses
+        https://bugs.webkit.org/show_bug.cgi?id=209808
+
+        Reviewed by Eric Carlson.
+
+        Update code to support IPv6 addresses when doing DNS resolution of TURN/STUN servers.
+        Refactor code to share more code between Cocoa ports and non Cocoa ports.
+        Manually tested with external IPv6 TURN servers.
+
+        * NetworkProcess/webrtc/NetworkRTCProvider.cpp:
+        (WebKit::NetworkRTCProvider::createResolver):
+        * NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp:
+        (WebKit::resolvedName):
+
 2020-03-31  Megan Gardner  <megan_gardner@apple.com>
 
         Dismiss color picker on color selection on MacCatalyst
diff --git a/Source/WebKit/NetworkProcess/webrtc/NetworkRTCProvider.cpp b/Source/WebKit/NetworkProcess/webrtc/NetworkRTCProvider.cpp
index 4a12f69..48411d1 100644
--- a/Source/WebKit/NetworkProcess/webrtc/NetworkRTCProvider.cpp
+++ b/Source/WebKit/NetworkProcess/webrtc/NetworkRTCProvider.cpp
@@ -201,60 +201,46 @@
     NetworkRTCSocket(makeObjectIdentifier<LibWebRTCSocketIdentifierType>(decoder.destinationID()), *this).didReceiveMessage(connection, decoder);
 }
 
-#if PLATFORM(COCOA)
 
 void NetworkRTCProvider::createResolver(LibWebRTCResolverIdentifier identifier, const String& address)
 {
-    auto resolver = NetworkRTCResolver::create(identifier, [this, identifier](WebCore::DNSAddressesOrError&& result) mutable {
+    WebCore::DNSCompletionHandler completionHandler = [this, identifier](auto&& result) {
         if (!result.has_value()) {
             if (result.error() != WebCore::DNSError::Cancelled)
                 m_connection->connection().send(Messages::WebRTCResolver::ResolvedAddressError(1), identifier);
             return;
         }
 
-        auto addresses = WTF::map(result.value(), [] (auto& address) {
-            return RTCNetwork::IPAddress { rtc::IPAddress { address.getSinAddr() } };
-        });
-
-        m_connection->connection().send(Messages::WebRTCResolver::SetResolvedAddress(addresses), identifier);
-    });
-    resolver->start(address);
-    m_resolvers.add(identifier, WTFMove(resolver));
-}
-
-void NetworkRTCProvider::stopResolver(LibWebRTCResolverIdentifier identifier)
-{
-    if (auto resolver = m_resolvers.take(identifier))
-        resolver->stop();
-}
-
-#else
-
-void NetworkRTCProvider::createResolver(LibWebRTCResolverIdentifier identifier, const String& address)
-{
-    auto completionHandler = [this, identifier](WebCore::DNSAddressesOrError&& result) mutable {
-        if (!result.has_value()) {
-            if (result.error() != WebCore::DNSError::Cancelled)
-                m_connection->connection().send(Messages::WebRTCResolver::ResolvedAddressError(1), identifier);
-            return;
+        Vector<RTCNetwork::IPAddress> ipAddresses;
+        ipAddresses.reserveInitialCapacity(result.value().size());
+        for (auto& address : result.value()) {
+            if (address.isIPv4())
+                ipAddresses.uncheckedAppend(rtc::IPAddress { address.ipv4Address() });
+            else if (address.isIPv6())
+                ipAddresses.uncheckedAppend(rtc::IPAddress { address.ipv6Address() });
         }
 
-        auto addresses = WTF::map(result.value(), [] (auto& address) {
-            return RTCNetwork::IPAddress { rtc::IPAddress { address.getSinAddr() } };
-        });
-
-        m_connection->connection().send(Messages::WebRTCResolver::SetResolvedAddress(addresses), identifier);
+        m_connection->connection().send(Messages::WebRTCResolver::SetResolvedAddress(ipAddresses), identifier);
     };
 
+#if PLATFORM(COCOA)
+    auto resolver = NetworkRTCResolver::create(identifier, WTFMove(completionHandler));
+    resolver->start(address);
+    m_resolvers.add(identifier, WTFMove(resolver));
+#else
     WebCore::resolveDNS(address, identifier.toUInt64(), WTFMove(completionHandler));
+#endif
 }
 
 void NetworkRTCProvider::stopResolver(LibWebRTCResolverIdentifier identifier)
 {
+#if PLATFORM(COCOA)
+    if (auto resolver = m_resolvers.take(identifier))
+        resolver->stop();
+#else
     WebCore::stopResolveDNS(identifier.toUInt64());
-}
-
 #endif
+}
 
 void NetworkRTCProvider::closeListeningSockets(Function<void()>&& completionHandler)
 {
diff --git a/Source/WebKit/NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp b/Source/WebKit/NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp
index 9c4e041..3080343 100644
--- a/Source/WebKit/NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp
+++ b/Source/WebKit/NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp
@@ -55,10 +55,8 @@
 
     for (size_t index = 0; index < count; ++index) {
         CFDataRef data = (CFDataRef)CFArrayGetValueAtIndex(resolvedAddresses, index);
-        auto* address = reinterpret_cast<const struct sockaddr_in*>(CFDataGetBytePtr(data));
-        if (address->sin_family == AF_INET)
-            addresses.uncheckedAppend(WebCore::IPAddress(*address));
-        // FIXME: We should probably return AF_INET6 addresses as well.
+        if (auto address = IPAddress::fromSockAddrIn6(*reinterpret_cast<const struct sockaddr_in6*>(CFDataGetBytePtr(data))))
+            addresses.uncheckedAppend(*address);
     }
     if (addresses.isEmpty()) {
         resolver->completed(makeUnexpected(WebCore::DNSError::CannotResolve));