Gateway (RDG) use same IP for both channels
authorAndre Esteve <andreesteve@gmail.com>
Thu, 15 Mar 2018 05:37:30 +0000 (22:37 -0700)
committerAndre Esteve <andreesteve@gmail.com>
Wed, 11 Apr 2018 03:59:33 +0000 (20:59 -0700)
libfreerdp/core/gateway/rdg.c
libfreerdp/core/tcp.c
libfreerdp/core/tcp.h

index ba71339..03bbe28 100644 (file)
@@ -1027,8 +1027,10 @@ static BOOL rdg_tls_in_connect(rdpRdg* rdg, const char* hostname, UINT16 port, i
        BIO* bufferedBio = NULL;
        rdpSettings* settings = rdg->settings;
        const char* peerHostname = settings->GatewayHostname;
-       int peerPort = settings->GatewayPort;
+       UINT16 peerPort = settings->GatewayPort;
        BOOL isProxyConnection = FALSE;
+       int outChannelSocket = 0;
+       char* gatewayAddress = NULL;
        assert(hostname != NULL);
 
        if (settings->ProxyType)
@@ -1037,17 +1039,45 @@ static BOOL rdg_tls_in_connect(rdpRdg* rdg, const char* hostname, UINT16 port, i
                peerPort = settings->ProxyPort;
                isProxyConnection = TRUE;
        }
+       else
+       {
+               /**
+                * if settings->GatewayHostname is a name, it may be mapped to more than one
+                * IP address (thus potentially multiple gateway servers) - to avoid openning
+                * the IN channel with one server and the OUT channel with another server
+                * we want to use the same IP when connecting to both IN and OUT channels
+                * below we get the peer ip address in use by the OUT channel and use it
+                * when opening the connection for the IN channel
+               */
+               BIO_get_socket(rdg->tlsOut->underlying, &outChannelSocket);
+               gatewayAddress = freerdp_tcp_get_peer_address(outChannelSocket);
+
+               if (gatewayAddress == NULL)
+               {
+                       WLog_DBG(TAG,
+                                "RDG out channel was created but gateway IP couldn't be resolved. Falling back to resolving gateway hostname again for IN channel.");
+               }
+               else
+               {
+                       WLog_DBG(TAG, "Gateway hostname %s resolved to IP %s.", peerHostname, gatewayAddress);
+                       peerHostname = gatewayAddress;
+               }
+       }
 
        sockfd = freerdp_tcp_connect(rdg->context, settings, peerHostname,
                                     peerPort, timeout);
 
        if (sockfd < 1)
+       {
+               free(gatewayAddress);
                return FALSE;
+       }
 
        socketBio = BIO_new(BIO_s_simple_socket());
 
        if (!socketBio)
        {
+               free(gatewayAddress);
                closesocket(sockfd);
                return FALSE;
        }
@@ -1057,6 +1087,7 @@ static BOOL rdg_tls_in_connect(rdpRdg* rdg, const char* hostname, UINT16 port, i
 
        if (!bufferedBio)
        {
+               free(gatewayAddress);
                BIO_free(socketBio);
                return FALSE;
        }
@@ -1066,6 +1097,7 @@ static BOOL rdg_tls_in_connect(rdpRdg* rdg, const char* hostname, UINT16 port, i
 
        if (!status)
        {
+               free(gatewayAddress);
                BIO_free_all(bufferedBio);
                return FALSE;
        }
@@ -1077,6 +1109,7 @@ static BOOL rdg_tls_in_connect(rdpRdg* rdg, const char* hostname, UINT16 port, i
 
        if (status < 1)
        {
+               free(gatewayAddress);
                return FALSE;
        }
 
index 03f848c..b14990c 100644 (file)
@@ -664,17 +664,16 @@ BIO_METHOD* BIO_s_buffered_socket(void)
        return bio_methods;
 }
 
-static char* freerdp_tcp_get_ip_address(int sockfd, BOOL* pIPv6)
+static char* freerdp_tcp_address_to_string(const struct sockaddr_storage* addr, BOOL* pIPv6)
 {
-       socklen_t length;
        char ipAddress[INET6_ADDRSTRLEN + 1] = { 0 };
-       struct sockaddr_storage saddr = { 0 };
-       struct sockaddr_in6* sockaddr_ipv6 = (struct sockaddr_in6*)&saddr;
-       struct sockaddr_in* sockaddr_ipv4 = (struct sockaddr_in*)&saddr;
-       length = sizeof(struct sockaddr_storage);
+       struct sockaddr_in6* sockaddr_ipv6 = (struct sockaddr_in6*)addr;
+       struct sockaddr_in* sockaddr_ipv4 = (struct sockaddr_in*)addr;
 
-       if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
+       if (addr == NULL)
+       {
                return NULL;
+       }
 
        switch (sockaddr_ipv4->sin_family)
        {
@@ -698,12 +697,40 @@ static char* freerdp_tcp_get_ip_address(int sockfd, BOOL* pIPv6)
                        return NULL;
        }
 
-       if (pIPv6)
+       if (pIPv6 != NULL)
+       {
                *pIPv6 = (sockaddr_ipv4->sin_family == AF_INET6);
+       }
 
        return _strdup(ipAddress);
 }
 
+static char* freerdp_tcp_get_ip_address(int sockfd, BOOL* pIPv6)
+{
+       struct sockaddr_storage saddr = { 0 };
+       socklen_t length = sizeof(struct sockaddr_storage);
+
+       if (getsockname(sockfd, (struct sockaddr*)&saddr, &length) != 0)
+       {
+               return NULL;
+       }
+
+       return freerdp_tcp_address_to_string(&saddr, pIPv6);
+}
+
+char* freerdp_tcp_get_peer_address(int sockfd)
+{
+       struct sockaddr_storage saddr = { 0 };
+       socklen_t length = sizeof(struct sockaddr_storage);
+
+       if (getpeername(sockfd, (struct sockaddr*)&saddr, &length) != 0)
+       {
+               return NULL;
+       }
+
+       return freerdp_tcp_address_to_string(&saddr, NULL);
+}
+
 static int freerdp_uds_connect(const char* path)
 {
 #ifndef _WIN32
@@ -1110,6 +1137,7 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings,
                if (sockfd <= 0)
                {
                        char port_str[16];
+                       char* peerAddress;
                        struct addrinfo hints;
                        struct addrinfo* addr;
                        struct addrinfo* result;
@@ -1150,6 +1178,12 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings,
                                return -1;
                        }
 
+                       if ((peerAddress = freerdp_tcp_address_to_string(addr->ai_addr, NULL)) != NULL)
+                       {
+                               WLog_DBG(TAG, "connecting to peer %s", peerAddress);
+                               free(peerAddress);
+                       }
+
                        if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr,
                                                         addr->ai_addrlen, timeout))
                        {
index 6638c19..f63f477 100644 (file)
@@ -67,4 +67,6 @@ FREERDP_LOCAL int freerdp_tcp_connect(rdpContext* context,
                                       rdpSettings* settings,
                                       const char* hostname, int port, int timeout);
 
+FREERDP_LOCAL char* freerdp_tcp_get_peer_address(int sockfd);
+
 #endif /* FREERDP_LIB_CORE_TCP_H */