| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*
- * 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
|