DynDNS.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "NativeFeatureIncludes.h"
  11. #if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1
  12. #include "TCPInterface.h"
  13. #include "RakNetSocket2.h"
  14. #include "DynDNS.h"
  15. #include "GetTime.h"
  16. #include "Base64Encoder.h"
  17. using namespace RakNet;
  18. struct DynDnsResult
  19. {
  20. const char *description;
  21. const char *code;
  22. DynDnsResultCode resultCode;
  23. };
  24. DynDnsResult resultTable[13] =
  25. {
  26. // See http://www.dyndns.com/developers/specs/flow.pdf
  27. {"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!
  28. {"No change", "nochg", RC_NO_CHANGE},
  29. {"Host has been blocked. You will need to contact DynDNS to reenable.", "abuse", RC_ABUSE},
  30. {"Useragent is blocked", "badagent", RC_BAD_AGENT},
  31. {"Username/password pair bad", "badauth", RC_BAD_AUTH},
  32. {"Bad system parameter", "badsys", RC_BAD_SYS},
  33. {"DNS inconsistency", "dnserr", RC_DNS_ERROR},
  34. {"Paid account feature", "!donator", RC_NOT_DONATOR},
  35. {"No such host in system", "nohost", RC_NO_HOST},
  36. {"Invalid hostname format", "notfqdn", RC_NOT_FQDN},
  37. {"Serious error", "numhost", RC_NUM_HOST},
  38. {"This host exists, but does not belong to you", "!yours", RC_NOT_YOURS},
  39. {"911", "911", RC_911}
  40. };
  41. DynDNS::DynDNS()
  42. {
  43. connectPhase=CP_IDLE;
  44. tcp=0;
  45. }
  46. DynDNS::~DynDNS()
  47. {
  48. if (tcp)
  49. RakNet::OP_DELETE(tcp, _FILE_AND_LINE_);
  50. }
  51. void DynDNS::Stop(void)
  52. {
  53. tcp->Stop();
  54. connectPhase = CP_IDLE;
  55. RakNet::OP_DELETE(tcp, _FILE_AND_LINE_);
  56. tcp=0;
  57. }
  58. // newIPAddress is optional - if left out, DynDNS will use whatever it receives
  59. void DynDNS::UpdateHostIPAsynch(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword )
  60. {
  61. myIPStr[0]=0;
  62. if (tcp==0)
  63. tcp = RakNet::OP_NEW<TCPInterface>(_FILE_AND_LINE_);
  64. connectPhase = CP_IDLE;
  65. host = dnsHost;
  66. if (tcp->Start(0, 1)==false)
  67. {
  68. SetCompleted(RC_TCP_FAILED_TO_START, "TCP failed to start");
  69. return;
  70. }
  71. connectPhase = CP_CONNECTING_TO_CHECKIP;
  72. tcp->Connect("checkip.dyndns.org", 80, false);
  73. // See https://www.dyndns.com/developers/specs/syntax.html
  74. getString="GET /nic/update?hostname=";
  75. getString+=dnsHost;
  76. if (newIPAddress)
  77. {
  78. getString+="&myip=";
  79. getString+=newIPAddress;
  80. }
  81. getString+="&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0\n";
  82. getString+="Host: members.dyndns.org\n";
  83. getString+="Authorization: Basic ";
  84. char outputData[512];
  85. Base64Encoding((const unsigned char*) usernameAndPassword, (int) strlen(usernameAndPassword), outputData);
  86. getString+=outputData;
  87. getString+="User-Agent: Jenkins Software LLC - PC - 1.0\n\n";
  88. }
  89. void DynDNS::Update(void)
  90. {
  91. if (connectPhase==CP_IDLE)
  92. return;
  93. serverAddress=tcp->HasFailedConnectionAttempt();
  94. if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS)
  95. {
  96. SetCompleted(RC_TCP_DID_NOT_CONNECT, "Could not connect to DynDNS");
  97. return;
  98. }
  99. serverAddress=tcp->HasCompletedConnectionAttempt();
  100. if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS)
  101. {
  102. if (connectPhase == CP_CONNECTING_TO_CHECKIP)
  103. {
  104. checkIpAddress=serverAddress;
  105. connectPhase = CP_WAITING_FOR_CHECKIP_RESPONSE;
  106. 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
  107. }
  108. else
  109. {
  110. connectPhase = CP_WAITING_FOR_DYNDNS_RESPONSE;
  111. tcp->Send(getString.C_String(), (unsigned int) getString.GetLength(), serverAddress, false);
  112. }
  113. phaseTimeout=RakNet::GetTime()+1000;
  114. }
  115. if (connectPhase==CP_WAITING_FOR_CHECKIP_RESPONSE && RakNet::GetTime()>phaseTimeout)
  116. {
  117. connectPhase = CP_CONNECTING_TO_DYNDNS;
  118. tcp->CloseConnection(checkIpAddress);
  119. tcp->Connect("members.dyndns.org", 80, false);
  120. }
  121. else if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE && RakNet::GetTime()>phaseTimeout)
  122. {
  123. SetCompleted(RC_DYNDNS_TIMEOUT, "DynDNS did not respond");
  124. return;
  125. }
  126. Packet *packet = tcp->Receive();
  127. if (packet)
  128. {
  129. if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE)
  130. {
  131. unsigned int i;
  132. char *result;
  133. result=strstr((char*) packet->data, "Connection: close");
  134. if (result!=0)
  135. {
  136. result+=strlen("Connection: close");
  137. while (*result && ((*result=='\r') || (*result=='\n') || (*result==' ')) )
  138. result++;
  139. for (i=0; i < 13; i++)
  140. {
  141. if (strncmp(resultTable[i].code, result, strlen(resultTable[i].code))==0)
  142. {
  143. if (resultTable[i].resultCode==RC_SUCCESS)
  144. {
  145. // Read my external IP into myIPStr
  146. // Advance until we hit a number
  147. while (*result && ((*result<'0') || (*result>'9')) )
  148. result++;
  149. if (*result)
  150. {
  151. SystemAddress parser;
  152. parser.FromString(result);
  153. parser.ToString(false, myIPStr);
  154. }
  155. }
  156. tcp->DeallocatePacket(packet);
  157. SetCompleted(resultTable[i].resultCode, resultTable[i].description);
  158. break;
  159. }
  160. }
  161. if (i==13)
  162. {
  163. tcp->DeallocatePacket(packet);
  164. SetCompleted(RC_UNKNOWN_RESULT, "DynDNS returned unknown result");
  165. }
  166. }
  167. else
  168. {
  169. tcp->DeallocatePacket(packet);
  170. SetCompleted(RC_PARSING_FAILURE, "Parsing failure on returned string from DynDNS");
  171. }
  172. return;
  173. }
  174. else
  175. {
  176. /*
  177. HTTP/1.1 200 OK
  178. Content-Type: text/html
  179. Server: DynDNS-CheckIP/1.0
  180. Connection: close
  181. Cache-Control: no-cache
  182. Pragma: no-cache
  183. Content-Length: 105
  184. <html><head><title>Current IP Check</title></head><body>Current IP Address: 98.1
  185. 89.219.22</body></html>
  186. Connection to host lost.
  187. */
  188. char *result;
  189. result=strstr((char*) packet->data, "Current IP Address: ");
  190. if (result!=0)
  191. {
  192. result+=strlen("Current IP Address: ");
  193. SystemAddress myIp;
  194. myIp.FromString(result);
  195. myIp.ToString(false, myIPStr);
  196. char existingHost[65];
  197. existingHost[0]=0;
  198. // Resolve DNS we are setting. If equal to current then abort
  199. RakNetSocket2::DomainNameToIP(host.C_String(), existingHost);
  200. if (existingHost && strcmp(existingHost, myIPStr)==0)
  201. {
  202. // DynDNS considers setting the IP to what it is already set abuse
  203. tcp->DeallocatePacket(packet);
  204. SetCompleted(RC_DNS_ALREADY_SET, "No action needed");
  205. return;
  206. }
  207. }
  208. tcp->DeallocatePacket(packet);
  209. tcp->CloseConnection(packet->systemAddress);
  210. connectPhase = CP_CONNECTING_TO_DYNDNS;
  211. tcp->Connect("members.dyndns.org", 80, false);
  212. }
  213. }
  214. if (tcp->HasLostConnection()!=UNASSIGNED_SYSTEM_ADDRESS)
  215. {
  216. if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE)
  217. {
  218. SetCompleted(RC_CONNECTION_LOST_WITHOUT_RESPONSE, "Connection lost to DynDNS during GET operation");
  219. }
  220. }
  221. }
  222. #endif // _RAKNET_SUPPORT_DynDNS
粤ICP备19079148号