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:
parent
3c3b6b9cf2
commit
2569409ba2
14 changed files with 134 additions and 85 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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&
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue