From d240069b5eff576a5b66c9d5184c6fc33a9d71da Mon Sep 17 00:00:00 2001 From: Andre Esteve Date: Wed, 14 Mar 2018 22:37:30 -0700 Subject: [PATCH] Gateway (RDG) use same IP for both channels --- libfreerdp/core/gateway/rdg.c | 35 +++++++++++++++++++++++++++++- libfreerdp/core/tcp.c | 50 ++++++++++++++++++++++++++++++++++++------- libfreerdp/core/tcp.h | 2 ++ 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index ba71339..03bbe28 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -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; } diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 03f848c..b14990c 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -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)) { diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index 6638c19..f63f477 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -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 */ -- 2.7.4