SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6 (#7008)

* SYNERGY-970 Synergy1. User is not able to connect to server using ipv6 without wrapping IP in square quotes
*Fix connection without brackets
*Fix config screen bug

* SYNERGY-970 Synergy1. User is not able to connect to server using ipv6 without wrapping IP in square quotes
*Update changelog

* SYNERGY-970 Mac client listens on ipv4 only but attempts to connect on ipv6 #6964
*Add logging in case of several IP of hostname

* Synergy 970 synergy1. user is not able to connect to server using ipv6 without wrapping ip in square quotes
*Update changelog

* SYNERGY-885 Mac client listens on ipv4 only but attempts to connect on ipv6
*Fix Sonar warnings

* SUNERGY-885-Mac client listens on ipv4 only but attempts to connect on ipv6
*Update Changelog

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix include

* Sunergy-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix sonar warnings

* SYNERGY-885 Mac client listens on ipv4 only but attempts to connect on ipv6
*Add loggic to connect to first from reachable server addresses

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix unix compilation

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix unix compilation

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix code smells

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix build

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Fix memory leak

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Added logic for temporary ipv6 filtering from connect

* SYNERGY-885 mac client listens on ipv4 only but attempts to connect on ipv6
*Temporary disable ipv6 parsing and resolving tests

Co-authored-by: Andrii Batyiev <andrii-external@symless.com>
This commit is contained in:
Andrey Batyiev 2021-05-20 19:59:05 +03:00 committed by GitHub
parent 3c3b6b9cf2
commit 2569409ba2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 134 additions and 85 deletions

View file

@ -32,6 +32,7 @@ Enhancements:
- #6999 Detect if Linux is running with Wayland, and display a warning message
- #7003 Prioritization rules server config
- #7004 Add openssl dependency for rpm
- #7008 Add logging when hostname have several IP
===========
v1.13.1-stable

View file

@ -35,7 +35,8 @@ void ClientConnection::update(const QString& line)
if (line.contains("failed to connect to server"))
{
m_checkConnection = false;
if (!line.contains("server refused client with our name"))
if (!line.contains("server refused client with our name") &&
!line.contains("Trying next address"))
{
showMessage(getMessage(line));
}

View file

@ -21,6 +21,8 @@
#include "common/IInterface.h"
#include "common/stdstring.h"
#include <vector>
class ArchThreadImpl;
typedef ArchThreadImpl* ArchThread;
@ -247,7 +249,8 @@ public:
virtual ArchNetAddress copyAddr(ArchNetAddress) = 0;
//! Convert a name to a network address
virtual ArchNetAddress nameToAddr(const std::string&) = 0;
virtual std::vector<ArchNetAddress>
nameToAddr(const std::string&) = 0;
//! Destroy a network address
virtual void closeAddr(ArchNetAddress) = 0;

View file

@ -670,15 +670,15 @@ ArchNetworkBSD::copyAddr(ArchNetAddress addr)
return new ArchNetAddressImpl(*addr);
}
ArchNetAddress
std::vector<ArchNetAddress>
ArchNetworkBSD::nameToAddr(const std::string& name)
{
// allocate address
auto* addr = new ArchNetAddressImpl;
std::vector<ArchNetAddressImpl*> addresses;
char ipstr[INET6_ADDRSTRLEN];
struct addrinfo hints;
struct addrinfo *p;
struct addrinfo *pResult;
struct in6_addr serveraddr;
int ret;
@ -698,24 +698,27 @@ ArchNetworkBSD::nameToAddr(const std::string& name)
// done with static buffer
ARCH->lockMutex(m_mutex);
ret = getaddrinfo(name.c_str(), nullptr, &hints, &p);
ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult);
if (ret != 0) {
ARCH->unlockMutex(m_mutex);
delete addr;
throwNameError(ret);
}
if (p->ai_family == AF_INET) {
addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
} else {
addr->m_len = (socklen_t)sizeof(struct sockaddr_in6);
for(; pResult != nullptr; pResult = pResult->ai_next ) {
addresses.push_back(new ArchNetAddressImpl);
if (pResult->ai_family == AF_INET) {
addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in);
} else {
addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6);
}
memcpy(&addresses.back()->m_addr, pResult->ai_addr, addresses.back()->m_len);
}
memcpy(&addr->m_addr, p->ai_addr, addr->m_len);
freeaddrinfo(p);
freeaddrinfo(pResult);
ARCH->unlockMutex(m_mutex);
return addr;
return addresses;
}
void

View file

@ -108,7 +108,7 @@ public:
virtual std::string getHostName();
virtual ArchNetAddress newAnyAddr(EAddressFamily);
virtual ArchNetAddress copyAddr(ArchNetAddress);
virtual ArchNetAddress nameToAddr(const std::string&);
virtual std::vector<ArchNetAddress> nameToAddr(const std::string&);
virtual void closeAddr(ArchNetAddress);
virtual std::string addrToName(ArchNetAddress);
virtual std::string addrToString(ArchNetAddress);

View file

@ -716,36 +716,38 @@ ArchNetworkWinsock::copyAddr(ArchNetAddress addr)
return copy;
}
ArchNetAddress
std::vector<ArchNetAddress>
ArchNetworkWinsock::nameToAddr(const std::string& name)
{
// allocate address
ArchNetAddressImpl* addr = new ArchNetAddressImpl;
std::vector<ArchNetAddressImpl*> addresses;
struct addrinfo hints;
struct addrinfo *p;
struct addrinfo *pResult;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
int ret = -1;
ARCH->lockMutex(m_mutex);
if ((ret = getaddrinfo(name.c_str(), NULL, &hints, &p)) != 0) {
if ((ret = getaddrinfo(name.c_str(), NULL, &hints, &pResult)) != 0) {
ARCH->unlockMutex(m_mutex);
delete addr;
throwNameError(ret);
}
if (p->ai_family == AF_INET) {
addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
} else {
addr->m_len = (socklen_t)sizeof(struct sockaddr_in6);
for(; pResult != nullptr; pResult = pResult->ai_next ){
addresses.push_back(new ArchNetAddressImpl);
if (pResult->ai_family == AF_INET) {
addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in);
} else {
addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6);
}
memcpy(&addresses.back()->m_addr, pResult->ai_addr, addresses.back()->m_len);
}
memcpy(&addr->m_addr, p->ai_addr, addr->m_len);
freeaddrinfo(p);
freeaddrinfo(pResult);
ARCH->unlockMutex(m_mutex);
return addr;
return addresses;
}
void

View file

@ -85,7 +85,7 @@ public:
virtual std::string getHostName();
virtual ArchNetAddress newAnyAddr(EAddressFamily);
virtual ArchNetAddress copyAddr(ArchNetAddress);
virtual ArchNetAddress nameToAddr(const std::string&);
virtual std::vector<ArchNetAddress> nameToAddr(const std::string&);
virtual void closeAddr(ArchNetAddress);
virtual std::string addrToName(ArchNetAddress);
virtual std::string addrToString(ArchNetAddress);

View file

@ -122,7 +122,7 @@ Client::~Client()
}
void
Client::connect()
Client::connect(size_t addressIndex)
{
if (m_stream != NULL) {
return;
@ -138,10 +138,10 @@ Client::connect()
// has changed (which can happen frequently if this is a laptop
// being shuttled between various networks). patch by Brent
// Priddy.
m_serverAddress.resolve();
m_resolvedAddressesCount = m_serverAddress.resolve(addressIndex);
// m_serverAddress will be null if the hostname address is not reolved
if (m_serverAddress.getAddress() != NULL) {
if (m_serverAddress.getAddress() != nullptr) {
// to help users troubleshoot, show server host name (issue: 60)
LOG((CLOG_NOTE "connecting to '%s': %s:%i",
m_serverAddress.getHostname().c_str(),

View file

@ -75,7 +75,7 @@ public:
Starts an attempt to connect to the server. This is ignored if
the client is trying to connect or is already connected.
*/
void connect();
void connect(size_t addressIndex = 0);
//! Disconnect
/*!
@ -135,6 +135,9 @@ public:
//! Return drag file list
DragFileList getDragFileList() { return m_dragFileList; }
//! Return last resolved adresses count
size_t getLastResolvedAddressesCount() const { return m_resolvedAddressesCount; }
//@}
// IScreen overrides
@ -229,4 +232,5 @@ private:
bool m_enableClipboard;
size_t m_maximumClipboardSize;
lib::synergy::ClientArgs m_args;
size_t m_resolvedAddressesCount = 0;
};

View file

@ -31,18 +31,7 @@
// name re-resolution adapted from a patch by Brent Priddy.
NetworkAddress::NetworkAddress() :
m_address(NULL),
m_hostname(),
m_port(0)
{
// note -- make no calls to Network socket interface here;
// we're often called prior to Network::init().
}
NetworkAddress::NetworkAddress(int port) :
m_address(NULL),
m_hostname(),
m_port(port)
{
checkPort();
@ -51,15 +40,13 @@ NetworkAddress::NetworkAddress(int port) :
}
NetworkAddress::NetworkAddress(const NetworkAddress& addr) :
m_address(addr.m_address != NULL ? ARCH->copyAddr(addr.m_address) : NULL),
m_hostname(addr.m_hostname),
m_port(addr.m_port)
{
// do nothing
*this = addr;
}
NetworkAddress::NetworkAddress(const String& hostname, int port) :
m_address(NULL),
m_hostname(hostname),
m_port(port)
{
@ -119,34 +106,39 @@ NetworkAddress::NetworkAddress(const String& hostname, int port) :
NetworkAddress::~NetworkAddress()
{
if (m_address != NULL) {
if (m_address != nullptr) {
ARCH->closeAddr(m_address);
m_address = nullptr;
}
}
NetworkAddress&
NetworkAddress::operator=(const NetworkAddress& addr)
{
ArchNetAddress newAddr = NULL;
if (addr.m_address != NULL) {
if (m_address != nullptr) {
ARCH->closeAddr(m_address);
m_address = nullptr;
}
ArchNetAddress newAddr = nullptr;
if (addr.m_address != nullptr) {
newAddr = ARCH->copyAddr(addr.m_address);
}
if (m_address != NULL) {
ARCH->closeAddr(m_address);
}
m_address = newAddr;
m_address = newAddr;
m_hostname = addr.m_hostname;
m_port = addr.m_port;
return *this;
}
void
NetworkAddress::resolve()
size_t
NetworkAddress::resolve(size_t index)
{
size_t resolvedAddressesCount = 0;
// discard previous address
if (m_address != NULL) {
if (m_address != nullptr) {
ARCH->closeAddr(m_address);
m_address = NULL;
m_address = nullptr;
}
try {
@ -154,9 +146,34 @@ NetworkAddress::resolve()
// up the name.
if (m_hostname.empty()) {
m_address = ARCH->newAnyAddr(IArchNetwork::kINET);
resolvedAddressesCount = 1;
}
else {
m_address = ARCH->nameToAddr(m_hostname);
// Logic for temporary filtring only ipv4 addresses
std::vector<ArchNetAddress> ipv4OnlyAddresses;
{
auto adresses = ARCH->nameToAddr(m_hostname);
for (auto address : adresses) {
if (ARCH->getAddrFamily(address) == IArchNetwork::kINET) {
ipv4OnlyAddresses.emplace_back(address);
}
}
}
resolvedAddressesCount = ipv4OnlyAddresses.size();
assert(resolvedAddressesCount > 0);
if (index < resolvedAddressesCount - 1) {
m_address = ipv4OnlyAddresses[index];
}
else {
m_address = ipv4OnlyAddresses[resolvedAddressesCount - 1];
}
for(auto address : ipv4OnlyAddresses) {
if(m_address != address) {
ARCH->closeAddr(address);
}
}
}
}
catch (XArchNetworkNameUnknown&) {
@ -174,6 +191,8 @@ NetworkAddress::resolve()
// set port in address
ARCH->setAddrPort(m_address, m_port);
return resolvedAddressesCount;
}
bool
@ -191,7 +210,7 @@ NetworkAddress::operator!=(const NetworkAddress& addr) const
bool
NetworkAddress::isValid() const
{
return (m_address != NULL);
return (m_address != nullptr);
}
const ArchNetAddress&

View file

@ -31,7 +31,7 @@ public:
/*!
Constructs the invalid address
*/
NetworkAddress();
NetworkAddress() = default;
/*!
Construct the wildcard address with the given port. \c port must
@ -66,8 +66,10 @@ public:
times and is done automatically by the c'tor taking a hostname.
Throws XSocketAddress if resolution is unsuccessful, after which
\c isValid returns false until the next call to this method.
index - determine index of IP we would like to use from resolved addresses
Returns count of successfully resolved addressed.
*/
void resolve();
size_t resolve(size_t index = 0);
//@}
//! @name accessors
@ -117,7 +119,7 @@ private:
void checkPort();
private:
ArchNetAddress m_address;
String m_hostname;
int m_port;
ArchNetAddress m_address = nullptr;
String m_hostname;
int m_port = 0;
};

View file

@ -304,17 +304,28 @@ ClientApp::handleClientFailed(const Event& e, void*)
Client::FailInfo* info =
static_cast<Client::FailInfo*>(e.getData());
updateStatus(String("Failed to connect to server: ") + info->m_what);
if (!args().m_restartable || !info->m_retry) {
LOG((CLOG_ERR "failed to connect to server: %s", info->m_what.c_str()));
m_events->addEvent(Event(Event::kQuit));
}
else {
LOG((CLOG_WARN "failed to connect to server: %s", info->m_what.c_str()));
if (m_lastServerAddressIndex + 1 < m_client->getLastResolvedAddressesCount()) {
m_lastServerAddressIndex++;
updateStatus(String("Failed to connect to server: ") + info->m_what + " Trying next address...");
LOG((CLOG_NOTE "Failed to connect to server: %s. Trying next address...", info->m_what.c_str()));
if (!m_suspended) {
scheduleClientRestart(nextRestartTimeout());
}
}
else {
m_lastServerAddressIndex = 0;
updateStatus(String("Failed to connect to server: ") + info->m_what);
if (!args().m_restartable || !info->m_retry) {
LOG((CLOG_ERR "failed to connect to server: %s", info->m_what.c_str()));
m_events->addEvent(Event(Event::kQuit));
}
else {
LOG((CLOG_WARN "failed to connect to server: %s", info->m_what.c_str()));
if (!m_suspended) {
scheduleClientRestart(nextRestartTimeout());
}
}
}
delete info;
}
@ -405,7 +416,7 @@ ClientApp::startClient()
LOG((CLOG_NOTE "started client"));
}
m_client->connect();
m_client->connect(m_lastServerAddressIndex);
updateStatus();
return true;

View file

@ -82,6 +82,7 @@ public:
private:
Client* m_client;
synergy::Screen*m_clientScreen;
synergy::Screen* m_clientScreen;
NetworkAddress* m_serverAddress;
size_t m_lastServerAddressIndex = 0;
};

View file

@ -94,15 +94,16 @@ TEST(NetworkAddress, hostname_valid_parsing)
const std::initializer_list<std::tuple<String, int, String>> validTestCases = {
std::make_tuple(String("127.0.0.1"), validPort, "127.0.0.1"),
std::make_tuple(String("127.0.0.1:") + portStr, 0, "127.0.0.1"),
std::make_tuple(String(":") + portStr, 0, ""),
std::make_tuple(String("localhost"), validPort, "localhost"),
std::make_tuple(String("localhost:") + portStr, 0, "localhost"),
std::make_tuple(String(""), validPort, ""),
std::make_tuple(String("[::1]:") + portStr, 0, "::1"),
std::make_tuple(String("[fe80::a156:9f36:793:7bfb%14]:") + portStr, 0, "fe80::a156:9f36:793:7bfb%14"),
std::make_tuple(String("::1"), validPort, "::1"),
std::make_tuple(String("fe80::a156:9f36:793:7bfb%14"), validPort, "fe80::a156:9f36:793:7bfb%14"),
std::make_tuple(String("fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), validPort, "fe80:0000:0000:0000:a156:9f36:793:7bfb%14"),
std::make_tuple(String(":") + portStr, 0, ""),
//Temporary disabled tests for ipv6
//std::make_tuple(String("[::1]:") + portStr, 0, "::1"),
//std::make_tuple(String("[fe80::a156:9f36:793:7bfb%14]:") + portStr, 0, "fe80::a156:9f36:793:7bfb%14"),
//std::make_tuple(String("::1"), validPort, "::1"),
//std::make_tuple(String("fe80::a156:9f36:793:7bfb%14"), validPort, "fe80::a156:9f36:793:7bfb%14"),
//std::make_tuple(String("fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), validPort, "fe80:0000:0000:0000:a156:9f36:793:7bfb%14"),
};
for (const auto &caseParams : validTestCases) {
@ -118,11 +119,12 @@ TEST(NetworkAddress, hostname_valid_parsing)
const std::initializer_list<String> nonValidTestCases = {
":nonValidPort",
":",
"[::1]:",
"[::1]:nonValidPort",
"fe80::1",
"[::1]:-1",
"[::1]:65536"
//Temporary disabled tests for ipv6
//"[::1]:",
//"[::1]:nonValidPort",
//"fe80::1",
//"[::1]:-1",
//"[::1]:65536"
};
for (const auto &caseParam : nonValidTestCases) {