1
0

dns_srv.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * dns_srv.c
  3. *
  4. * This file contains the code for KMS SRV record lookup in DNS (_vlmcs._tcp.example.com IN SRV 0 0 1688 mykms.example.com)
  5. *
  6. */
  7. #ifndef CONFIG
  8. #define CONFIG "config.h"
  9. #endif // CONFIG
  10. #include CONFIG
  11. #ifndef NO_DNS
  12. #include "dns_srv.h"
  13. #include <string.h>
  14. #include <stdio.h>
  15. #ifndef _WIN32
  16. #include <signal.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #include <errno.h>
  20. #include <netdb.h>
  21. //#ifndef DNS_PARSER_INTERNAL
  22. #if __ANDROID__
  23. #include <netinet/in.h>
  24. #include "nameser.h"
  25. #include "resolv.h"
  26. #else // other Unix non-Android
  27. #include <netinet/in.h>
  28. #include <arpa/nameser.h>
  29. #include <resolv.h>
  30. #endif // other Unix non-Android
  31. //#endif // DNS_PARSER_INTERNAL
  32. #else // WIN32
  33. #include <windns.h>
  34. #endif // WIN32
  35. #include "helpers.h"
  36. #include "output.h"
  37. #include "endian.h"
  38. #if defined(DNS_PARSER_INTERNAL) && !defined(_WIN32)
  39. #include "ns_name.h"
  40. #include "ns_parse.h"
  41. // Define macros to redirect DNS parser functions to internal versions
  42. #undef ns_msg
  43. #undef ns_initparse
  44. #undef ns_parserr
  45. #undef ns_rr
  46. #undef ns_name_uncompress
  47. #undef ns_msg_base
  48. #undef ns_msg_end
  49. #undef ns_rr_rdata
  50. #undef ns_rr_type
  51. #undef ns_msg_count
  52. #undef ns_rr_class
  53. #undef ns_s_an
  54. #define ns_msg ns_msg_vlmcsd
  55. #define ns_initparse ns_initparse_vlmcsd
  56. #define ns_parserr ns_parserr_vlmcsd
  57. #define ns_rr ns_rr_vlmcsd
  58. #define ns_name_uncompress ns_name_uncompress_vlmcsd
  59. #define ns_msg_base ns_msg_base_vlmcsd
  60. #define ns_msg_end ns_msg_end_vlmcsd
  61. #define ns_rr_rdata ns_rr_rdata_vlmcsd
  62. #define ns_rr_type ns_rr_type_vlmcsd
  63. #define ns_msg_count ns_msg_count_vlmcsd
  64. #define ns_rr_class ns_rr_class_vlmcsd
  65. #define ns_s_an ns_s_an_vlmcsd
  66. #ifndef NS_MAXLABEL
  67. #define NS_MAXLABEL 63
  68. #endif
  69. #endif // defined(DNS_PARSER_INTERNAL) && !defined(_WIN32)
  70. //TODO: maybe move to helpers.c
  71. static unsigned int isqrt(unsigned int n)
  72. {
  73. unsigned int c = 0x8000;
  74. unsigned int g = 0x8000;
  75. for(;;)
  76. {
  77. if(g*g > n)
  78. g ^= c;
  79. c >>= 1;
  80. if(c == 0) return g;
  81. g |= c;
  82. }
  83. }
  84. /*
  85. * Compare function for qsort to sort SRV records by priority and weight
  86. * random_weight must be product of weight from SRV record and square root of a random number
  87. */
  88. static int kmsServerListCompareFunc1(const void* a, const void* b)
  89. {
  90. if ( !a && !b) return 0;
  91. if ( a && !b) return -1;
  92. if ( !a && b) return 1;
  93. int priority_order = (int)((*(kms_server_dns_ptr*)a)->priority) - ((int)(*(kms_server_dns_ptr*)b)->priority);
  94. if (priority_order) return priority_order;
  95. return (int)((*(kms_server_dns_ptr*)b)->random_weight) - ((int)(*(kms_server_dns_ptr*)a)->random_weight);
  96. }
  97. /* Sort resulting SRV records */
  98. void sortSrvRecords(kms_server_dns_ptr* serverlist, const int answers)
  99. {
  100. int i;
  101. for (i = 0; i < answers; i++)
  102. {
  103. serverlist[i]->random_weight = (rand32() % 256) * isqrt(serverlist[i]->weight * 1000);
  104. }
  105. qsort(serverlist, answers, sizeof(kms_server_dns_ptr), kmsServerListCompareFunc1);
  106. }
  107. #define RECEIVE_BUFFER_SIZE 2048
  108. #ifndef _WIN32 // UNIX resolver
  109. /*
  110. * Retrieves a raw DNS answer (a buffer of what came over the net)
  111. * Result must be parsed
  112. */
  113. static int getDnsRawAnswer(const char *restrict query, unsigned char** receive_buffer)
  114. {
  115. if (res_init() < 0)
  116. {
  117. errorout("Cannot initialize resolver: %s", strerror(errno));
  118. return 0;
  119. }
  120. //if(!(*receive_buffer = (unsigned char*)malloc(RECEIVE_BUFFER_SIZE))) OutOfMemory();
  121. *receive_buffer = (unsigned char*)vlmcsd_malloc(RECEIVE_BUFFER_SIZE);
  122. int bytes_received;
  123. if (*query == '.')
  124. {
  125. # if __ANDROID__ || __GLIBC__ /* including __UCLIBC__*/ || __APPLE__ || __CYGWIN__ || __FreeBSD__ || __NetBSD__ || __DragonFly__ || __OpenBSD__ || __sun__
  126. bytes_received = res_querydomain("_vlmcs._tcp", query + 1, ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE);
  127. # else
  128. char* querystring = (char*)alloca(strlen(query) + 12);
  129. strcpy(querystring, "_vlmcs._tcp");
  130. strcat(querystring, query);
  131. bytes_received = res_query(querystring, ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE);
  132. # endif
  133. }
  134. else
  135. {
  136. bytes_received = res_search("_vlmcs._tcp", ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE);
  137. }
  138. if (bytes_received < 0)
  139. {
  140. errorout("Fatal: DNS query to %s%s failed: %s\n", "_vlmcs._tcp", *query == '.' ? query : "", hstrerror(h_errno));
  141. return 0;
  142. }
  143. return bytes_received;
  144. }
  145. /*
  146. * Retrieves an unsorted array of SRV records (Unix / Posix)
  147. */
  148. int getKmsServerList(kms_server_dns_ptr** serverlist, const char *restrict query)
  149. {
  150. unsigned char* receive_buffer;
  151. *serverlist = NULL;
  152. int bytes_received = getDnsRawAnswer(query, &receive_buffer);
  153. if (bytes_received == 0) return 0;
  154. ns_msg msg;
  155. if (ns_initparse(receive_buffer, bytes_received, &msg) < 0)
  156. {
  157. errorout("Fatal: Incorrect DNS response: %s\n", strerror(errno));
  158. free(receive_buffer);
  159. return 0;
  160. }
  161. uint16_t i, answers = ns_msg_count(msg, ns_s_an);
  162. //if(!(*serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr)))) OutOfMemory();
  163. *serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr));
  164. memset(*serverlist, 0, answers * sizeof(kms_server_dns_ptr));
  165. for (i = 0; i < answers; i++)
  166. {
  167. ns_rr rr;
  168. if (ns_parserr(&msg, ns_s_an, i, &rr) < 0)
  169. {
  170. errorout("Warning: Error in DNS resource record: %s\n", strerror(errno));
  171. continue;
  172. }
  173. if (ns_rr_type(rr) != ns_t_srv)
  174. {
  175. errorout("Warning: DNS server returned non-SRV record\n");
  176. continue;
  177. }
  178. if (ns_rr_class(rr) != ns_c_in)
  179. {
  180. errorout("Warning: DNS server returned non-IN class record\n");
  181. continue;
  182. }
  183. dns_srv_record_ptr srvrecord = (dns_srv_record_ptr)ns_rr_rdata(rr);
  184. kms_server_dns_ptr kms_server = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t));
  185. (*serverlist)[i] = kms_server;
  186. if (ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), srvrecord->name, kms_server->serverName, sizeof(kms_server->serverName)) < 0)
  187. {
  188. errorout("Warning: No valid DNS name returned in SRV record: %s\n", strerror(errno));
  189. continue;
  190. }
  191. sprintf(kms_server->serverName + strlen(kms_server->serverName), ":%hu", GET_UA16BE(&srvrecord->port));
  192. kms_server->priority = GET_UA16BE(&srvrecord->priority);
  193. kms_server->weight = GET_UA16BE(&srvrecord->weight);
  194. }
  195. free(receive_buffer);
  196. return answers;
  197. }
  198. #else // WIN32 (Windows Resolver)
  199. /*
  200. * Retrieves an unsorted array of SRV records (Windows)
  201. */
  202. int getKmsServerList(kms_server_dns_ptr** serverlist, const char *const restrict query)
  203. {
  204. # define MAX_DNS_NAME_SIZE 254
  205. *serverlist = NULL;
  206. PDNS_RECORD receive_buffer;
  207. char dnsDomain[MAX_DNS_NAME_SIZE];
  208. char FqdnQuery[MAX_DNS_NAME_SIZE];
  209. DWORD size = MAX_DNS_NAME_SIZE;
  210. DNS_STATUS result;
  211. int answers = 0;
  212. PDNS_RECORD dns_iterator;
  213. if (*query == '-')
  214. {
  215. if (!GetComputerNameExA(ComputerNamePhysicalDnsDomain, dnsDomain, &size))
  216. {
  217. errorout("Fatal: Could not determine computer's DNS name: %s\n", vlmcsd_strerror(GetLastError()));
  218. return 0;
  219. }
  220. strcpy(FqdnQuery, "_vlmcs._tcp.");
  221. strncat(FqdnQuery, dnsDomain, MAX_DNS_NAME_SIZE - 12);
  222. }
  223. else
  224. {
  225. strcpy(FqdnQuery, "_vlmcs._tcp");
  226. strncat(FqdnQuery, query, MAX_DNS_NAME_SIZE - 11);
  227. }
  228. if ((result = DnsQuery_UTF8(FqdnQuery, DNS_TYPE_SRV, 0, NULL, &receive_buffer, NULL)) != 0)
  229. {
  230. errorout("Fatal: DNS query to %s failed: %s\n", FqdnQuery, vlmcsd_strerror(result));
  231. return 0;
  232. }
  233. for (dns_iterator = receive_buffer; dns_iterator; dns_iterator = dns_iterator->pNext)
  234. {
  235. if (dns_iterator->Flags.S.Section != 1) continue;
  236. if (dns_iterator->wType != DNS_TYPE_SRV)
  237. {
  238. errorout("Warning: DNS server returned non-SRV record\n");
  239. continue;
  240. }
  241. answers++;
  242. }
  243. *serverlist = (kms_server_dns_ptr*)vlmcsd_malloc(answers * sizeof(kms_server_dns_ptr));
  244. for (answers = 0, dns_iterator = receive_buffer; dns_iterator; dns_iterator = dns_iterator->pNext)
  245. {
  246. if (dns_iterator->wType != DNS_TYPE_SRV) continue;
  247. kms_server_dns_ptr kms_server = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t));
  248. memset(kms_server, 0, sizeof(kms_server_dns_t));
  249. snprintf(kms_server->serverName, sizeof(kms_server->serverName), "%s:%hu", dns_iterator->Data.SRV.pNameTarget, dns_iterator->Data.SRV.wPort);
  250. kms_server->priority = dns_iterator->Data.SRV.wPriority;
  251. kms_server->weight = dns_iterator->Data.SRV.wWeight;
  252. (*serverlist)[answers++] = kms_server;
  253. }
  254. //sortSrvRecords(*serverlist, answers, NoSrvRecordPriority);
  255. DnsRecordListFree(receive_buffer, DnsFreeRecordList);
  256. return answers;
  257. # undef MAX_DNS_NAME_SIZE
  258. }
  259. #endif // _WIN32
  260. #undef RECEIVE_BUFFER_SIZE
  261. #endif // NO_DNS