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)
9 #define CONFIG "config.h"
25 //#ifndef DNS_PARSER_INTERNAL
27 #include <netinet/in.h>
30 #else // other Unix non-Android
31 #include <netinet/in.h>
32 #include <arpa/nameser.h>
34 #endif // other Unix non-Android
35 //#endif // DNS_PARSER_INTERNAL
44 #if defined(DNS_PARSER_INTERNAL) && !defined(_WIN32)
49 // Define macros to redirect DNS parser functions to internal versions
55 #undef ns_name_uncompress
63 #define ns_msg ns_msg_vlmcsd
64 #define ns_initparse ns_initparse_vlmcsd
65 #define ns_parserr ns_parserr_vlmcsd
66 #define ns_rr ns_rr_vlmcsd
67 #define ns_name_uncompress ns_name_uncompress_vlmcsd
68 #define ns_msg_base ns_msg_base_vlmcsd
69 #define ns_msg_end ns_msg_end_vlmcsd
70 #define ns_rr_rdata ns_rr_rdata_vlmcsd
71 #define ns_rr_type ns_rr_type_vlmcsd
72 #define ns_msg_count ns_msg_count_vlmcsd
73 #define ns_rr_class ns_rr_class_vlmcsd
74 #define ns_s_an ns_s_an_vlmcsd
77 #define NS_MAXLABEL 63
80 #endif // defined(DNS_PARSER_INTERNAL) && !defined(_WIN32)
83 //TODO: maybe move to helpers.c
84 static unsigned int isqrt(unsigned int n
)
86 unsigned int c
= 0x8000;
87 unsigned int g
= 0x8000;
104 * Compare function for qsort to sort SRV records by priority and weight
105 * random_weight must be product of weight from SRV record and square root of a random number
107 static int kmsServerListCompareFunc1(const void* a
, const void* b
)
109 if ( !a
&& !b
) return 0;
110 if ( a
&& !b
) return -1;
111 if ( !a
&& b
) return 1;
113 int priority_order
= (int)((*(kms_server_dns_ptr
*)a
)->priority
) - ((int)(*(kms_server_dns_ptr
*)b
)->priority
);
115 if (priority_order
) return priority_order
;
117 return (int)((*(kms_server_dns_ptr
*)b
)->random_weight
) - ((int)(*(kms_server_dns_ptr
*)a
)->random_weight
);
120 /* Sort resulting SRV records */
121 void sortSrvRecords(kms_server_dns_ptr
* serverlist
, const int answers
)
125 for (i
= 0; i
< answers
; i
++)
127 serverlist
[i
]->random_weight
= (rand32() % 256) * isqrt(serverlist
[i
]->weight
* 1000);
130 qsort(serverlist
, answers
, sizeof(kms_server_dns_ptr
), kmsServerListCompareFunc1
);
134 #define RECEIVE_BUFFER_SIZE 2048
135 #ifndef _WIN32 // UNIX resolver
138 * Retrieves a raw DNS answer (a buffer of what came over the net)
139 * Result must be parsed
141 static int getDnsRawAnswer(const char *restrict query
, unsigned char** receive_buffer
)
145 errorout("Cannot initialize resolver: %s", strerror(errno
));
149 //if(!(*receive_buffer = (unsigned char*)malloc(RECEIVE_BUFFER_SIZE))) OutOfMemory();
150 *receive_buffer
= (unsigned char*)vlmcsd_malloc(RECEIVE_BUFFER_SIZE
);
156 # if __ANDROID__ || __GLIBC__ /* including __UCLIBC__*/ || __APPLE__ || __CYGWIN__ || __FreeBSD__ || __NetBSD__ || __DragonFly__ || __OpenBSD__ || __sun__
157 bytes_received
= res_querydomain("_vlmcs._tcp", query
+ 1, ns_c_in
, ns_t_srv
, *receive_buffer
, RECEIVE_BUFFER_SIZE
);
159 char* querystring
= (char*)alloca(strlen(query
) + 12);
160 strcpy(querystring
, "_vlmcs._tcp");
161 strcat(querystring
, query
);
162 bytes_received
= res_query(querystring
, ns_c_in
, ns_t_srv
, *receive_buffer
, RECEIVE_BUFFER_SIZE
);
167 bytes_received
= res_search("_vlmcs._tcp", ns_c_in
, ns_t_srv
, *receive_buffer
, RECEIVE_BUFFER_SIZE
);
170 if (bytes_received
< 0)
172 errorout("Fatal: DNS query to %s%s failed: %s\n", "_vlmcs._tcp", *query
== '.' ? query
: "", hstrerror(h_errno
));
176 return bytes_received
;
180 * Retrieves an unsorted array of SRV records (Unix / Posix)
182 int getKmsServerList(kms_server_dns_ptr
** serverlist
, const char *restrict query
)
184 unsigned char* receive_buffer
;
187 int bytes_received
= getDnsRawAnswer(query
, &receive_buffer
);
189 if (bytes_received
== 0) return 0;
193 if (ns_initparse(receive_buffer
, bytes_received
, &msg
) < 0)
195 errorout("Fatal: Incorrect DNS response: %s\n", strerror(errno
));
196 free(receive_buffer
);
200 uint16_t i
, answers
= ns_msg_count(msg
, ns_s_an
);
201 //if(!(*serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr)))) OutOfMemory();
202 *serverlist
= (kms_server_dns_ptr
*)malloc(answers
* sizeof(kms_server_dns_ptr
));
204 memset(*serverlist
, 0, answers
* sizeof(kms_server_dns_ptr
));
206 for (i
= 0; i
< answers
; i
++)
210 if (ns_parserr(&msg
, ns_s_an
, i
, &rr
) < 0)
212 errorout("Warning: Error in DNS resource record: %s\n", strerror(errno
));
216 if (ns_rr_type(rr
) != ns_t_srv
)
218 errorout("Warning: DNS server returned non-SRV record\n");
222 if (ns_rr_class(rr
) != ns_c_in
)
224 errorout("Warning: DNS server returned non-IN class record\n");
228 dns_srv_record_ptr srvrecord
= (dns_srv_record_ptr
)ns_rr_rdata(rr
);
229 kms_server_dns_ptr kms_server
= (kms_server_dns_ptr
)vlmcsd_malloc(sizeof(kms_server_dns_t
));
231 (*serverlist
)[i
] = kms_server
;
233 if (ns_name_uncompress(ns_msg_base(msg
), ns_msg_end(msg
), srvrecord
->name
, kms_server
->serverName
, sizeof(kms_server
->serverName
)) < 0)
235 errorout("Warning: No valid DNS name returned in SRV record: %s\n", strerror(errno
));
239 sprintf(kms_server
->serverName
+ strlen(kms_server
->serverName
), ":%hu", GET_UA16BE(&srvrecord
->port
));
240 kms_server
->priority
= GET_UA16BE(&srvrecord
->priority
);
241 kms_server
->weight
= GET_UA16BE(&srvrecord
->weight
);
245 free(receive_buffer
);
249 #else // WIN32 (Windows Resolver)
252 * Retrieves an unsorted array of SRV records (Windows)
254 int getKmsServerList(kms_server_dns_ptr
** serverlist
, const char *const restrict query
)
256 # define MAX_DNS_NAME_SIZE 254
258 PDNS_RECORD receive_buffer
;
259 char dnsDomain
[MAX_DNS_NAME_SIZE
];
260 char FqdnQuery
[MAX_DNS_NAME_SIZE
];
261 DWORD size
= MAX_DNS_NAME_SIZE
;
264 PDNS_RECORD dns_iterator
;
268 if (!GetComputerNameExA(ComputerNamePhysicalDnsDomain
, dnsDomain
, &size
))
270 errorout("Fatal: Could not determine computer's DNS name: %s\n", vlmcsd_strerror(GetLastError()));
274 strcpy(FqdnQuery
, "_vlmcs._tcp.");
275 strncat(FqdnQuery
, dnsDomain
, MAX_DNS_NAME_SIZE
- 12);
279 strcpy(FqdnQuery
, "_vlmcs._tcp");
280 strncat(FqdnQuery
, query
, MAX_DNS_NAME_SIZE
- 11);
283 if ((result
= DnsQuery_UTF8(FqdnQuery
, DNS_TYPE_SRV
, 0, NULL
, &receive_buffer
, NULL
)) != 0)
285 errorout("Fatal: DNS query to %s failed: %s\n", FqdnQuery
, vlmcsd_strerror(result
));
289 for (dns_iterator
= receive_buffer
; dns_iterator
; dns_iterator
= dns_iterator
->pNext
)
291 if (dns_iterator
->Flags
.S
.Section
!= 1) continue;
293 if (dns_iterator
->wType
!= DNS_TYPE_SRV
)
295 errorout("Warning: DNS server returned non-SRV record\n");
302 *serverlist
= (kms_server_dns_ptr
*)vlmcsd_malloc(answers
* sizeof(kms_server_dns_ptr
));
304 for (answers
= 0, dns_iterator
= receive_buffer
; dns_iterator
; dns_iterator
= dns_iterator
->pNext
)
306 if (dns_iterator
->wType
!= DNS_TYPE_SRV
) continue;
308 kms_server_dns_ptr kms_server
= (kms_server_dns_ptr
)vlmcsd_malloc(sizeof(kms_server_dns_t
));
310 memset(kms_server
, 0, sizeof(kms_server_dns_t
));
312 snprintf(kms_server
->serverName
, sizeof(kms_server
->serverName
), "%s:%hu", dns_iterator
->Data
.SRV
.pNameTarget
, dns_iterator
->Data
.SRV
.wPort
);
313 kms_server
->priority
= dns_iterator
->Data
.SRV
.wPriority
;
314 kms_server
->weight
= dns_iterator
->Data
.SRV
.wWeight
;
316 (*serverlist
)[answers
++] = kms_server
;
319 //sortSrvRecords(*serverlist, answers, NoSrvRecordPriority);
321 DnsRecordListFree(receive_buffer
, DnsFreeRecordList
);
324 # undef MAX_DNS_NAME_SIZE
327 #undef RECEIVE_BUFFER_SIZE