mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
250 lines
6.7 KiB
C++
250 lines
6.7 KiB
C++
/*
|
|
* Copyright (c) 2014, Oculus VR, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
|
|
#include "NativeFeatureIncludes.h"
|
|
#if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1
|
|
|
|
#include "TCPInterface.h"
|
|
#include "RakNetSocket2.h"
|
|
#include "DynDNS.h"
|
|
#include "GetTime.h"
|
|
#include "Base64Encoder.h"
|
|
|
|
using namespace RakNet;
|
|
|
|
struct DynDnsResult
|
|
{
|
|
const char *description;
|
|
const char *code;
|
|
DynDnsResultCode resultCode;
|
|
};
|
|
|
|
DynDnsResult resultTable[13] =
|
|
{
|
|
// See http://www.dyndns.com/developers/specs/flow.pdf
|
|
{"DNS update success.\nPlease wait up to 60 seconds for the change to take effect.\n", "good", RC_SUCCESS}, // Even with success, it takes time for the cache to update!
|
|
{"No change", "nochg", RC_NO_CHANGE},
|
|
{"Host has been blocked. You will need to contact DynDNS to reenable.", "abuse", RC_ABUSE},
|
|
{"Useragent is blocked", "badagent", RC_BAD_AGENT},
|
|
{"Username/password pair bad", "badauth", RC_BAD_AUTH},
|
|
{"Bad system parameter", "badsys", RC_BAD_SYS},
|
|
{"DNS inconsistency", "dnserr", RC_DNS_ERROR},
|
|
{"Paid account feature", "!donator", RC_NOT_DONATOR},
|
|
{"No such host in system", "nohost", RC_NO_HOST},
|
|
{"Invalid hostname format", "notfqdn", RC_NOT_FQDN},
|
|
{"Serious error", "numhost", RC_NUM_HOST},
|
|
{"This host exists, but does not belong to you", "!yours", RC_NOT_YOURS},
|
|
{"911", "911", RC_911}
|
|
};
|
|
DynDNS::DynDNS()
|
|
{
|
|
connectPhase=CP_IDLE;
|
|
tcp=0;
|
|
}
|
|
DynDNS::~DynDNS()
|
|
{
|
|
if (tcp)
|
|
RakNet::OP_DELETE(tcp, _FILE_AND_LINE_);
|
|
}
|
|
void DynDNS::Stop(void)
|
|
{
|
|
tcp->Stop();
|
|
connectPhase = CP_IDLE;
|
|
RakNet::OP_DELETE(tcp, _FILE_AND_LINE_);
|
|
tcp=0;
|
|
}
|
|
|
|
|
|
// newIPAddress is optional - if left out, DynDNS will use whatever it receives
|
|
void DynDNS::UpdateHostIPAsynch(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword )
|
|
{
|
|
myIPStr[0]=0;
|
|
|
|
if (tcp==0)
|
|
tcp = RakNet::OP_NEW<TCPInterface>(_FILE_AND_LINE_);
|
|
connectPhase = CP_IDLE;
|
|
host = dnsHost;
|
|
|
|
if (tcp->Start(0, 1)==false)
|
|
{
|
|
SetCompleted(RC_TCP_FAILED_TO_START, "TCP failed to start");
|
|
return;
|
|
}
|
|
|
|
connectPhase = CP_CONNECTING_TO_CHECKIP;
|
|
tcp->Connect("checkip.dyndns.org", 80, false);
|
|
|
|
// See https://www.dyndns.com/developers/specs/syntax.html
|
|
getString="GET /nic/update?hostname=";
|
|
getString+=dnsHost;
|
|
if (newIPAddress)
|
|
{
|
|
getString+="&myip=";
|
|
getString+=newIPAddress;
|
|
}
|
|
getString+="&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0\n";
|
|
getString+="Host: members.dyndns.org\n";
|
|
getString+="Authorization: Basic ";
|
|
char outputData[512];
|
|
Base64Encoding((const unsigned char*) usernameAndPassword, (int) strlen(usernameAndPassword), outputData);
|
|
getString+=outputData;
|
|
getString+="User-Agent: Jenkins Software LLC - PC - 1.0\n\n";
|
|
}
|
|
void DynDNS::Update(void)
|
|
{
|
|
if (connectPhase==CP_IDLE)
|
|
return;
|
|
|
|
serverAddress=tcp->HasFailedConnectionAttempt();
|
|
if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
SetCompleted(RC_TCP_DID_NOT_CONNECT, "Could not connect to DynDNS");
|
|
return;
|
|
}
|
|
|
|
serverAddress=tcp->HasCompletedConnectionAttempt();
|
|
if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
if (connectPhase == CP_CONNECTING_TO_CHECKIP)
|
|
{
|
|
checkIpAddress=serverAddress;
|
|
connectPhase = CP_WAITING_FOR_CHECKIP_RESPONSE;
|
|
tcp->Send("GET\n\n", (unsigned int) strlen("GET\n\n"), serverAddress, false); // Needs 2 newlines! This is not documented and wasted a lot of my time
|
|
}
|
|
else
|
|
{
|
|
connectPhase = CP_WAITING_FOR_DYNDNS_RESPONSE;
|
|
tcp->Send(getString.C_String(), (unsigned int) getString.GetLength(), serverAddress, false);
|
|
}
|
|
phaseTimeout=RakNet::GetTime()+1000;
|
|
}
|
|
|
|
if (connectPhase==CP_WAITING_FOR_CHECKIP_RESPONSE && RakNet::GetTime()>phaseTimeout)
|
|
{
|
|
connectPhase = CP_CONNECTING_TO_DYNDNS;
|
|
tcp->CloseConnection(checkIpAddress);
|
|
tcp->Connect("members.dyndns.org", 80, false);
|
|
}
|
|
else if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE && RakNet::GetTime()>phaseTimeout)
|
|
{
|
|
SetCompleted(RC_DYNDNS_TIMEOUT, "DynDNS did not respond");
|
|
return;
|
|
}
|
|
|
|
Packet *packet = tcp->Receive();
|
|
if (packet)
|
|
{
|
|
if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE)
|
|
{
|
|
unsigned int i;
|
|
|
|
char *result;
|
|
result=strstr((char*) packet->data, "Connection: close");
|
|
if (result!=0)
|
|
{
|
|
result+=strlen("Connection: close");
|
|
while (*result && ((*result=='\r') || (*result=='\n') || (*result==' ')) )
|
|
result++;
|
|
for (i=0; i < 13; i++)
|
|
{
|
|
if (strncmp(resultTable[i].code, result, strlen(resultTable[i].code))==0)
|
|
{
|
|
if (resultTable[i].resultCode==RC_SUCCESS)
|
|
{
|
|
// Read my external IP into myIPStr
|
|
// Advance until we hit a number
|
|
while (*result && ((*result<'0') || (*result>'9')) )
|
|
result++;
|
|
if (*result)
|
|
{
|
|
SystemAddress parser;
|
|
parser.FromString(result);
|
|
parser.ToString(false, myIPStr);
|
|
}
|
|
}
|
|
tcp->DeallocatePacket(packet);
|
|
SetCompleted(resultTable[i].resultCode, resultTable[i].description);
|
|
break;
|
|
}
|
|
}
|
|
if (i==13)
|
|
{
|
|
tcp->DeallocatePacket(packet);
|
|
SetCompleted(RC_UNKNOWN_RESULT, "DynDNS returned unknown result");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tcp->DeallocatePacket(packet);
|
|
SetCompleted(RC_PARSING_FAILURE, "Parsing failure on returned string from DynDNS");
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
HTTP/1.1 200 OK
|
|
Content-Type: text/html
|
|
Server: DynDNS-CheckIP/1.0
|
|
Connection: close
|
|
Cache-Control: no-cache
|
|
Pragma: no-cache
|
|
Content-Length: 105
|
|
|
|
<html><head><title>Current IP Check</title></head><body>Current IP Address: 98.1
|
|
89.219.22</body></html>
|
|
|
|
|
|
Connection to host lost.
|
|
*/
|
|
|
|
char *result;
|
|
result=strstr((char*) packet->data, "Current IP Address: ");
|
|
if (result!=0)
|
|
{
|
|
result+=strlen("Current IP Address: ");
|
|
SystemAddress myIp;
|
|
myIp.FromString(result);
|
|
myIp.ToString(false, myIPStr);
|
|
|
|
char existingHost[65];
|
|
existingHost[0]=0;
|
|
// Resolve DNS we are setting. If equal to current then abort
|
|
RakNetSocket2::DomainNameToIP(host.C_String(), existingHost);
|
|
if (existingHost && strcmp(existingHost, myIPStr)==0)
|
|
{
|
|
// DynDNS considers setting the IP to what it is already set abuse
|
|
tcp->DeallocatePacket(packet);
|
|
SetCompleted(RC_DNS_ALREADY_SET, "No action needed");
|
|
return;
|
|
}
|
|
}
|
|
|
|
tcp->DeallocatePacket(packet);
|
|
tcp->CloseConnection(packet->systemAddress);
|
|
|
|
connectPhase = CP_CONNECTING_TO_DYNDNS;
|
|
tcp->Connect("members.dyndns.org", 80, false);
|
|
}
|
|
}
|
|
|
|
if (tcp->HasLostConnection()!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE)
|
|
{
|
|
SetCompleted(RC_CONNECTION_LOST_WITHOUT_RESPONSE, "Connection lost to DynDNS during GET operation");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endif // _RAKNET_SUPPORT_DynDNS
|