From 5f239a8f22c8107e1feef608d1ffadc5d36760b4 Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Wed, 27 Jan 2021 00:46:29 +0100 Subject: [PATCH 1/3] Add support for --serverpublicip When running servers and registering them with a central server, Jamulus will auto-detect the external IP of the current machine. However, this will not be a publicly reachable IP when using NAT and a central server in the same private network. This means, that the server is inaccessible via that central server. Therefore, add a new command line option --serverpublicip to override this auto-detection. Note: This still requires that proper port forwarding is set up. It also assumes that ports are forwarded symmetrically, i.e. external-ip:22124 -> internal-ip:22124 Required for #888. Signed-off-by: Christian Hoffmann --- src/main.cpp | 19 +++++++++++++++++++ src/server.cpp | 2 ++ src/server.h | 1 + src/serverlist.cpp | 14 +++++++++++++- src/serverlist.h | 1 + 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 9f59fda66b..f47b790150 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -83,6 +83,7 @@ int main ( int argc, char** argv ) QString strRecordingDirName = ""; QString strCentralServer = ""; QString strServerInfo = ""; + QString strServerPublicIP = ""; QString strServerListFilter = ""; QString strWelcomeMessage = ""; QString strClientName = ""; @@ -397,6 +398,20 @@ int main ( int argc, char** argv ) } + // Server Public IP -------------------------------------------------- + if ( GetStringArgument ( argc, + argv, + i, + "--serverpublicip", // no short form + "--serverpublicip", + strArgument ) ) + { + strServerPublicIP = strArgument; + CommandLineOptions << "--serverpublicip"; + continue; + } + + // Server info --------------------------------------------------------- if ( GetStringArgument ( argc, argv, @@ -696,6 +711,7 @@ int main ( int argc, char** argv ) strHTMLStatusFileName, strCentralServer, strServerInfo, + strServerPublicIP, strServerListFilter, strWelcomeMessage, strRecordingDirName, @@ -814,6 +830,9 @@ QString UsageArguments ( char **argv ) " -u, --numchannels maximum number of channels\n" " -w, --welcomemessage welcome message on connect\n" " -z, --startminimized start minimizied\n" + " --serverpublicip specify your public IP address when\n" + " running a slave and your own central server\n" + " behind the same NAT\n" "\nClient only:\n" " -M, --mutestream starts the application in muted state\n" " --mutemyown mute me in my personal mix (headless only)\n" diff --git a/src/server.cpp b/src/server.cpp index e80df8e020..9ef505efb5 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -226,6 +226,7 @@ CServer::CServer ( const int iNewMaxNumChan, const QString& strCentralServer, const QString& strServerInfo, const QString& strServerListFilter, + const QString& strServerPublicIP, const QString& strNewWelcomeMessage, const QString& strRecordingDirName, const bool bNDisconnectAllClientsOnQuit, @@ -245,6 +246,7 @@ CServer::CServer ( const int iNewMaxNumChan, ServerListManager ( iPortNumber, strCentralServer, strServerInfo, + strServerPublicIP, strServerListFilter, iNewMaxNumChan, &ConnLessProtocol ), diff --git a/src/server.h b/src/server.h index 119ef0e94f..b4e78b4462 100755 --- a/src/server.h +++ b/src/server.h @@ -176,6 +176,7 @@ class CServer : const QString& strCentralServer, const QString& strServerInfo, const QString& strServerListFilter, + const QString& strServerPublicIP, const QString& strNewWelcomeMessage, const QString& strRecordingDirName, const bool bNDisconnectAllClientsOnQuit, diff --git a/src/serverlist.cpp b/src/serverlist.cpp index e835fcd80f..f3c424cb2a 100755 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -29,6 +29,7 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum, const QString& sNCentServAddr, const QString& strServerInfo, const QString& strServerListFilter, + const QString& strServerPublicIP, const int iNumChannels, CProtocol* pNConLProt ) : eCentralServerAddressType ( AT_CUSTOM ), // must be AT_CUSTOM for the "no GUI" case @@ -41,7 +42,18 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum, SetCentralServerAddress ( sNCentServAddr ); // set the server internal address, including internal port number - SlaveCurLocalHostAddress = CHostAddress( NetworkUtil::GetLocalAddress().InetAddr, iNPortNum ); + QHostAddress qhaServerPublicIP; + if ( strServerPublicIP == "" ) + { + // No user-supplied override via --serverpublicip -> use auto-detection + qhaServerPublicIP = NetworkUtil::GetLocalAddress().InetAddr; + } + else + { + // User-supplied --serverpublicip + qhaServerPublicIP = QHostAddress ( strServerPublicIP ); + } + SlaveCurLocalHostAddress = CHostAddress ( qhaServerPublicIP, iNPortNum ); // prepare the server info information QStringList slServInfoSeparateParams; diff --git a/src/serverlist.h b/src/serverlist.h index 51a494c56d..6fa1df276e 100755 --- a/src/serverlist.h +++ b/src/serverlist.h @@ -128,6 +128,7 @@ class CServerListManager : public QObject const QString& sNCentServAddr, const QString& strServerInfo, const QString& strServerListFilter, + const QString& strServerPublicIP, const int iNumChannels, CProtocol* pNConLProt ); From 4800e05089a348a1c83631cc7c125259035df5f5 Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Wed, 27 Jan 2021 22:03:48 +0100 Subject: [PATCH 2/3] Add support for central servers+slaves behind NAT Previously, the server list handed out the originating address of a slave server to any client. A special case was implemented to hand out internal addresses instead of public addresses when both the slave server and the client are assumed to be behind the same NAT. This commit adds another special case for running central servers and slave servers behind NAT while serving clients from the Internet. In such a setup, slave servers would only be known by their internal address to the central server. As such, clients would be served an internal IP address which they cannot use. When slave servers make use of the newly added --externalserverip flag, they can now override their internal IP address with the proper public IP address. This commit adapts the server list logic to make use of an IP which is provided in this way. Fixes #888. Signed-off-by: Christian Hoffmann --- src/protocol.cpp | 3 +++ src/serverlist.cpp | 14 ++++++++++++++ src/util.cpp | 22 ++++++++++++++++++++++ src/util.h | 1 + 4 files changed, 40 insertions(+) diff --git a/src/protocol.cpp b/src/protocol.cpp index 0e94b99c75..de027c2b5c 100755 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -303,6 +303,9 @@ CONNECTION LESS MESSAGES NOTE: In the PROTMESSID_CLM_SERVER_LIST list, this field will be empty as only the initial IP address should be used by the client. Where necessary, that value will contain the server internal address. + When running a central server and a slave server behind the same NAT, + this field is used the other way round: It will contain the public + IP in this case which will be served to clients from the Internet. - PROTMESSID_CLM_REGISTER_SERVER_EX: Register a server, providing extended server diff --git a/src/serverlist.cpp b/src/serverlist.cpp index f3c424cb2a..79d0c4768d 100755 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -455,6 +455,20 @@ void CServerListManager::CentralServerQueryServerList ( const CHostAddress& Inet { vecServerInfo[iIdx].HostAddr = ServerList[iIdx].LHostAddr; } + else if ( !NetworkUtil::IsPrivateNetworkIP ( InetAddr.InetAddr ) && + NetworkUtil::IsPrivateNetworkIP ( vecServerInfo[iIdx].HostAddr.InetAddr ) && + !NetworkUtil::IsPrivateNetworkIP ( ServerList[iIdx].LHostAddr.InetAddr ) ) + { + // We've got a request from a public client, the server + // list's entry's primary address is a private address, + // but it supplied an additional public address using + // --serverpublicip. + // In this case, use the latter. + // This is common when running a central server with slave + // servers behind a NAT and dealing with external, public + // clients. + vecServerInfo[iIdx].HostAddr = ServerList[iIdx].LHostAddr; + } else { // create "send empty message" for all registered servers diff --git a/src/util.cpp b/src/util.cpp index 5df6d9d29e..2790bc4185 100755 --- a/src/util.cpp +++ b/src/util.cpp @@ -1059,6 +1059,28 @@ QString NetworkUtil::FixAddress ( const QString& strAddress ) return strAddress.simplified().replace ( " ", "" ); } +// Return whether the given HostAdress is within a private IP range +// as per RFC 1918 & RFC 5735. +bool NetworkUtil::IsPrivateNetworkIP ( const QHostAddress &qhAddr ) +{ + // https://www.rfc-editor.org/rfc/rfc1918 + // https://www.rfc-editor.org/rfc/rfc5735 + static QList> addresses = + { + QPair ( QHostAddress ( "10.0.0.0" ), 8 ), + QPair ( QHostAddress ( "127.0.0.0" ), 8 ), + QPair ( QHostAddress ( "172.16.0.0" ), 12 ), + QPair ( QHostAddress ( "192.168.0.0" ), 16 ), + }; + + foreach ( auto item, addresses ) { + if ( qhAddr.isInSubnet ( item ) ) { + return true; + } + } + return false; +} + // Instrument picture data base ------------------------------------------------ CVector& CInstPictures::GetTable ( const bool bReGenerateTable ) diff --git a/src/util.h b/src/util.h index 7dadac409b..3c8d766de7 100755 --- a/src/util.h +++ b/src/util.h @@ -1104,6 +1104,7 @@ class NetworkUtil static CHostAddress GetLocalAddress(); static QString GetCentralServerAddress ( const ECSAddType eCentralServerAddressType, const QString& strCentralServerAddress ); + static bool IsPrivateNetworkIP ( const QHostAddress& qhAddr ); }; From 47f871f14839c10ddd4d286fe9646cfda2661ef4 Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Sun, 7 Feb 2021 00:11:58 +0100 Subject: [PATCH 3/3] ChangeLog: document --serverpublicip #954 Signed-off-by: Christian Hoffmann --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index a543adceb2..0ea8a77b27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,9 @@ - remove ConsoleWriterFactory (#926) +- add new --serverpublicip option to support central servers behind NAT, + coded by hoffie (#954) + TODO fix crash if settings are changed in ASIO4All during a connection (contained in #796)