| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- /*
- * dns_srv.c
- *
- * This file contains the code for KMS SRV record lookup in DNS (_vlmcs._tcp.example.com IN SRV 0 0 1688 mykms.example.com)
- *
- */
- #ifndef CONFIG
- #define CONFIG "config.h"
- #endif // CONFIG
- #include CONFIG
- #ifndef NO_DNS
- #include "dns_srv.h"
- #include <string.h>
- #include <stdio.h>
- #ifndef _WIN32
- #include <signal.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <netdb.h>
- //#ifndef DNS_PARSER_INTERNAL
- #if __ANDROID__
- #include <netinet/in.h>
- #include "nameser.h"
- #include "resolv.h"
- #else // other Unix non-Android
- #include <netinet/in.h>
- #include <arpa/nameser.h>
- #include <resolv.h>
- #endif // other Unix non-Android
- //#endif // DNS_PARSER_INTERNAL
- #else // WIN32
- #include <windns.h>
- #endif // WIN32
- #include "helpers.h"
- #include "output.h"
- #include "endian.h"
- #if defined(DNS_PARSER_INTERNAL) && !defined(_WIN32)
- #include "ns_name.h"
- #include "ns_parse.h"
- // Define macros to redirect DNS parser functions to internal versions
- #undef ns_msg
- #undef ns_initparse
- #undef ns_parserr
- #undef ns_rr
- #undef ns_name_uncompress
- #undef ns_msg_base
- #undef ns_msg_end
- #undef ns_rr_rdata
- #undef ns_rr_type
- #undef ns_msg_count
- #undef ns_rr_class
- #undef ns_s_an
- #define ns_msg ns_msg_vlmcsd
- #define ns_initparse ns_initparse_vlmcsd
- #define ns_parserr ns_parserr_vlmcsd
- #define ns_rr ns_rr_vlmcsd
- #define ns_name_uncompress ns_name_uncompress_vlmcsd
- #define ns_msg_base ns_msg_base_vlmcsd
- #define ns_msg_end ns_msg_end_vlmcsd
- #define ns_rr_rdata ns_rr_rdata_vlmcsd
- #define ns_rr_type ns_rr_type_vlmcsd
- #define ns_msg_count ns_msg_count_vlmcsd
- #define ns_rr_class ns_rr_class_vlmcsd
- #define ns_s_an ns_s_an_vlmcsd
- #ifndef NS_MAXLABEL
- #define NS_MAXLABEL 63
- #endif
- #endif // defined(DNS_PARSER_INTERNAL) && !defined(_WIN32)
- //TODO: maybe move to helpers.c
- static unsigned int isqrt(unsigned int n)
- {
- unsigned int c = 0x8000;
- unsigned int g = 0x8000;
- for(;;)
- {
- if(g*g > n)
- g ^= c;
- c >>= 1;
- if(c == 0) return g;
- g |= c;
- }
- }
- /*
- * Compare function for qsort to sort SRV records by priority and weight
- * random_weight must be product of weight from SRV record and square root of a random number
- */
- static int kmsServerListCompareFunc1(const void* a, const void* b)
- {
- if ( !a && !b) return 0;
- if ( a && !b) return -1;
- if ( !a && b) return 1;
- int priority_order = (int)((*(kms_server_dns_ptr*)a)->priority) - ((int)(*(kms_server_dns_ptr*)b)->priority);
- if (priority_order) return priority_order;
- return (int)((*(kms_server_dns_ptr*)b)->random_weight) - ((int)(*(kms_server_dns_ptr*)a)->random_weight);
- }
- /* Sort resulting SRV records */
- void sortSrvRecords(kms_server_dns_ptr* serverlist, const int answers)
- {
- int i;
- for (i = 0; i < answers; i++)
- {
- serverlist[i]->random_weight = (rand32() % 256) * isqrt(serverlist[i]->weight * 1000);
- }
- qsort(serverlist, answers, sizeof(kms_server_dns_ptr), kmsServerListCompareFunc1);
- }
- #define RECEIVE_BUFFER_SIZE 2048
- #ifndef _WIN32 // UNIX resolver
- /*
- * Retrieves a raw DNS answer (a buffer of what came over the net)
- * Result must be parsed
- */
- static int getDnsRawAnswer(const char *restrict query, unsigned char** receive_buffer)
- {
- if (res_init() < 0)
- {
- errorout("Cannot initialize resolver: %s", strerror(errno));
- return 0;
- }
- //if(!(*receive_buffer = (unsigned char*)malloc(RECEIVE_BUFFER_SIZE))) OutOfMemory();
- *receive_buffer = (unsigned char*)vlmcsd_malloc(RECEIVE_BUFFER_SIZE);
- int bytes_received;
- if (*query == '.')
- {
- # if __ANDROID__ || __GLIBC__ /* including __UCLIBC__*/ || __APPLE__ || __CYGWIN__ || __FreeBSD__ || __NetBSD__ || __DragonFly__ || __OpenBSD__ || __sun__
- bytes_received = res_querydomain("_vlmcs._tcp", query + 1, ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE);
- # else
- char* querystring = (char*)alloca(strlen(query) + 12);
- strcpy(querystring, "_vlmcs._tcp");
- strcat(querystring, query);
- bytes_received = res_query(querystring, C_IN, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE);
- # endif
- }
- else
- {
- bytes_received = res_search("_vlmcs._tcp", ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE);
- }
- if (bytes_received < 0)
- {
- errorout("Fatal: DNS query to %s%s failed: %s\n", "_vlmcs._tcp", *query == '.' ? query : "", hstrerror(h_errno));
- return 0;
- }
- return bytes_received;
- }
- /*
- * Retrieves an unsorted array of SRV records (Unix / Posix)
- */
- int getKmsServerList(kms_server_dns_ptr** serverlist, const char *restrict query)
- {
- unsigned char* receive_buffer;
- *serverlist = NULL;
- int bytes_received = getDnsRawAnswer(query, &receive_buffer);
- if (bytes_received == 0) return 0;
- ns_msg msg;
- if (ns_initparse(receive_buffer, bytes_received, &msg) < 0)
- {
- errorout("Fatal: Incorrect DNS response: %s\n", strerror(errno));
- free(receive_buffer);
- return 0;
- }
- uint16_t i, answers = ns_msg_count(msg, ns_s_an);
- //if(!(*serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr)))) OutOfMemory();
- *serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr));
- memset(*serverlist, 0, answers * sizeof(kms_server_dns_ptr));
- for (i = 0; i < answers; i++)
- {
- ns_rr rr;
- if (ns_parserr(&msg, ns_s_an, i, &rr) < 0)
- {
- errorout("Warning: Error in DNS resource record: %s\n", strerror(errno));
- continue;
- }
- if (ns_rr_type(rr) != ns_t_srv)
- {
- errorout("Warning: DNS server returned non-SRV record\n");
- continue;
- }
- if (ns_rr_class(rr) != ns_c_in)
- {
- errorout("Warning: DNS server returned non-IN class record\n");
- continue;
- }
- dns_srv_record_ptr srvrecord = (dns_srv_record_ptr)ns_rr_rdata(rr);
- kms_server_dns_ptr kms_server = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t));
- (*serverlist)[i] = kms_server;
- if (ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), srvrecord->name, kms_server->serverName, sizeof(kms_server->serverName)) < 0)
- {
- errorout("Warning: No valid DNS name returned in SRV record: %s\n", strerror(errno));
- continue;
- }
- sprintf(kms_server->serverName + strlen(kms_server->serverName), ":%hu", GET_UA16BE(&srvrecord->port));
- kms_server->priority = GET_UA16BE(&srvrecord->priority);
- kms_server->weight = GET_UA16BE(&srvrecord->weight);
- }
- free(receive_buffer);
- return answers;
- }
- #else // WIN32 (Windows Resolver)
- /*
- * Retrieves an unsorted array of SRV records (Windows)
- */
- int getKmsServerList(kms_server_dns_ptr** serverlist, const char *const restrict query)
- {
- # define MAX_DNS_NAME_SIZE 254
- *serverlist = NULL;
- PDNS_RECORD receive_buffer;
- char dnsDomain[MAX_DNS_NAME_SIZE];
- char FqdnQuery[MAX_DNS_NAME_SIZE];
- DWORD size = MAX_DNS_NAME_SIZE;
- DNS_STATUS result;
- int answers = 0;
- PDNS_RECORD dns_iterator;
- if (*query == '-')
- {
- if (!GetComputerNameExA(ComputerNamePhysicalDnsDomain, dnsDomain, &size))
- {
- errorout("Fatal: Could not determine computer's DNS name: %s\n", vlmcsd_strerror(GetLastError()));
- return 0;
- }
- strcpy(FqdnQuery, "_vlmcs._tcp.");
- strncat(FqdnQuery, dnsDomain, MAX_DNS_NAME_SIZE - 12);
- }
- else
- {
- strcpy(FqdnQuery, "_vlmcs._tcp");
- strncat(FqdnQuery, query, MAX_DNS_NAME_SIZE - 11);
- }
- if ((result = DnsQuery_UTF8(FqdnQuery, DNS_TYPE_SRV, 0, NULL, &receive_buffer, NULL)) != 0)
- {
- errorout("Fatal: DNS query to %s failed: %s\n", FqdnQuery, vlmcsd_strerror(result));
- return 0;
- }
- for (dns_iterator = receive_buffer; dns_iterator; dns_iterator = dns_iterator->pNext)
- {
- if (dns_iterator->Flags.S.Section != 1) continue;
- if (dns_iterator->wType != DNS_TYPE_SRV)
- {
- errorout("Warning: DNS server returned non-SRV record\n");
- continue;
- }
- answers++;
- }
- *serverlist = (kms_server_dns_ptr*)vlmcsd_malloc(answers * sizeof(kms_server_dns_ptr));
- for (answers = 0, dns_iterator = receive_buffer; dns_iterator; dns_iterator = dns_iterator->pNext)
- {
- if (dns_iterator->wType != DNS_TYPE_SRV) continue;
- kms_server_dns_ptr kms_server = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t));
- memset(kms_server, 0, sizeof(kms_server_dns_t));
- snprintf(kms_server->serverName, sizeof(kms_server->serverName), "%s:%hu", dns_iterator->Data.SRV.pNameTarget, dns_iterator->Data.SRV.wPort);
- kms_server->priority = dns_iterator->Data.SRV.wPriority;
- kms_server->weight = dns_iterator->Data.SRV.wWeight;
- (*serverlist)[answers++] = kms_server;
- }
- //sortSrvRecords(*serverlist, answers, NoSrvRecordPriority);
- DnsRecordListFree(receive_buffer, DnsFreeRecordList);
- return answers;
- # undef MAX_DNS_NAME_SIZE
- }
- #endif // _WIN32
- #undef RECEIVE_BUFFER_SIZE
- #endif // NO_DNS
|