-
Notifications
You must be signed in to change notification settings - Fork 247
Add IPv6 support for Directories (still incomplete) #3809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0532fa1
dfeca47
2bd0d26
0b794c1
6848938
b4f9f7e
20f4d8d
d4efb29
b5e92aa
5172a2a
238d0c1
657a94f
70df0de
d0c74d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,6 +77,21 @@ from clients not on the same LAN as the directory. | |
| /* Implementation *************************************************************/ | ||
|
|
||
| // --- CServerListEntry --- | ||
| CServerListEntry::CServerListEntry() : CServerInfo ( CHostAddress(), CHostAddress(), "", QLocale::AnyCountry, "", 0, false ) { UpdateRegistration(); } | ||
|
|
||
| CServerListEntry::CServerListEntry ( const CHostAddress& NHAddr, const CHostAddress& NLHAddr, const CServerCoreInfo& NewCoreServerInfo ) : | ||
| CServerInfo ( NHAddr, | ||
| NLHAddr, | ||
| NewCoreServerInfo.strName, | ||
| NewCoreServerInfo.eCountry, | ||
| NewCoreServerInfo.strCity, | ||
| NewCoreServerInfo.iMaxNumClients, | ||
| NewCoreServerInfo.bPermanentOnline ), | ||
| token ( QRandomGenerator::system()->generate() ) | ||
| { | ||
| UpdateRegistration(); | ||
| } | ||
|
|
||
| CServerListEntry CServerListEntry::parse ( QString strHAddr, | ||
| QString strLHAddr, | ||
| QString sName, | ||
|
|
@@ -130,8 +145,8 @@ QString CServerListEntry::toCSV() | |
| { | ||
| QStringList sl; | ||
|
|
||
| sl.append ( this->HostAddr.toString() ); | ||
| sl.append ( this->LHostAddr.toString() ); | ||
| sl.append ( this->HostAddr4.toString() ); | ||
| sl.append ( this->LHostAddr4.toString() ); | ||
|
Comment on lines
+148
to
+149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Persist IPv6-only registrations.
🤖 Prompt for AI Agents |
||
| sl.append ( ToBase64 ( this->strName ) ); | ||
| sl.append ( ToBase64 ( this->strCity ) ); | ||
| sl.append ( QString::number ( this->eCountry ) ); | ||
|
|
@@ -212,7 +227,9 @@ CServerListManager::CServerListManager ( CServer* pServer, | |
| * | ||
| * If we are a directory, we assume that we are a permanent server. | ||
| */ | ||
| CServerListEntry ThisServerListEntry ( haServerAddr, ServerPublicIP, "", QLocale::system().country(), "", iNumChannels, bIsDirectory ); | ||
| CServerListEntry ThisServerListEntry ( haServerAddr, | ||
| ServerPublicIP, | ||
| CServerCoreInfo ( "", QLocale::system().country(), "", iNumChannels, bIsDirectory ) ); | ||
|
|
||
| // parse the server info string according to definition: | ||
| // [this server name];[this server city];[this server country as QLocale ID] (; ... ignored) | ||
|
|
@@ -543,7 +560,7 @@ void CServerListManager::OnTimerPingServerInList() | |
| for ( int iIdx = 1; iIdx < iCurServerListSize; iIdx++ ) | ||
| { | ||
| // send empty message to keep NAT port open at registered server | ||
| pConnLessProtocol->CreateCLEmptyMes ( ServerList[iIdx].HostAddr ); | ||
| pConnLessProtocol->CreateCLEmptyMes ( ServerList[iIdx].HostAddr4 ); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Use the registered address family for directory keep-alives. 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
|
|
||
|
|
@@ -560,7 +577,7 @@ void CServerListManager::OnTimerPollList() | |
| if ( ServerList[iIdx].RegisterTime.elapsed() > ( SERVLIST_TIME_OUT_MINUTES * 60000 ) ) | ||
| { | ||
| // remove this list entry | ||
| vecRemovedHostAddr.Add ( ServerList[iIdx].HostAddr ); | ||
| vecRemovedHostAddr.Add ( ServerList[iIdx].HostAddr4 ); | ||
| ServerList.removeAt ( iIdx ); | ||
| } | ||
| } | ||
|
|
@@ -637,7 +654,7 @@ void CServerListManager::Append ( const CHostAddress& InetAddr, | |
| else | ||
| { | ||
| // update all data and call update registration function | ||
| ServerList[iSelIdx].LHostAddr = LInetAddr; | ||
| ServerList[iSelIdx].LHostAddr4 = LInetAddr; | ||
| ServerList[iSelIdx].strName = ServerInfo.strName; | ||
| ServerList[iSelIdx].eCountry = ServerInfo.eCountry; | ||
| ServerList[iSelIdx].strCity = ServerInfo.strCity; | ||
|
|
@@ -695,12 +712,12 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr ) | |
| bool clientIsInternal = NetworkUtil::IsPrivateNetworkIP ( InetAddr.InetAddr ); | ||
|
|
||
| CHostAddress clientPublicAddr = InetAddr; | ||
| if ( clientIsInternal && CHostAddress().InetAddr != ServerList[0].LHostAddr.InetAddr && | ||
| !NetworkUtil::IsPrivateNetworkIP ( ServerList[0].LHostAddr.InetAddr ) ) | ||
| if ( clientIsInternal && CHostAddress().InetAddr != ServerList[0].LHostAddr4.InetAddr && | ||
| !NetworkUtil::IsPrivateNetworkIP ( ServerList[0].LHostAddr4.InetAddr ) ) | ||
| { | ||
| // client and directory on same LAN, directory has public IP set, that should be suitable for the | ||
| // client, too (i.e. same router with same public IP will be used for both), so use it for client public IP | ||
| clientPublicAddr.InetAddr = ServerList[0].LHostAddr.InetAddr; | ||
| clientPublicAddr.InetAddr = ServerList[0].LHostAddr4.InetAddr; | ||
| } | ||
|
|
||
| const ushort iCurServerListSize = static_cast<ushort> ( ServerList.size() ); | ||
|
|
@@ -709,8 +726,8 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr ) | |
| CVector<CServerInfo> vecServerInfo ( iCurServerListSize ); | ||
|
|
||
| // copy list item for the directory and just let the protocol sort out the actual details | ||
| vecServerInfo[0] = ServerList[0]; | ||
| vecServerInfo[0].HostAddr = CHostAddress(); | ||
| vecServerInfo[0] = ServerList[0]; | ||
| vecServerInfo[0].HostAddr4 = CHostAddress(); | ||
|
|
||
| // copy the list (we have to copy it since the message requires a vector but the list is actually stored in a QList object | ||
| // and not in a vector object) | ||
|
|
@@ -719,25 +736,25 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr ) | |
| // copy list item | ||
| CServerInfo& siCurListEntry = vecServerInfo[iIdx] = ServerList[iIdx]; | ||
|
|
||
| bool serverIsInternal = NetworkUtil::IsPrivateNetworkIP ( siCurListEntry.HostAddr.InetAddr ); | ||
| bool serverIsInternal = NetworkUtil::IsPrivateNetworkIP ( siCurListEntry.HostAddr4.InetAddr ); | ||
|
|
||
| bool wantHostAddr = clientIsInternal /* HostAddr is local IP if local server else external IP, so do not replace */ || | ||
| bool wantHostAddr = clientIsInternal /* HostAddr4 is local IP if local server else external IP, so do not replace */ || | ||
| ( !serverIsInternal && | ||
| InetAddr.InetAddr != siCurListEntry.HostAddr.InetAddr /* external server and client have different public IPs */ ); | ||
| InetAddr.InetAddr != siCurListEntry.HostAddr4.InetAddr /* external server and client have different public IPs */ ); | ||
|
|
||
| if ( !wantHostAddr ) | ||
| { | ||
| vecServerInfo[iIdx].HostAddr = siCurListEntry.LHostAddr; | ||
| vecServerInfo[iIdx].HostAddr4 = siCurListEntry.LHostAddr4; | ||
| } | ||
|
|
||
| // do not send a "ping" to a server local to the directory (no need) | ||
| if ( !serverIsInternal ) | ||
| { | ||
| // create "send empty message" for all other registered servers | ||
| // this causes the server (vecServerInfo[iIdx].HostAddr) | ||
| // this causes the server (vecServerInfo[iIdx].HostAddr4) | ||
| // to send a "reply" to the client (InetAddr or best guess public IP address if internal to directory) | ||
| // - with the intent of opening the server firewall for the client | ||
| pConnLessProtocol->CreateCLSendEmptyMesMes ( siCurListEntry.HostAddr, clientPublicAddr ); | ||
| pConnLessProtocol->CreateCLSendEmptyMesMes ( siCurListEntry.HostAddr4, clientPublicAddr ); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -749,6 +766,31 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr ) | |
| } | ||
| } | ||
|
|
||
| // fetch copy of registered server list for use by JSON-RPC | ||
| // return false if not a directory | ||
| bool CServerListManager::GetDirectoryServerList ( CVector<CServerInfo>& vecServerInfo ) | ||
| { | ||
| QMutexLocker locker ( &Mutex ); | ||
|
|
||
| if ( !bIsDirectory ) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| const ushort iCurServerListSize = static_cast<ushort> ( ServerList.size() ); | ||
|
|
||
| // allocate memory for the entire list | ||
| vecServerInfo.Init ( iCurServerListSize ); | ||
|
|
||
| // copy the list | ||
| for ( int iIdx = 0; iIdx < iCurServerListSize; iIdx++ ) | ||
| { | ||
| vecServerInfo[iIdx] = ServerList[iIdx]; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int CServerListManager::IndexOf ( const CHostAddress& haSearchTerm ) | ||
| { | ||
| // Called with lock set. | ||
|
|
@@ -758,7 +800,11 @@ int CServerListManager::IndexOf ( const CHostAddress& haSearchTerm ) | |
| // (i.e., this server). | ||
| for ( int iIdx = ServerList.size() - 1; iIdx > 0; iIdx-- ) | ||
| { | ||
| if ( ServerList[iIdx].HostAddr == haSearchTerm ) | ||
| if ( haSearchTerm.InetAddr.protocol() == QAbstractSocket::IPv4Protocol && ServerList[iIdx].HostAddr4 == haSearchTerm ) | ||
| { | ||
| return iIdx; | ||
| } | ||
| if ( haSearchTerm.InetAddr.protocol() == QAbstractSocket::IPv6Protocol && ServerList[iIdx].HostAddr6 == haSearchTerm ) | ||
| { | ||
| return iIdx; | ||
| } | ||
|
|
@@ -847,15 +893,15 @@ bool CServerListManager::Load() | |
| pServer->IsIPv6Available() ); | ||
|
|
||
| // We expect servers to have addresses... | ||
| if ( ( CHostAddress() == serverListEntry.HostAddr ) ) | ||
| if ( ( CHostAddress() == serverListEntry.HostAddr4 ) ) | ||
| { | ||
| qWarning() << qUtf8Printable ( QString ( "Could not parse '%1' successfully - invalid host" ).arg ( line ) ); | ||
| continue; | ||
| } | ||
|
|
||
| qInfo() << qUtf8Printable ( QString ( "Loading registration for %1 (%2): %3" ) | ||
| .arg ( serverListEntry.HostAddr.toString() ) | ||
| .arg ( serverListEntry.LHostAddr.toString() ) | ||
| .arg ( serverListEntry.HostAddr4.toString() ) | ||
| .arg ( serverListEntry.LHostAddr4.toString() ) | ||
| .arg ( serverListEntry.strName ) ); | ||
| ServerList.append ( serverListEntry ); | ||
| } | ||
|
|
@@ -889,8 +935,8 @@ void CServerListManager::Save() | |
| for ( int iIdx = ServerList.size() - 1; iIdx > 0; iIdx-- ) | ||
| { | ||
| qInfo() << qUtf8Printable ( QString ( tr ( "Saving registration for %1 (%2): %3" ) ) | ||
| .arg ( ServerList[iIdx].HostAddr.toString() ) | ||
| .arg ( ServerList[iIdx].LHostAddr.toString() ) | ||
| .arg ( ServerList[iIdx].HostAddr4.toString() ) | ||
| .arg ( ServerList[iIdx].LHostAddr4.toString() ) | ||
| .arg ( ServerList[iIdx].strName ) ); | ||
| out << ServerList[iIdx].toCSV() << '\n'; | ||
| } | ||
|
|
@@ -1012,7 +1058,7 @@ void CServerListManager::SetRegistered ( const bool bIsRegister ) | |
| // Allow IPv4 only for communicating with Directories | ||
| // Use SRV DNS discovery for directory connections, fallback to A/AAAA if none. | ||
| const QString strNetworkAddress = NetworkUtil::GetDirectoryAddress ( DirectoryType, strDirectoryAddress ); | ||
| const bool bDirectoryAddressValid = NetworkUtil::ParseNetworkAddress ( strNetworkAddress, DirectoryAddress, false ); | ||
| const bool bDirectoryAddressValid = NetworkUtil::ParseNetworkAddress ( strNetworkAddress, DirectoryAddress, pServer->IsIPv6Available() ); | ||
|
|
||
| // lock the mutex again now that the address has been resolved. | ||
| locker.relock(); | ||
|
|
@@ -1027,7 +1073,18 @@ void CServerListManager::SetRegistered ( const bool bIsRegister ) | |
| // For a registered server, the server properties are stored in the | ||
| // very first item in the server list (which is actually no server list | ||
| // but just one item long for the registered server). | ||
| pConnLessProtocol->CreateCLRegisterServerExMes ( DirectoryAddress, ServerList[0].LHostAddr, ServerList[0] ); | ||
| if ( DirectoryAddress.InetAddr.protocol() == QAbstractSocket::IPv4Protocol ) | ||
| { | ||
| pConnLessProtocol->CreateCLRegisterServerExMes ( DirectoryAddress, ServerPublicIP, ServerList[0] ); | ||
| } | ||
| else if ( DirectoryAddress.InetAddr.protocol() == QAbstractSocket::IPv6Protocol ) | ||
| { | ||
| pConnLessProtocol->CreateCLRegisterServerExMes ( DirectoryAddress, ServerPublicIP6, ServerList[0] ); | ||
| } | ||
| else | ||
| { | ||
| SetSvrRegStatus ( SRS_BAD_ADDRESS ); | ||
| } | ||
| } | ||
| else | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🔎 Supported by static analysis
🤖 get_repo_knowledge executed:
get_repo_knowledge jamulussoftware/jamulus /tmp/coderabbit-repo-knowledge/jamulussoftware-jamulus-e32ae91c/architecture /tmp/coderabbit-repo-knowledge/jamulussoftware-jamulus-e32ae91c/conventionsLength of output: 4956
🏁 Script executed:
Repository: jamulussoftware/jamulus
Length of output: 50379
🏁 Script executed:
Repository: jamulussoftware/jamulus
Length of output: 50379
🏁 Script executed:
Repository: jamulussoftware/jamulus
Length of output: 8630
🏁 Script executed:
Repository: jamulussoftware/jamulus
Length of output: 27902
Add an IPv6-capable server-list wire format.
For an IPv6 registration,
CServerInfostores the endpoint inHostAddr6, whileHostAddr4remains the default address with port0. Both serializers encodeHostAddr4, and both evaluators decode only four IPv4 bytes. The client therefore receives0.0.0.0:0instead of the registered endpoint.Define a versioned or address-family-aware format, update both producers and consumers, and add IPv6-only regression coverage for both message types.
📍 Affects 1 file
src/protocol.cpp#L2112-L2116(this comment)src/protocol.cpp#L2235-L2239🤖 Prompt for AI Agents