1
0
forked from 0ad/0ad

Get the public IP from the lobby if not using STUN.

Follow-up to 1a8de6d2b8. This makes it again possible to host without
STUN via the lobby.
The lobby bot will answer the host "Register" command with the external
IP. This is only sent to the host, avoiding IP leakage.

There is a small window in which a client might try to join and the
public IP isn't up, and the request goes through, but that seems rather
unlikely to be a problem in practice.

Refs #5913

Differential Revision: https://code.wildfiregames.com/D3490
This was SVN commit r24858.
This commit is contained in:
wraitii 2021-02-08 15:47:34 +00:00
parent c009eae0a5
commit d078df0b85
5 changed files with 23 additions and 22 deletions

View File

@ -129,7 +129,7 @@ GameListQuery::GameListQuery(const glooxwrapper::Tag* tag)
if (!tag || tag->name() != "query" || tag->xmlns() != XMLNS_GAMELIST)
return;
const glooxwrapper::Tag* c = tag->findTag_clone("query/game");
const glooxwrapper::Tag* c = tag->findTag_clone("query/command");
if (c)
m_Command = c->cdata();
glooxwrapper::Tag::free(c);

View File

@ -430,8 +430,6 @@ void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::
GameListQuery* g = new GameListQuery();
g->m_Command = "register";
glooxwrapper::Tag* game = glooxwrapper::Tag::allocate("game");
// Add a fake ip which will be overwritten by the ip stamp XMPP module on the server.
game->addAttribute("ip", "fake");
// Iterate through all the properties reported and add them to the stanza.
std::vector<std::string> properties;
@ -861,6 +859,23 @@ bool XmppClient::handleIq(const glooxwrapper::IQ& iq)
}
if (gq)
{
if (iq.from().full() == m_xpartamuppId && gq->m_Command == "register" && g_NetServer && !g_NetServer->GetUseSTUN())
{
if (gq->m_GameList.empty())
{
LOGWARNING("XmppClient: Received empty game list in response to Game Register");
return true;
}
std::string publicIP = gq->m_GameList.front()->findAttribute("ip").to_string();
if (publicIP.empty())
{
LOGWARNING("XmppClient: Received game with no IP in response to Game Register");
return true;
}
g_NetServer->SetConnectionData(publicIP, g_NetServer->GetPublicPort(), false);
return true;
}
for (const glooxwrapper::Tag* const& t : m_GameList)
glooxwrapper::Tag::free(t);
m_GameList.clear();

View File

@ -371,11 +371,6 @@ bool STUNRequestAndResponse(ENetHost& transactionHost)
ParseStunResponse(buffer);
}
bool StunClient::GetPublicIp(CStr8& ip, u16 port)
{
return FindStunEndpointHost(ip, port);
}
bool StunClient::FindStunEndpointHost(CStr8& ip, u16& port)
{
ENetAddress hostAddr{ENET_HOST_ANY, static_cast<u16>(port)};

View File

@ -40,8 +40,6 @@ bool FindStunEndpointHost(CStr8& ip, u16& port);
bool FindStunEndpointJoin(ENetHost& transactionHost, StunClient::StunEndpoint& stunEndpoint);
void SendHolePunchingMessages(ENetHost& enetClient, const std::string& serverAddress, u16 serverPort);
bool GetPublicIp(CStr8& ip, u16 port);
}
#endif // STUNCLIENT_H

View File

@ -88,22 +88,15 @@ void JSI_Network::StartNetworkHost(ScriptInterface::CmptPrivate* pCmptPrivate, c
bool hasLobby = !!g_XmppClient;
g_NetServer = new CNetServer(hasLobby);
// In lobby, we send our public ip and port on request to the players, who want to connect.
// In both cases we need to ping stun server to get our public ip. If we want to host via stun,
// we need port as well.
// In either case we need to know our public IP. If using STUN, we'll use that,
// otherwise, the lobby's reponse to the game registration stanza will tell us our public IP.
if (hasLobby)
{
CStr ip;
if (!useSTUN)
{
if (!StunClient::GetPublicIp(ip, serverPort))
{
ScriptRequest rq(pCmptPrivate->pScriptInterface);
ScriptException::Raise(rq, "Failed to get public ip.");
SAFE_DELETE(g_NetServer);
return;
}
g_NetServer->SetConnectionData(ip, serverPort, false);
}
// Don't store IP - the lobby bot will send it later.
// (if a client tries to connect before it's setup, they'll be disconnected)
g_NetServer->SetConnectionData("", serverPort, false);
else
{
u16 port = serverPort;