Watt-32 tcp/ip  2.2 dev-rel.10
udp_rev.c
Go to the documentation of this file.
1 
5 /*
6  * Reverse IPv4/IPv6 lookup functions
7  *
8  * Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  * must display the following acknowledgement:
20  * This product includes software developed by Gisle Vanem
21  * Bergen, Norway.
22  *
23  * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * \version 0.2
35  */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include "wattcp.h"
42 #include "strings.h"
43 #include "misc.h"
44 #include "timer.h"
45 #include "language.h"
46 #include "netaddr.h"
47 #include "pctcp.h"
48 #include "pcdbug.h"
49 #include "pcconfig.h"
50 #include "idna.h"
51 #include "bsdname.h"
52 #include "pcdns.h"
53 
54 static BOOL read_response (sock_type *s, char *name, size_t size);
55 static BYTE *dns_labels (BYTE *bp, BYTE *p, BYTE *ep, char *result);
56 static BYTE *dns_resource (WORD req_qtype, BYTE *bp, BYTE *p,
57  BYTE *ep, char *result);
58 
63 static size_t query_init_ip4 (struct DNS_query *q, DWORD ip)
64 {
65  char *c;
66  BYTE i, x;
67 
68  q->head.ident = set_timeout (0UL) & 0xFFFF; /* Random ID */
69  q->head.flags = intel16 (DRD); /* Query, Recursion desired */
70  q->head.qdcount = intel16 (1);
71  q->head.ancount = 0;
72  q->head.nscount = 0;
73  q->head.arcount = 0;
74 
75  c = (char*) &q->body[0];
76  ip = ntohl (ip);
77  for (i = 0; i < sizeof(ip); i++)
78  {
79  x = ip & 255;
80  ip >>= 8;
81  *c = (x < 10) ? 1 : (x < 100) ? 2 : 3;
82  itoa (x, c+1, 10);
83  c += *c + 1;
84  }
85  strcpy (c, "\7in-addr\4arpa");
86  c += 14;
87  *(WORD*) c = intel16 (DTYPE_PTR);
88  c += sizeof(WORD);
89  *(WORD*) c = intel16 (DIN);
90  c += sizeof(WORD);
91 
92  return (c - (char*)q);
93 }
94 
95 
100 static BOOL reverse_lookup (const struct DNS_query *q, size_t qlen,
101  char *name, size_t size, DWORD nameserver)
102 {
103  BOOL ret;
104  BOOL ready = FALSE;
105  BOOL quit = FALSE;
106  WORD sec;
107  DWORD timer;
108  _udp_Socket dom_sock;
109  sock_type *sock = NULL;
110 
111  if (!nameserver) /* no nameserver, give up */
112  {
113  dom_errno = DNS_CLI_NOSERV;
114  outsnl (dom_strerror(dom_errno));
115  return (FALSE);
116  }
117 
118  if (!udp_open(&dom_sock, DOM_SRC_PORT, nameserver, DOM_DST_PORT, NULL))
119  {
120  dom_errno = DNS_CLI_SYSTEM;
121  return (FALSE);
122  }
123 
124  timer = set_timeout (1000 * dns_timeout); /* overall expiry (for all servers) */
125 
126  for (sec = 2; sec < dns_timeout-1 && !quit && !_resolve_exit; sec *= 2)
127  {
128  sock = (sock_type*)&dom_sock;
129  sock_write (sock, (const BYTE*)q, qlen);
130  ip_timer_init (sock, sec); /* per server expiry */
131 
132  do
133  {
134  tcp_tick (sock);
135 
136  if (_watt_cbroke || (_resolve_hook && (*_resolve_hook)() == 0))
137  {
138  _resolve_exit = 1; /* terminate do_reverse_resolve() */
139  dom_errno = DNS_CLI_USERQUIT;
140  quit = TRUE;
141  ready = FALSE;
142  break;
143  }
144  if (sock_dataready(sock))
145  {
146  quit = TRUE;
147  ready = TRUE;
148  }
149  else if (ip_timer_expired(sock) || chk_timeout(timer))
150  {
151  dom_errno = DNS_CLI_TIMEOUT;
152  ready = FALSE;
153  _resolve_timeout = 1;
154  break; /* retry */
155  }
156  if (sock->udp.usr_yield)
157  (*sock->udp.usr_yield)();
158  else WATT_YIELD();
159  }
160  while (!quit);
161  }
162 
163  if (ready && sock)
164  ret = read_response (sock, name, size);
165  else ret = FALSE;
166 
167  if (sock) /* if we ran the above for-loop */
168  sock_close (sock);
169  return (ret);
170 }
171 
177 {
178  char name [MAX_HOSTLEN];
179 
180  if (!reverse_resolve_ip4(htonl(my_ip_addr),name,sizeof(name)))
181  return (0);
182 
183  if (debug_on >= 1)
184  {
185  outs (_LANG("My FQDN: "));
186  outsnl (name);
187  }
188  if (sethostname(name,sizeof(name)) < 0)
189  return (0);
190  return (1);
191 }
192 
193 /*------------------------------------------------------------------*/
194 
195 static int do_reverse_resolve (const struct DNS_query *q, size_t qlen,
196  char *result, size_t size)
197 {
198  WORD brk_mode;
199  int i;
200 
201  if (dns_timeout == 0)
202  dns_timeout = (UINT)sock_delay << 2;
203 
204  NEW_BREAK_MODE (brk_mode, 1);
205 
206  _resolve_exit = _resolve_timeout = 0;
207 
208  *result = '\0';
209  dom_cname[0] = '\0';
210 
211  for (i = 0; i < last_nameserver; ++i)
212  if (reverse_lookup(q,qlen,result,size,def_nameservers[i]) ||
213  _resolve_exit)
214  break;
215 
216  OLD_BREAK_MODE (brk_mode);
217  return (*result != '\0');
218 }
219 
220 /*------------------------------------------------------------------*/
221 
222 int reverse_resolve_ip4 (DWORD ip, char *result, size_t size)
223 {
224  struct DNS_query q;
225  size_t len = query_init_ip4 (&q, ip);
226 
227  memset (&dom_a4list, 0, sizeof(dom_a4list));
228 
229 #if defined(WIN32)
230  /* The 'result' could be a wide-str if _UNICODE is used. Caller needs to test.
231  */
232  if (WinDnsQuery_PTR4(ip, (TCHAR*)result, size))
233  return (1);
234 #endif
235  return do_reverse_resolve (&q, len, result, size);
236 }
237 
238 #if defined(USE_IPV6)
239 
240 #define USE_IP6_BITSTRING 0 /* RFC-2673 */
241 
247 static size_t query_init_ip6 (struct DNS_query *q, const void *addr)
248 {
249  const BYTE *ip = (const BYTE*) addr;
250  char *c;
251  int i;
252 
253  q->head.ident = set_timeout (0UL) & 0xFFFF; /* Random ID */
254  q->head.flags = intel16 (DRD); /* Query, Recursion desired */
255  q->head.qdcount = intel16 (1); /* 1 query */
256  q->head.ancount = 0;
257  q->head.nscount = 0;
258  q->head.arcount = 0;
259 
260  c = (char*) &q->body[0];
261 
262 #if USE_IP6_BITSTRING
263  strcpy (c, "\3\\[x");
264  c += 4;
265  for (i = 0; i < SIZEOF(ip6_address); i++)
266  {
267  int hi = ip[i] >> 4;
268  int lo = ip[i] & 15;
269 
270  if (i == SIZEOF(ip6_address) - 1)
271  *c++ = 5;
272  else *c++ = 4;
273  *c++ = hex_chars_lower [hi];
274  *c++ = hex_chars_lower [lo];
275  }
276  strcpy (c, "]\3ip6\4arpa");
277  c += 11;
278 
279 #else
280  for (i = sizeof(ip6_address)-1; i >= 0; i--)
281  {
282  int hi = ip[i] >> 4;
283  int lo = ip[i] & 15;
284 
285  *c++ = 2;
286  *c++ = hex_chars_lower [hi];
287  *c++ = hex_chars_lower [lo];
288  }
289  strcpy (c, "\3ip6\4arpa");
290  c += 10;
291 #endif
292 
293  *(WORD*) c = intel16 (DTYPE_PTR);
294  c += sizeof(WORD);
295  *(WORD*) c = intel16 (DIN);
296  c += sizeof(WORD);
297 
298  return (c - (char*)q);
299 }
300 
301 int reverse_resolve_ip6 (const void *addr, char *result, size_t size)
302 {
303  struct DNS_query q;
304  size_t len = query_init_ip6 (&q, addr);
305 
306  memset (&dom_a6list, 0, sizeof(dom_a6list));
307 
308 #if defined(WIN32)
309  /* The 'result' could be a wide-str if _UNICODE is used. Caller needs to test.
310  */
311  if (WinDnsQuery_PTR6(addr, (TCHAR*)result, size))
312  return (1);
313 #endif
314  return do_reverse_resolve (&q, len, result, size);
315 }
316 #endif /* USE_IPV6 */
317 
318 
319 static BOOL read_response (sock_type *s, char *name, size_t size)
320 {
321  struct {
322  struct DNS_Header head;
323  BYTE body [DOMSIZE];
324  } response;
325 
326  struct DNS_Header *dns = &response.head;
327  int len, num_q, num_ans;
328  BYTE *bp, *body, *end_p;
329  char result [DOMSIZE];
330 
331  #define CHECK_SHORT(p) if ((p) > len+(BYTE*)&response) goto short_resp
332 
333  memset (&response, 0, sizeof(response));
334  len = sock_fastread (s, (BYTE*)&response, sizeof(response));
335  bp = (BYTE*) &response;
336  body = (BYTE*) &response.body;
337  end_p = (BYTE*) &response + len;
338 
339  CHECK_SHORT (body);
340 
341  num_q = intel16 (dns->dns_num_q);
342  num_ans = intel16 (dns->dns_num_ans);
343  if (dns->dns_fl_rcode != DNS_SRV_OK || num_ans == 0)
344  goto no_name;
345 
346  /* Go past the question part of the packet.
347  */
348  while (num_q > 0)
349  {
350  body = dns_labels (bp, body, end_p, result);
351  CHECK_SHORT (body);
352  body += 4; /* skip Qtype and Qclass */
353  num_q--;
354  }
355 
356  /* Parse the resource records for the answers
357  */
358  while (num_ans > 0)
359  {
360  memset (&result, '\0', sizeof(result));
361  body = dns_resource (DTYPE_PTR, bp, body, end_p, result);
362  CHECK_SHORT (body);
363  num_ans--;
364  if (result[0])
365  {
366 #if defined(USE_IDNA)
367  if (dns_do_idna && !IDNA_convert_from_ACE(result,&size))
368  {
369  dom_errno = DNS_CLI_ILL_IDNA;
370  return (FALSE);
371  }
372 #endif
373  dom_errno = DNS_SRV_OK;
374  _strlcpy (name, dom_remove_dot(result), size);
375  return (TRUE);
376  }
377  }
378 
379 no_name:
380  dom_errno = dns->dns_fl_rcode;
381  return (FALSE);
382 
383 short_resp:
384  dom_errno = DNS_CLI_ILL_RESP;
385  return (FALSE);
386 }
387 
388 /*
389  * Recursively parse a label entry in a DNS packet
390  * 'bp' points to a beginning of DNS header.
391  * 'p' points to a DNS label.
392  */
393 static BYTE *dns_labels (BYTE *bp, BYTE *p, BYTE *ep, char *result)
394 {
395  while (1)
396  {
397  BYTE count = *p++;
398  WORD offset;
399 
400  if (count >= 0xC0)
401  {
402  /* There's a pointer (rel to 'bp' start) in this label.
403  * Let's grab the 14 low-order bits and run with them.
404  */
405  count -= 0xC0;
406  offset = (WORD) (((unsigned)(count) << 8) + *p++);
407 
408  dns_labels (bp, bp+offset, ep, result);
409  return (p);
410  }
411  if (count == 0)
412  break;
413 
414  while (count > 0)
415  {
416  if (p <= ep)
417  {
418  *result++ = *p++;
419  count--;
420  }
421  else
422  return (p); /* Packet length exceeded */
423  }
424  *result++ = '.';
425  *result = '\0'; /* 0-terminate incase this is the last label */
426  }
427  return (p);
428 }
429 
430 /*
431  * Return the given resource record.
432  */
433 static BYTE *dns_resource (WORD req_qtype, BYTE *bp, BYTE *p, BYTE *ep, char *result)
434 {
435  DWORD ttl;
436  WORD qtype, qclass, reslen;
437  char dummy [DOMSIZE];
438 
439  p = dns_labels (bp, p, ep, dummy);
440 
441  /* Do query type, class, ttl and resource length
442  */
443  qtype = intel16 (*(WORD*)p); p += sizeof(qtype);
444  qclass = intel16 (*(WORD*)p); p += sizeof(qclass);
445  ttl = intel (*(DWORD*)p); p += sizeof(ttl);
446  reslen = intel16 (*(WORD*)p); p += sizeof(reslen);
447 
448  /* Do resource data.
449  */
450  if (qclass == DIN && qtype == req_qtype)
451  {
452  p = dns_labels (bp, p, ep, result);
453  dom_ttl = ttl;
454  }
455  else
456  p += reslen;
457 
458  return (p);
459 }
460 
int reverse_lookup_myip(void)
Do a reverse lookup on `my_ip_addr'.
Definition: udp_rev.c:176
static BOOL reverse_lookup(const struct DNS_query *q, size_t qlen, char *name, size_t size, DWORD nameserver)
Translate an IPv4/IPv6 address into a host name.
Definition: udp_rev.c:100
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 size_t query_init_ip4(struct DNS_query *q, DWORD ip)
Fill in the reverse lookup question packet.
Definition: udp_rev.c:63
int W32_CALL sock_close(sock_type *s)
Close a UDP/TCP socket.
Definition: pctcp.c:3139
Another definition of 'struct DNS_head'.
Definition: pcdns.h:93
volatile int _watt_cbroke
Definition: pc_cbrk.c:47
Core definitions.
int W32_CALL sock_write(sock_type *s, const BYTE *data, int len)
Writes data and returns length written.
Definition: pctcp.c:2960
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
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
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
Definition: ip.h:67
int W32_CALL sock_fastread(sock_type *s, BYTE *buf, int len)
Read a socket with maximum 'len' bytes.
Definition: pctcp.c:2931
int W32_CALL sethostname(const char *fqdn, SETHOSTNAME_ARG2 len)
BSD-style: Expects a "Fully Qualified Domain Name" in `fqdn'.
Definition: bsdname.c:293
const char *W32_CALL dom_strerror(int err)
Return text for error code (dom_errno).
Definition: pcdns.c:746
static size_t query_init_ip6(struct DNS_query *q, const void *addr)
Fill in the reverse lookup question packet.
Definition: udp_rev.c:247
DWORD my_ip_addr
our IP address
Definition: pctcp.c:70
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
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