Watt-32 tcp/ip  2.2 dev-rel.10
pcdns.c
Go to the documentation of this file.
1 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <limits.h>
37 #include <sys/werrno.h>
38 
39 #include "copyrigh.h"
40 #include "wattcp.h"
41 #include "strings.h"
42 #include "misc.h"
43 #include "timer.h"
44 #include "language.h"
45 #include "pcconfig.h"
46 #include "pcdbug.h"
47 #include "pctcp.h"
48 #include "netaddr.h"
49 #include "idna.h"
50 #include "ip6_out.h"
51 #include "netaddr.h"
52 #include "pcdns.h"
53 
57 #if defined(USE_BSD_API)
58  #include <netdb.h>
59 
60  BOOL called_from_resolve = FALSE;
61  BOOL called_from_ghbn = FALSE;
62 #endif
63 
64 #if !defined(WIN32)
65  #define TCHAR
66 #endif
67 
71 char defaultdomain [MAX_HOSTLEN+1] = "your.domain.com";
72 char *def_domain = defaultdomain;
73 
74 int (W32_CALL *_resolve_hook)(void); /* user hook for terminating resolve() */
75 
76 BOOL _resolve_exit; /* user hook interrupted */
77 BOOL _resolve_timeout; /* (reverse) lookup timeout */
78 BOOL from_windns; /* the answer came from WinDNS */
79 DWORD dom_ttl; /* Time-to-Live of last response */
80 int dom_errno; /* domain errno (DNS_SRV_xx/DNS_CLI_xx) */
81 char dom_cname [MAX_HOSTLEN+1]; /* CNAME of last response */
82 
83 DWORD def_nameservers [MAX_NAMESERVERS];
84 WORD last_nameserver = 0;
85 WORD dns_timeout = 0;
86 BOOL dns_recurse = TRUE; /* Recurse over dotless names */
87 BOOL dns_do_ipv6 = TRUE; /* Do try to resolve to IPv6 */
88 BOOL dns_do_idna = FALSE; /* Convert non-ASCII names to/from ACE */
89 WORD dns_windns = 0; /* How to read/write the WinDns cache */
90 
91 static const char *loc_domain; /* current subname to be used */
92 static DWORD res_timeout;
93 
94 /* Additional addresses from last resolve().
95  * dom_a4_list is on network order!
96  */
97 DWORD dom_a4list [MAX_ADDRESSES+1];
98 
99 #if defined(USE_IPV6)
100 ip6_address dom_a6list [MAX_ADDRESSES+1];
101 #endif
102 
103 
107 static void query_init (struct DNS_query *q, BOOL is_ip6)
108 {
109  int i;
110 
111  memset (&q->head, 0, sizeof(q->head));
112  q->head.flags = intel16 (DRD); /* Query, Recursion desired */
113  q->head.qdcount = intel16 (1);
114 
115 #if defined(USE_IPV6)
116  if (is_ip6)
117  memset (&dom_a6list, 0, sizeof(dom_a6list));
118  else
119 #endif
120  for (i = 0; i < DIM(dom_a4list); i++)
121  dom_a4list[i] = INADDR_NONE;
122  ARGSUSED (is_ip6);
123 }
124 
128 static void store_alt_address (const void *data, int idx, BOOL is_ip6)
129 {
130  if (idx < 0 || idx >= MAX_ADDRESSES)
131  return;
132 
133 #if defined(USE_IPV6)
134  if (is_ip6)
135  memcpy (&dom_a6list[idx], data, sizeof(ip6_address));
136  else
137 #endif
138  dom_a4list [idx] = *(DWORD*)data; /* store on network order */
139  ARGSUSED (is_ip6);
140 }
141 
148 static int pack_domain (BYTE *dst, const char *src)
149 {
150  const char *p;
151  BYTE *q, *savedst;
152  BOOL dotflag, defflag;
153  int i;
154 
155  dotflag = defflag = FALSE;
156  savedst = dst;
157  p = src;
158 
159  do /* copy whole string */
160  {
161  *dst = '\0';
162  q = dst + 1;
163  while (*p && *p != '.')
164  *q++ = *p++;
165 
166  i = p - src;
167  if (i > MAX_LABEL_SIZE) /* label length exceeded */
168  return (-1);
169 
170  *dst = i;
171  *q = '\0';
172 
173  if (*p) /* update pointers */
174  {
175  dotflag = TRUE;
176  src = ++p;
177  dst = q;
178  }
179  else if (!dotflag && !defflag && loc_domain)
180  {
181  p = loc_domain; /* continue packing with default */
182  defflag = TRUE;
183  src = p;
184  dst = q;
185  }
186  }
187  while (*p);
188 
189  q++;
190  return (q - savedst); /* length of packed string */
191 }
192 
197 static int send_query (sock_type *sock, struct DNS_query *q,
198  const char *name, DWORD towho, WORD qtype)
199 {
200  WORD len;
201  BYTE *p;
202  int i;
203 
204  if (!udp_open(&sock->udp,DOM_SRC_PORT,towho,DOM_DST_PORT,NULL))
205  {
206  dom_errno = DNS_CLI_SYSTEM; /* errno ENETDOWN/EHOSTUNREACH etc. */
207  if (debug_on)
208  {
209  outs (_LANG("Domain: "));
210  outsnl (sock->udp.err_msg);
211  }
212  return (0);
213  }
214 
215  p = &q->body[0];
216  i = pack_domain (p, name);
217  if (i < 0)
218  {
219  dom_errno = DNS_CLI_TOOBIG;
220  return (0);
221  }
222 
223  p += i;
224  *(WORD*)p = intel16 (qtype); /* QTYPE is A or AAAA */
225  p += sizeof(WORD);
226  *(WORD*)p = intel16 (DIN); /* QCLASS is always internet */
227  p += sizeof(WORD);
228 
229  len = p - (BYTE*)q;
230  if (sock_write (sock, (const BYTE*)q, len) < len)
231  {
232  dom_errno = DNS_CLI_SYSTEM;
233  return (0);
234  }
235  return (len);
236 }
237 
238 static __inline int count_paths (const char *path_str)
239 {
240  int count = 0;
241  const char *p;
242 
243  for (p = path_str; *p || *(p+1); p++)
244  if (*p == '\0')
245  count++;
246  return (++count);
247 }
248 
249 static __inline const char *get_path (
250  const char *path_str, /* the path list to search */
251  int which_one) /* which path to get, starts at 1 */
252 {
253  const char *p;
254 
255  if (which_one > count_paths(path_str))
256  return (NULL);
257 
258  which_one--;
259  for (p = path_str; which_one; p++)
260  if (*p == '\0')
261  which_one--;
262  return (p);
263 }
264 
268 static void extract_cname (const struct DNS_query *q, const char *src,
269  char *dest, size_t max)
270 {
271  const char *p = src;
272  const char *start = dest;
273  const char *end = dest + max;
274 
275  while (dest < end)
276  {
277  BYTE count = *p++;
278  WORD ofs;
279 
280  if ((count & 0xC0) == 0xC0)
281  {
282  ofs = ((count - 0xC0) << 8) + *p++; /* new offset */
283  p = (const char*)q + ofs;
284  count = *p++;
285  }
286  if (count == 0)
287  break;
288 
289  while (count > 0)
290  {
291  if (dest > end)
292  break;
293  *dest++ = *p++;
294  count--;
295  }
296  *dest++ = '.';
297  }
298  if (dest > start && *(dest-1) == '.') /* remove trailing '.' */
299  dest--;
300  *dest = '\0';
301 }
302 
303 
314 static int unpack_domain (const struct DNS_query *q,
315  const BYTE *src, size_t src_size,
316  BYTE *dst, size_t dst_size)
317 {
318  int retval = 0;
319  const BYTE *start = src;
320  const BYTE *src_max = src + src_size;
321  const BYTE *dst_max = dst + dst_size;
322  const BYTE *base = (const BYTE*)q;
323 
324  while (*src && src < src_max && dst < dst_max)
325  {
326  int i, j = *src;
327 
328  while ((j & 0xC0) == 0xC0)
329  {
330  if (!retval)
331  retval = src - start + 2;
332  src++;
333  src = &base [((j - 0xC0) << 8) + *src];
334  j = *src;
335  }
336 
337  src++;
338  for (i = 0; i < (j & ~0xC0); i++)
339  {
340  if (dst >= dst_max-1)
341  return (-1);
342  *dst++ = *src++;
343  }
344  *dst++ = '.';
345  }
346 
347  if (src > start)
348  {
349  *(--dst) = '\0'; /* add terminator */
350  src++; /* account for terminator on src */
351  }
352 
353  if (!retval)
354  retval = src - start;
355  return (retval);
356 }
357 
358 
368 static int read_response (const struct DNS_query *q, int len,
369  WORD qtype, void *addr)
370 {
371  WORD nans = intel16 (q->head.ancount); /* # of answers */
372  WORD flags = intel16 (q->head.flags);
373  BYTE rcode = (DRCODE & flags);
374  BYTE space [sizeof(q->body)];
375  const BYTE *p;
376  int i, num_addr;
377 
378  if (rcode != DNS_SRV_OK) /* not okay reply */
379  {
380  dom_errno = rcode;
381  return (0);
382  }
383 
384  if (nans == 0 || /* not at least one answer */
385  !(flags & DQR)) /* response flag not set */
386  {
387  dom_errno = DNS_SRV_NAME;
388  return (0);
389  }
390 
391  len -= sizeof(q->head);
392  p = &q->body[0];
393  i = unpack_domain (q, p, len, space, sizeof(space));
394  if (i < 0)
395  {
396  dom_errno = DNS_CLI_ILL_RESP;
397  return (0);
398  }
399 
400  /* spec defines name then QTYPE + QCLASS = 4 bytes
401  */
402  p += i + 4;
403 
404  /* no canonical name yet
405  */
406  dom_cname[0] = '\0';
407 
408  /* There may be several answers. We will return the first A or
409  * AAAA-record. If there's a CNAME-record, store the name too.
410  */
411  num_addr = 0;
412  while (nans-- > 0 && len > 0) /* look at each answer */
413  {
414  const struct DNS_resource *rrp;
415  size_t rr_len;
416  WORD rr_type;
417 
418  i = unpack_domain (q, p, len, space, sizeof(space));
419  if (i < 0)
420  break;
421 
422  p += i; /* account for string */
423  rrp = (struct DNS_resource*) p; /* resource record here */
424  rr_len = intel16 (rrp->rdlength); /* length of this record */
425  rr_type = intel16 (rrp->rtype);
426 
427  if (intel16(rrp->rclass) == DIN) /* Internet (ARPA) class */
428  {
429  if (rr_type == qtype) /* Record type A or AAAA */
430  {
431  BOOL is_ip6 = (qtype == DTYPE_AAAA);
432 
433  if (num_addr == 0) /* prefered address should always be 1st */
434  {
435  /* save IPv4/IPv6 address */
436  if (is_ip6)
437  memcpy (addr, &rrp->rdata[0], sizeof(ip6_address));
438  else *(DWORD*)addr = intel (*(DWORD*)&rrp->rdata[0]);
439 
440  dom_ttl = intel (rrp->ttl); /* TTL in seconds */
441  dom_errno = DNS_SRV_OK;
442  }
443  else
444  store_alt_address (&rrp->rdata[0], num_addr-1, is_ip6);
445  num_addr++;
446  }
447  else if (rr_type == DTYPE_CNAME && !dom_cname[0])
448  {
449  size_t max = sizeof(dom_cname) - 1;
450  extract_cname (q, (const char*)rrp->rdata, dom_cname, max);
451  }
452  }
453  p += RESOURCE_HEAD_SIZE + rr_len; /* length of rest of RR */
454  len -= RESOURCE_HEAD_SIZE + rr_len;
455  }
456 
457  if (num_addr > 0)
458  return (1);
459 
460  /* Could be a reponse with a CNAME record but no A record, so
461  * turn it into a "Hostname not found" error.
462  */
463  dom_errno = DNS_SRV_NAME;
464  return (0);
465 }
466 
467 /*
468  * Check if the ID in the reply is among our ID(s) sent.
469  * If not, ignore the response and keep waiting.
470  */
471 static __inline BOOL legal_ident (WORD id, const WORD *cache, int num)
472 {
473  int i;
474 
475  for (i = 0; i < num; i++)
476  if (id == cache[i])
477  return (TRUE);
478  return (FALSE);
479 }
480 
490 static int lookup_domain (
491  struct DNS_query *q, /* the UDP/IPv4 query packet */
492  const char *mname, /* the host-name to query */
493  BOOL add_dom, /* append domain suffix */
494  DWORD nameserver, /* nameserver to use */
495  BOOL *timedout, /* set on timeout */
496  BOOL is_aaaa, /* Query A or AAAA record */
497  void *addr) /* return address */
498 {
499  _udp_Socket sock;
500  sock_type *dom_sock = NULL;
501 
502  struct DNS_query reply;
503  char namebuf [3*MAX_HOSTLEN]; /* may overflow!! */
504  size_t len;
505  int rc;
506  WORD qtype = is_aaaa ? DTYPE_AAAA : DTYPE_A;
507  WORD id_cache [100]; /* should be plenty */
508  int id_index = 0;
509  WORD sec;
510 
511  *timedout = TRUE; /* assume we will timeout */
512 
513  if (!nameserver) /* no nameserver, give up now */
514  {
515  _resolve_exit = TRUE;
516  dom_errno = DNS_CLI_NOSERV;
517  outsnl (dom_strerror(dom_errno));
518  return (0);
519  }
520 
521  while (*mname && *mname <= ' ') /* kill leading cruft */
522  mname++;
523 
524  if (*mname == '\0')
525  {
526  dom_errno = DNS_CLI_OTHER;
527  return (0);
528  }
529 
530  strcpy (namebuf, mname);
531 
532 #if defined(USE_IDNA)
533  /*
534  * Convert 'namebuf' to ACE form if needed
535  */
536  len = sizeof (namebuf);
537  if (dns_do_idna && !IDNA_convert_to_ACE(namebuf,&len))
538  {
539  dom_errno = DNS_CLI_ILL_IDNA;
540  return (0);
541  }
542 #endif
543 
544  if (add_dom)
545  {
546  int dot = strlen (namebuf) - 1;
547 
548  if (namebuf[dot] != '.') /* if no trailing dot */
549  {
550  if (loc_domain) /* there is a search list */
551  {
552  strcat (namebuf, ".");
553  strcat (namebuf, get_path(loc_domain,1));
554  }
555  }
556  else
557  namebuf [dot] = '\0'; /* kill trailing dot */
558  }
559 
560  /*
561  * This is not terribly good, but it attempts to use a binary
562  * exponentially increasing delay.
563  */
564 
565  for (sec = 2; sec < dns_timeout-1 && !_resolve_exit; sec *= 2)
566  {
567  q->head.ident = Random (1, USHRT_MAX);
568 
569  /* We might get a reply for a previous request with different ID.
570  * We therefore use a small cache of IDs sent.
571  */
572  if (id_index < DIM(id_cache))
573  id_cache [id_index++] = q->head.ident;
574  else outsnl (_LANG("udp_dom(): ID cache full"));
575 
576  dom_sock = (sock_type*) &sock;
577 
578  if (!send_query(dom_sock,q,namebuf,nameserver,qtype))
579  {
580  _resolve_timeout = TRUE;
581  rc = 0;
582  goto quit; /* doesn't hurt to do sock_close() if udp_open() fails */
583  }
584 
585 again:
586  ip_timer_init (dom_sock, sec);
587  do
588  {
589  if (!tcp_tick(dom_sock)) /* ICMP Port unreachable etc. */
590  {
591  rc = 0;
592  dom_errno = DNS_CLI_REFUSE;
593  goto quit;
594  }
595 
596  if (ip_timer_expired(dom_sock) || chk_timeout(res_timeout))
597  {
598  /* continue the for-loop with a new request */
599  break;
600  }
601 
602  if (_watt_cbroke || (_resolve_hook && (*_resolve_hook)() == 0))
603  {
604  dom_errno = DNS_CLI_USERQUIT;
605  _resolve_exit = TRUE;
606  rc = 0;
607  goto quit;
608  }
609 
610  if (dom_sock->udp.usr_yield)
611  (*dom_sock->udp.usr_yield)();
612  else WATT_YIELD();
613 
614  if (sock_dataready(dom_sock))
615  *timedout = FALSE;
616  }
617  while (*timedout);
618 
619  if (!*timedout) /* got an answer */
620  break;
621  }
622 
623  if (*timedout || !dom_sock)
624  {
625  _resolve_timeout = TRUE;
626  rc = 0;
627  dom_errno = DNS_CLI_TIMEOUT;
628  }
629  else
630  {
631  memset (&reply, 0, sizeof(reply));
632  len = sock_fastread (dom_sock, (BYTE*)&reply, sizeof(reply));
633  if (len < SIZEOF(reply.head))
634  {
635  dom_errno = DNS_CLI_ILL_RESP;
636  rc = 0;
637  }
638  else if (!legal_ident(reply.head.ident,id_cache,id_index))
639  {
640  *timedout = TRUE;
641  goto again;
642  }
643  else
644  {
645  rc = read_response (&reply, len, qtype, addr);
646 #if defined(USE_IDNA)
647  if (dns_do_idna && dom_cname[0])
648  {
649  len = sizeof(dom_cname);
650  IDNA_convert_from_ACE (dom_cname, &len);
651  dom_remove_dot (dom_cname);
652  }
653 #endif
654  }
655  }
656 
657 quit:
658  if (dom_sock) /* if we ran the above for-loop */
659  sock_close (dom_sock);
660  return (rc);
661 }
662 
667 static const char *next_domain (const char *domain, int count)
668 {
669  const char *p = domain;
670  int i;
671 
672  for (i = 0; i < count; i++)
673  {
674  p = strchr (p, '.');
675  if (!p)
676  return (NULL);
677  p++;
678  }
679  return (p);
680 }
681 
685 static const char *server_error (enum DNS_serv_resp err)
686 {
687  switch (err)
688  {
689  case DNS_SRV_OK:
690  return ("Success");
691  case DNS_SRV_FORM:
692  return ("Format error");
693  case DNS_SRV_FAIL:
694  return ("Error in response");
695  case DNS_SRV_NAME:
696  return ("Hostname not found");
697  case DNS_SRV_NOTIMPL:
698  return ("Not implemented");
699  case DNS_SRV_REFUSE:
700  return ("Service refused");
701  case DNS_SRV_MAX:
702  break;
703  }
704  return (NULL);
705 }
706 
710 static const char *client_error (enum DNS_client_code err)
711 {
712  switch (err)
713  {
714  case DNS_CLI_SYSTEM:
715  return (char*) strerror_s_ (_w32_errno);
716  case DNS_CLI_USERQUIT:
717  return ("User terminated");
718  case DNS_CLI_NOSERV:
719  return ("No nameserver defined");
720  case DNS_CLI_TIMEOUT:
721  return ("Request timeout");
722  case DNS_CLI_ILL_RESP:
723  return ("Illegal short response");
724  case DNS_CLI_ILL_IDNA:
725  return ("IDNA convertion failed");
726  case DNS_CLI_TOOBIG:
727  return ("Name too large");
728  case DNS_CLI_REFUSE:
729  return ("Service refused");
730  case DNS_CLI_NOIP:
731  return ("Cannot resolve without IP");
732  case DNS_CLI_NOIPV6:
733  return ("IPv6 DNS disabled");
734  case DNS_CLI_OTHER:
735  return ("Other error");
736  case DNS_CLI_MAX:
737  break;
738  }
739  return (NULL);
740 }
741 
742 
746 const char *W32_CALL dom_strerror (int err)
747 {
748  static char buf[80];
749  const char *rc = err < DNS_SRV_MAX ? server_error (err) :
750  err < DNS_CLI_MAX ? client_error (err) : NULL;
751  if (rc)
752  return (rc);
753  strcpy (buf, "Unknown error ");
754  itoa (err, buf+strlen(buf), 10);
755  return (buf);
756 }
757 
758 /*
759  *
760  */
761 char *W32_CALL dom_remove_dot (char *name)
762 {
763  char *dot = strrchr (name, '.');
764 
765  if (dot && dot[1] == '\0' && dot > name+1)
766  *dot = '\0';
767  return (name);
768 }
769 
775 DWORD W32_CALL resolve (const char *name)
776 {
777  DWORD ip4_addr = 0UL;
778  int count;
779  char namebuf [MAX_HOSTLEN], *dot;
780  BOOL timeout [MAX_NAMESERVERS];
781  BOOL got_ip = FALSE;
782  BOOL recurse = TRUE;
783  unsigned len;
784  static WORD brk_mode;
785  struct DNS_query request;
786 
787  if (!name || *name == '\0')
788  {
789  dom_errno = DNS_CLI_OTHER;
790  return (0);
791  }
792 
793  len = strlen (name);
794  if (len >= sizeof(namebuf)-1)
795  {
796  dom_errno = DNS_CLI_TOOBIG;
797  return (0);
798  }
799 
800  memcpy (namebuf, name, len+1); /* make a copy of 'name' */
801  rip (namebuf); /* strip off '\r' and/or '\n' */
802 
803  if (isaddr(namebuf))
804  {
805  dom_errno = 0;
806  return aton (namebuf);
807  }
808 
809  /* Names with trailing '.' shall not perform a DNS recursion
810  */
811  dot = strrchr (namebuf, '.');
812  if (dot && dot[1] == '\0')
813  {
814  *dot = '\0';
815  recurse = FALSE;
816  }
817 
818 #if defined(USE_BSD_API)
819  if (!called_from_ghbn) /* This hack avoids reentrancy */
820  { /* from gethostbyname() */
821  const struct hostent *h;
822 
823  called_from_resolve = TRUE; /* ditto hack ! (vice versa) */
824  h = gethostbyname (namebuf);
825  called_from_resolve = FALSE;
826  if (h) /* IP from host-file or cache */
827  {
828  /*
829  * NOTE: gethostbyname() returns network order
830  * We assume IPv4 (32-bit)
831  */
832  dom_errno = 0;
833  return intel (*(DWORD*)h->h_addr_list[0]);
834  }
835 
836  /* not found in host-file or cache, ask the DNS server(s)
837  */
838  }
839 #endif
840 
841 #if defined(WIN32)
842  /*
843  * Try the WinDns cache first
844  */
845  if (WinDnsQuery_A4(namebuf, &ip4_addr))
846  return (ip4_addr);
847 #endif
848 
849  /* If no nameserver or no IP-address, give up now
850  */
851  if (last_nameserver == 0)
852  {
853  dom_errno = DNS_CLI_NOSERV;
854  outsnl (dom_strerror(dom_errno));
855  return (0);
856  }
857 
858  if (my_ip_addr == 0)
859  {
860  dom_errno = DNS_CLI_NOIP;
861  outsnl (dom_strerror(dom_errno));
862  return (0);
863  }
864 
865  if (dns_timeout == 0)
866  dns_timeout = sock_delay << 2;
867  res_timeout = set_timeout (1000 * dns_timeout);
868 
869  count = 0;
870  memset (&timeout, 0, sizeof(timeout));
871  query_init (&request, FALSE);
872 
873  NEW_BREAK_MODE (brk_mode, 1);
874 
875  _resolve_exit = _resolve_timeout = FALSE;
876 
877  do
878  {
879  int i;
880 
881  if (!recurse || strchr(namebuf,'.'))
882  {
883  loc_domain = NULL;
884  count = -1;
885  }
886  else if (!dns_recurse && count == 0)
887  {
888  loc_domain = NULL;
889  count = -1;
890  }
891  else
892  {
893  loc_domain = next_domain (def_domain, count);
894  if (!loc_domain)
895  count = -1; /* use default name */
896  }
897 
898  for (i = 0; i < last_nameserver; i++)
899  {
900  if (!timeout[i])
901  {
902  int rc = lookup_domain (&request, namebuf, count != -1,
903  def_nameservers[i], timeout+i,
904  FALSE, &ip4_addr);
905  if (rc)
906  {
907  got_ip = TRUE;
908  break; /* got address, bail out of for loop */
909  }
910  if (_resolve_exit)
911  break; /* an error occured, return to caller */
912  }
913 
914  /*
915  * Should we really try the other nameservers if the first
916  * says the host doesn't exist? Maybe a trusting mechanism
917  * is needed (?)
918  */
919  }
920  if (count == -1)
921  break;
922  count++;
923  }
924  while (!got_ip && !_resolve_exit);
925 
926 #if defined(WIN32)
927  /* Put the result in the WinDns cache.
928  */
929  if (got_ip)
930  WinDnsCachePut_A4 (namebuf, ip4_addr);
931 #endif
932 
933  OLD_BREAK_MODE (brk_mode);
934 
935  return (ip4_addr);
936 }
937 
938 #if defined(USE_IPV6)
939 int W32_CALL resolve_ip6 (const char *name, void *addr)
940 {
941  struct DNS_query request;
942  ip6_address ip6_addr;
943 
944  int count;
945  unsigned len;
946  char namebuf [MAX_HOSTLEN];
947  BOOL timeout [MAX_NAMESERVERS];
948  WORD brk_mode;
949  BOOL got_ip = FALSE;
950 
951  if (!dns_do_ipv6)
952  {
953  dom_errno = DNS_CLI_NOIPV6;
954  TCP_CONSOLE_MSG (1, ("%s\n", dom_strerror(dom_errno)));
955  return (0);
956  }
957 
958  len = strlen (name);
959  if (len >= sizeof(namebuf)-1)
960  {
961  dom_errno = DNS_CLI_TOOBIG;
962  TCP_CONSOLE_MSG (1, ("%s\n", dom_strerror(dom_errno)));
963  return (0);
964  }
965 
966  memcpy (namebuf, name, len+1);
967  rip (namebuf);
968 
969 #if defined(WIN32)
970  /*
971  * Try the WinDns cache first
972  */
973  if (WinDnsQuery_A6(namebuf, &ip6_addr))
974  {
975  memcpy (addr, &ip6_addr, sizeof(ip6_addr));
976  return (1);
977  }
978 #endif
979 
980  if (last_nameserver == 0)
981  {
982  dom_errno = DNS_CLI_NOSERV;
983  outsnl (dom_strerror(dom_errno));
984  return (0);
985  }
986 
987  if (my_ip_addr == 0)
988  {
989  dom_errno = DNS_CLI_NOIP;
990  outsnl (dom_strerror(dom_errno));
991  return (0);
992  }
993 
994  if (dns_timeout == 0)
995  dns_timeout = sock_delay << 2;
996  res_timeout = set_timeout (1000 * dns_timeout);
997 
998  count = 0;
999  memset (&timeout, 0, sizeof(timeout));
1000  query_init (&request, TRUE);
1001 
1002  NEW_BREAK_MODE (brk_mode, 1);
1003  _resolve_exit = _resolve_timeout = FALSE;
1004 
1005  do
1006  {
1007  int i;
1008 
1009  if (strchr(namebuf,'.'))
1010  {
1011  loc_domain = NULL;
1012  count = -1;
1013  }
1014  else if (!dns_recurse && count == 0)
1015  {
1016  loc_domain = NULL;
1017  count = -1;
1018  }
1019  else
1020  {
1021  loc_domain = next_domain (def_domain, count);
1022  if (!loc_domain)
1023  count = -1;
1024  }
1025 
1026  for (i = 0; i < last_nameserver; i++)
1027  {
1028  if (!timeout[i])
1029  {
1030  int rc = lookup_domain (&request, namebuf, count != -1,
1031  def_nameservers[i], timeout+i,
1032  TRUE, &ip6_addr);
1033  if (rc)
1034  {
1035  got_ip = TRUE;
1036  break; /* got name, bail out of for loop */
1037  }
1038  if (_resolve_exit)
1039  break; /* an error occured, return to caller */
1040  }
1041 
1042  /*
1043  * Should we really try the other nameservers if the first
1044  * says the host doesn't exist? Maybe a trusting mechanism
1045  * is needed (?)
1046  */
1047  }
1048  if (count == -1)
1049  break;
1050  count++;
1051  }
1052  while (!got_ip && !_resolve_exit);
1053 
1054  if (got_ip)
1055  {
1056  memcpy (addr, &ip6_addr, sizeof(ip6_addr));
1057 
1058 #if defined(WIN32)
1059  /* Put the result in the WinDns cache.
1060  */
1061  WinDnsCachePut_A6 (namebuf, &ip6_addr);
1062 #endif
1063  }
1064 
1065  OLD_BREAK_MODE (brk_mode);
1066  return (got_ip ? 1 : 0);
1067 }
1068 #endif /* USE_IPV6 */
1069 
unsigned W32_CALL Random(unsigned a, unsigned b)
Returns a random integer in range [a..b].
Definition: misc.c:742
DWORD W32_CALL aton(const char *str)
Converts [a.b.c.d] or a.b.c.d to 32 bit IPv4 address.
Definition: netaddr.c:86
static int send_query(sock_type *sock, struct DNS_query *q, const char *name, DWORD towho, WORD qtype)
Put together a domain lookup packet and send it.
Definition: pcdns.c:197
int W32_CALL udp_open(_udp_Socket *s, WORD lport, DWORD ip, WORD port, ProtoHandler handler)
UDP active open.
Definition: pctcp.c:192
BOOL IDNA_convert_from_ACE(char *name, size_t *size)
Convert a possibly ACE-encoded name to a name in native codepage.
Definition: idna.c:451
static int pack_domain(BYTE *dst, const char *src)
Pack a regular text string into a packed domain name, suitable for the name server.
Definition: pcdns.c:148
static const char * client_error(enum DNS_client_code err)
Return text for client-side errors.
Definition: pcdns.c:710
int W32_CALL sock_close(sock_type *s)
Close a UDP/TCP socket.
Definition: pctcp.c:3139
Definition: netdb.h:102
static const char * server_error(enum DNS_serv_resp err)
Return text for server-side errors.
Definition: pcdns.c:685
volatile int _watt_cbroke
Definition: pc_cbrk.c:47
static const char * next_domain(const char *domain, int count)
Given domain and count = 0,1,2,..., return next larger domain or NULL when no more are available...
Definition: pcdns.c:667
Core definitions.
static void store_alt_address(const void *data, int idx, BOOL is_ip6)
Remember alternate address in dom_a?list[].
Definition: pcdns.c:128
int W32_CALL sock_write(sock_type *s, const BYTE *data, int len)
Writes data and returns length written.
Definition: pctcp.c:2960
static void extract_cname(const struct DNS_query *q, const char *src, char *dest, size_t max)
Extract the CNAME from a resource record.
Definition: pcdns.c:268
static int read_response(const struct DNS_query *q, int len, WORD qtype, void *addr)
Extract the IPv4/v6 address from a response message (A or AAAA record).
Definition: pcdns.c:368
BOOL IDNA_convert_to_ACE(char *name, size_t *size)
Convert a possibly non-ASCII name into ACE-form.
Definition: idna.c:384
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
int W32_CALL sock_fastread(sock_type *s, BYTE *buf, int len)
Read a socket with maximum 'len' bytes.
Definition: pctcp.c:2931
BOOL W32_CALL isaddr(const char *str)
Check if 'str' is simply an ip address.
Definition: netaddr.c:128
static int unpack_domain(const struct DNS_query *q, const BYTE *src, size_t src_size, BYTE *dst, size_t dst_size)
Unpack a received compressed domain name.
Definition: pcdns.c:314
BOOL called_from_resolve
Hacks to make gethostbyname() and resolve() cooperate.
Definition: pcdns.c:60
const char *W32_CALL dom_strerror(int err)
Return text for error code (dom_errno).
Definition: pcdns.c:746
DWORD my_ip_addr
our IP address
Definition: pctcp.c:70
char defaultdomain[MAX_HOSTLEN+1]
The 2 next variables are loaded from WATTCP.CFG file.
Definition: pcdns.c:71
static int lookup_domain(struct DNS_query *q, const char *mname, BOOL add_dom, DWORD nameserver, BOOL *timedout, BOOL is_aaaa, void *addr)
DOMAIN based name lookup.
Definition: pcdns.c:490
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
static void query_init(struct DNS_query *q, BOOL is_ip6)
Initialise the query header and clear the alternate addr-list.
Definition: pcdns.c:107
DWORD W32_CALL resolve(const char *name)
Convert host name to an address.
Definition: pcdns.c:775
WORD W32_CALL sock_dataready(sock_type *s)
sock_dataready - returns number of bytes waiting to be read.
Definition: sock_io.c:246
BOOL W32_CALL chk_timeout(DWORD value)
Check if milli-sec value has expired:
Definition: timer.c:547
char *W32_CALL rip(char *s)
Removes end-of-line termination from a string.
Definition: strings.c:180