explicitely use non-UNICODE structures in libstrophe DNS resolver on Windows
[public/netxms.git] / src / libstrophe / resolver.c
CommitLineData
96259f10
VK
1/* resolver.h
2 * strophe XMPP client library -- DNS resolver
3 *
4 * Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
5 *
6 * This software is provided AS-IS with no warranty, either express
7 * or implied.
8 *
9 * This program is dual licensed under the MIT and GPLv3 licenses.
10 */
11
12/** @file
13 * DNS resolver.
14 */
15
16#include <nms_common.h>
17#include <time.h>
18#include <strophe.h>
19
20#ifndef _WIN32
21#include <netinet/in.h>
22#include <arpa/nameser.h>
23#include <resolv.h> /* res_query */
24#endif /* _WIN32 */
25
26#include "ostypes.h"
27#include "snprintf.h"
28#include "util.h" /* xmpp_min */
29#include "resolver.h"
30
31#define MESSAGE_HEADER_LEN 12
32#define MESSAGE_RESPONSE 1
33#define MESSAGE_T_SRV 33
34#define MESSAGE_C_IN 1
35
36struct message_header {
37 uint16_t id;
38 uint8_t octet2;
39 uint8_t octet3;
40 uint16_t qdcount;
41 uint16_t ancount;
42 uint16_t nscount;
43 uint16_t arcount;
44};
45
46#ifdef _WIN32
47static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
48 resolver_srv_rr_t **srv_rr_list);
49static int resolver_win32_srv_query(const char *fulldomain,
50 unsigned char *buf, size_t len);
51#endif /* _WIN32 */
52
53/* the same as ntohs(), but receives pointer to the value */
54static uint16_t xmpp_ntohs_ptr(const void *ptr)
55{
56 const uint8_t *p = (const uint8_t *)ptr;
57
58 return (uint16_t)((p[0] << 8U) + p[1]);
59}
60
61static uint8_t message_header_qr(const struct message_header *header)
62{
63 return (header->octet2 >> 7) & 1;
64}
65
66static uint8_t message_header_rcode(const struct message_header *header)
67{
68 return header->octet3 & 0x0f;
69}
70
71/*
72 * Append a label or a dot to the target name with buffer overflow checks.
73 * Returns length of the non-truncated resulting string, may be bigger than
74 * name_max.
75 */
76static size_t message_name_append_safe(char *name, size_t name_len,
77 size_t name_max,
78 const char *tail, size_t tail_len)
79{
80 size_t copy_len;
81
82 copy_len = name_max > name_len ? name_max - name_len : 0;
83 copy_len = xmpp_min(tail_len, copy_len);
84 if (copy_len > 0)
85 strncpy(&name[name_len], tail, copy_len);
86
87 return name_len + tail_len;
88}
89
90/* Returns length of the compressed name. This is NOT the same as strlen(). */
91static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
92 unsigned buf_offset,
93 char *name, size_t name_max)
94{
95 size_t name_len = 0;
96 unsigned i = buf_offset;
97 unsigned pointer;
98 unsigned rc;
99 unsigned char label_len;
100
101
102 while (1) {
103 if (i >= buf_len) return 0;
104 label_len = buf[i++];
105 if (label_len == 0) break;
106
107 /* Label */
108 if ((label_len & 0xc0) == 0) {
109 if (i + label_len - 1 >= buf_len) return 0;
110 if (name != NULL) {
111 name_len = message_name_append_safe(name, name_len, name_max,
112 (char *)&buf[i], label_len);
113 name_len = message_name_append_safe(name, name_len, name_max,
114 ".", 1);
115 }
116 i += label_len;
117
118 /* Pointer */
119 } else if ((label_len & 0xc0) == 0xc0) {
120 if (i >= buf_len) return 0;
121 pointer = (label_len & 0x3f) << 8 | buf[i++];
122 if (name != NULL && name_len >= name_max && name_max > 0) {
123 /* We have filled the name buffer. Don't pass it recursively. */
124 name[name_max - 1] = '\0';
125 name = NULL;
126 name_max = 0;
127 }
128 rc = message_name_get(buf, buf_len, pointer,
129 name != NULL ? &name[name_len] : NULL,
130 name_max > name_len ? name_max - name_len : 0);
131 if (rc == 0) return 0;
132 /* Pointer is always the last. */
133 break;
134
135 /* The 10 and 01 combinations are reserved for future use. */
136 } else {
137 return 0;
138 }
139 }
140 if (label_len == 0) {
141 if (name_len == 0) name_len = 1;
142 /*
143 * At this point name_len is length of the resulting name,
144 * including '\0'. This value can be exported to allocate buffer
145 * of precise size.
146 */
147 if (name != NULL && name_max > 0) {
148 /*
149 * Overwrite leading '.' with a '\0'. If the resulting name is
150 * bigger than name_max it is truncated.
151 */
152 name[xmpp_min(name_len, name_max) - 1] = '\0';
153 }
154 }
155
156 return i - buf_offset;
157}
158
159static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
160 unsigned buf_offset)
161{
162 return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
163}
164
165static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
166{
167 resolver_srv_rr_t * rr_head;
168 resolver_srv_rr_t * rr_current;
169 resolver_srv_rr_t * rr_next;
170 resolver_srv_rr_t * rr_prev;
171 int swap;
172
173 rr_head = *srv_rr_list;
174
175 if ((rr_head == NULL) || (rr_head->next == NULL)) {
176 /* Empty or single record list */
177 return;
178 }
179
180 do {
181 rr_prev = NULL;
182 rr_current = rr_head;
183 rr_next = rr_head->next;
184 swap = 0;
185 while (rr_next != NULL) {
186 /*
187 * RFC2052: A client MUST attempt to contact the target host
188 * with the lowest-numbered priority it can reach.
189 * RFC2052: When selecting a target host among the
190 * those that have the same priority, the chance of trying
191 * this one first SHOULD be proportional to its weight.
192 */
193 if ((rr_current->priority > rr_next->priority) ||
194 (rr_current->priority == rr_next->priority &&
195 rr_current->weight < rr_next->weight))
196 {
197 /* Swap node */
198 swap = 1;
199 if (rr_prev != NULL) {
200 rr_prev->next = rr_next;
201 } else {
202 /* Swap head node */
203 rr_head = rr_next;
204 }
205 rr_current->next = rr_next->next;
206 rr_next->next = rr_current;
207
208 rr_prev = rr_next;
209 rr_next = rr_current->next;
210 } else {
211 /* Next node */
212 rr_prev = rr_current;
213 rr_current = rr_next;
214 rr_next = rr_next->next;
215 }
216 }
217 } while (swap != 0);
218
219 *srv_rr_list = rr_head;
220}
221
222#define BUF_OVERFLOW_CHECK(ptr, len) do { \
223 if ((ptr) >= (len)) { \
224 if (*srv_rr_list != NULL) \
225 resolver_srv_free(ctx, *srv_rr_list); \
226 *srv_rr_list = NULL; \
227 return XMPP_DOMAIN_NOT_FOUND; \
228 } \
229} while (0)
230
231int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
232 size_t len, resolver_srv_rr_t **srv_rr_list)
233{
234 unsigned i;
235 unsigned j;
236 unsigned name_len;
237 unsigned rdlength;
238 uint16_t type;
239 uint16_t class;
240 struct message_header header;
241 resolver_srv_rr_t *rr;
242
243 *srv_rr_list = NULL;
244
245 if (len < MESSAGE_HEADER_LEN)
246 return XMPP_DOMAIN_NOT_FOUND;
247
248 header.id = xmpp_ntohs_ptr(&buf[0]);
249 header.octet2 = buf[2];
250 header.octet3 = buf[3];
251 header.qdcount = xmpp_ntohs_ptr(&buf[4]);
252 header.ancount = xmpp_ntohs_ptr(&buf[6]);
253 header.nscount = xmpp_ntohs_ptr(&buf[8]);
254 header.arcount = xmpp_ntohs_ptr(&buf[10]);
255 if (message_header_qr(&header) != MESSAGE_RESPONSE ||
256 message_header_rcode(&header) != 0)
257 {
258 return XMPP_DOMAIN_NOT_FOUND;
259 }
260 j = MESSAGE_HEADER_LEN;
261
262 /* skip question section */
263 for (i = 0; i < header.qdcount; ++i) {
264 BUF_OVERFLOW_CHECK(j, len);
265 name_len = message_name_len(buf, len, j);
266 /* error in name format */
267 if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
268 j += name_len + 4;
269 }
270
271 for (i = 0; i < header.ancount; ++i) {
272 BUF_OVERFLOW_CHECK(j, len);
273 name_len = message_name_len(buf, len, j);
274 /* error in name format */
275 if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
276 j += name_len;
277 BUF_OVERFLOW_CHECK(j + 16, len);
278 type = xmpp_ntohs_ptr(&buf[j]);
279 class = xmpp_ntohs_ptr(&buf[j + 2]);
280 rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
281 j += 10;
282 if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
283 rr = xmpp_alloc(ctx, sizeof(*rr));
284 rr->next = *srv_rr_list;
285 rr->priority = xmpp_ntohs_ptr(&buf[j]);
286 rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
287 rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
288 name_len = message_name_get(buf, len, j + 6, rr->target,
289 sizeof(rr->target));
290 if (name_len > 0)
291 *srv_rr_list = rr;
292 else
293 xmpp_free(ctx, rr); /* skip broken record */
294 }
295 j += rdlength;
296 }
297 resolver_srv_list_sort(srv_rr_list);
298
299 return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
300}
301
302int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
303 const char *domain, resolver_srv_rr_t **srv_rr_list)
304{
305 char fulldomain[2048];
306 unsigned char buf[65535];
307 int len;
308 int set = XMPP_DOMAIN_NOT_FOUND;
309
310 xmpp_snprintf(fulldomain, sizeof(fulldomain),
311 "_%s._%s.%s", service, proto, domain);
312
313 *srv_rr_list = NULL;
314
315#ifdef _WIN32
316 set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
317 if (set == XMPP_DOMAIN_FOUND)
318 return set;
319 len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
320#else /* _WIN32 */
321 len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
322#endif /* _WIN32 */
323
324 if (len > 0)
325 set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
326
327 return set;
328}
329
330void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
331{
332 resolver_srv_rr_t *rr;
333
334 while (srv_rr_list != NULL) {
335 rr = srv_rr_list->next;
336 xmpp_free(ctx, srv_rr_list);
337 srv_rr_list = rr;
338 }
339}
340
341#ifdef _WIN32
342
343/*******************************************************************************
344 * Next part was copied from sock.c and contains old win32 code.
345 *
346 * The idea is to get raw response from a name server and pass it to
347 * resolver_srv_lookup_buf(). In fact, resolver_win32_srv_query() replaces
348 * the call of res_query().
349 * Dnsapi code is moved to a separated function resolver_srv_win32_lookup() and
350 * changed to meet new API.
351 *
352 * XXX If the code is compiled it should work like before.
353 ******************************************************************************/
354
355#include <winsock2.h>
356#include <ws2tcpip.h>
357#include <windns.h>
358#include <Iphlpapi.h>
359
360struct dnsquery_header
361{
362 unsigned short id;
363 unsigned char qr;
364 unsigned char opcode;
365 unsigned char aa;
366 unsigned char tc;
367 unsigned char rd;
368 unsigned char ra;
369 unsigned char z;
370 unsigned char rcode;
371 unsigned short qdcount;
372 unsigned short ancount;
373 unsigned short nscount;
374 unsigned short arcount;
375};
376
377struct dnsquery_question
378{
379 char qname[1024];
380 unsigned short qtype;
381 unsigned short qclass;
382};
383
384static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
385{
386 unsigned char *start = buf + *offset;
387 unsigned char *p = start;
388
389 /* assuming big endian */
390 *p++ = (num >> 8) & 0xff;
391 *p++ = (num) & 0xff;
392
393 *offset += 2;
394}
395
396static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
397 char *name)
398{
399 unsigned char *start = buf + *offset;
400 unsigned char *p = start;
401 unsigned char *wordstart, *wordend;
402
403 wordstart = (unsigned char *)name;
404
405 while (*wordstart)
406 {
407 int len;
408 wordend = wordstart;
409 while (*wordend && *wordend != '.')
410 {
411 wordend++;
412 }
413
414 len = (int)(wordend - wordstart);
415
416 if (len > 0x3F)
417 {
418 len = 0x3F;
419 }
420
421 *p++ = len;
422
423 while (wordstart != wordend)
424 {
425 *p++ = *wordstart++;
426 }
427
428 if (*wordstart == '.')
429 {
430 wordstart++;
431 }
432 }
433
434 *p++ = '\0';
435
e060b2da 436 *offset += (int)(p - start);
96259f10
VK
437}
438
439static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
440{
441 unsigned char *p;
442
443 netbuf_add_16bitnum(buf, buflen, offset, header->id);
444
445 p = buf + *offset;
446 *p++ = ((header->qr & 0x01) << 7)
447 | ((header->opcode & 0x0F) << 3)
448 | ((header->aa & 0x01) << 2)
449 | ((header->tc & 0x01) << 1)
450 | ((header->rd & 0x01));
451 *p++ = ((header->ra & 0x01) << 7)
452 | ((header->z & 0x07) << 4)
453 | ((header->rcode & 0x0F));
454 *offset += 2;
455
456 netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
457 netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
458 netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
459 netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
460}
461
462static void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
463{
464 netbuf_add_domain_name(buf, buflen, offset, question->qname);
465 netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
466 netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
467}
468
469static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
470 resolver_srv_rr_t **srv_rr_list)
471{
472 resolver_srv_rr_t *rr;
473 HINSTANCE hdnsapi = NULL;
474
4994603a
VK
475 DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA**, PVOID*);
476 void (WINAPI * pDnsRecordListFree)(DNS_RECORDA*, DNS_FREE_TYPE);
96259f10
VK
477
478 if (hdnsapi = LoadLibraryA("dnsapi.dll")) {
479 pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
480 pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
481
482 if (pDnsQuery_A && pDnsRecordListFree) {
4994603a 483 DNS_RECORDA *dnsrecords = NULL;
96259f10
VK
484 DNS_STATUS error;
485
486 error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
487
488 if (error == 0) {
4994603a 489 DNS_RECORDA *current = dnsrecords;
96259f10
VK
490
491 while (current) {
492 if (current->wType == DNS_TYPE_SRV) {
493 rr = xmpp_alloc(ctx, sizeof(*rr));
494 if (rr == NULL)
495 break;
496 rr->next = *srv_rr_list;
497 rr->port = current->Data.Srv.wPort;
498 rr->priority = current->Data.Srv.wPriority;
499 rr->weight = current->Data.Srv.wWeight;
500 xmpp_snprintf(rr->target, sizeof(rr->target), "%s",
501 current->Data.Srv.pNameTarget);
502 *srv_rr_list = rr;
503 }
504 current = current->pNext;
505 }
506 }
507
508 pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
509 }
510
511 FreeLibrary(hdnsapi);
512 }
513 resolver_srv_list_sort(srv_rr_list);
514
515 return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
516}
517
518static int resolver_win32_srv_query(const char *fulldomain,
519 unsigned char *buf, size_t len)
520{
521 int set = 0;
522 int insize;
523
524 /* if dnsapi didn't work/isn't there, try querying the dns server manually */
525 if (!set)
526 {
527 struct dnsquery_header header;
528 struct dnsquery_question question;
529 int offset = 0;
530 int addrlen;
531 sock_t sock;
532 struct sockaddr_in dnsaddr;
533 char dnsserverips[16][256];
534 int numdnsservers = 0;
535 int j;
536
537 /* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
538 if (!numdnsservers)
539 {
540 HINSTANCE hiphlpapi = NULL;
541 DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
542
543 if (hiphlpapi = LoadLibraryA("Iphlpapi.dll"))
544 {
545 pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
546
547 if (pGetNetworkParams)
548 {
549 FIXED_INFO *fi;
550 ULONG len;
551 DWORD error;
552 char buffer[65535];
553
554 len = 65535;
555 fi = (FIXED_INFO *)buffer;
556
557 if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
558 {
559 IP_ADDR_STRING *pias = &(fi->DnsServerList);
560
561 while (pias && numdnsservers < 16)
562 {
563 strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
564 pias = pias->Next;
565 }
566 }
567 }
568 }
569 FreeLibrary(hiphlpapi);
570 }
571
572 /* Next, try getting the DNS server ips from the registry */
573 if (!numdnsservers)
574 {
575 HKEY search;
576 LONG error;
577
578 error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
579
580 if (error != ERROR_SUCCESS)
581 {
582 error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
583 }
584
585 if (error == ERROR_SUCCESS)
586 {
587 char name[512];
588 DWORD len = 512;
589
590 error = RegQueryValueExA(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
591
592 if (error != ERROR_SUCCESS)
593 {
594 error = RegQueryValueExA(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
595 }
596
597 if (error == ERROR_SUCCESS)
598 {
599 char *parse = "0123456789.", *start, *end;
600 start = name;
601 end = name;
602 name[len] = '\0';
603
604 while (*start && numdnsservers < 16)
605 {
606 while (strchr(parse, *end))
607 {
608 end++;
609 }
610
611 strncpy(dnsserverips[numdnsservers++], start, end - start);
612
613 while (*end && !strchr(parse, *end))
614 {
615 end++;
616 }
617
618 start = end;
619 }
620 }
621 }
622
623 RegCloseKey(search);
624 }
625
626 if (!numdnsservers)
627 {
628 HKEY searchlist;
629 LONG error;
630
631 error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
632
633 if (error == ERROR_SUCCESS)
634 {
635 unsigned int i;
636 DWORD numinterfaces = 0;
637
638 RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
639
640 for (i = 0; i < numinterfaces; i++)
641 {
642 char name[512];
643 DWORD len = 512;
644 HKEY searchentry;
645
646 RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
647
648 if (RegOpenKeyExA(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
649 {
650 if (RegQueryValueExA(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
651 {
652 char *parse = "0123456789.", *start, *end;
653 start = name;
654 end = name;
655 name[len] = '\0';
656
657 while (*start && numdnsservers < 16)
658 {
659 while (strchr(parse, *end))
660 {
661 end++;
662 }
663
664 strncpy(dnsserverips[numdnsservers++], start, end - start);
665
666 while (*end && !strchr(parse, *end))
667 {
668 end++;
669 }
670
671 start = end;
672 }
673 }
674 else if (RegQueryValueExA(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
675 {
676 char *parse = "0123456789.", *start, *end;
677 start = name;
678 end = name;
679 name[len] = '\0';
680
681 while (*start && numdnsservers < 16)
682 {
683 while (strchr(parse, *end))
684 {
685 end++;
686 }
687
688 strncpy(dnsserverips[numdnsservers++], start, end - start);
689
690 while (*end && !strchr(parse, *end))
691 {
692 end++;
693 }
694
695 start = end;
696 }
697 }
698 RegCloseKey(searchentry);
699 }
700 }
701 RegCloseKey(searchlist);
702 }
703 }
704
705 /* If we have a DNS server, use it */
706 if (numdnsservers)
707 {
708 ULONG nonblocking = 1;
709 int i;
710
711 memset(&header, 0, sizeof(header));
712 header.id = 12345; /* FIXME: Get a better id here */
713 header.rd = 1;
714 header.qdcount = 1;
715
e060b2da 716 netbuf_add_dnsquery_header(buf, (int)len, &offset, &header);
96259f10
VK
717
718 memset(&question, 0, sizeof(question));
719 strncpy(question.qname, fulldomain, 1024);
720 question.qtype = 33; /* SRV */
721 question.qclass = 1; /* INTERNET! */
722
e060b2da 723 netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
96259f10
VK
724
725 insize = 0;
726 for (i = 0; i < numdnsservers && insize <= 0; i++)
727 {
728 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
729 ioctlsocket(sock, FIONBIO, &nonblocking);
730
731 memset(&dnsaddr, 0, sizeof(dnsaddr));
732
733 dnsaddr.sin_family = AF_INET;
734 dnsaddr.sin_port = htons(53);
735 dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
736
737 addrlen = sizeof(dnsaddr);
738 sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
739 for (j = 0; j < 50; j++)
740 {
e060b2da 741 insize = recvfrom(sock, (char *)buf, (int)len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
96259f10
VK
742 if (insize == SOCKET_ERROR)
743 {
744 if (sock_error() == WSAEWOULDBLOCK)
745 {
746 Sleep(100);
747 }
748 else
749 {
750 break;
751 }
752 }
753 else
754 {
755 break;
756 }
757 }
758
759 closesocket(sock);
760 }
761 set = insize > 0;
762 }
763
764 }
765
766 return set ? insize : -1;
767}
768
769#endif /* _WIN32 */