Watt-32 tcp/ip  2.2 dev-rel.10
res_send.c
Go to the documentation of this file.
1 
5 /*
6  * ++Copyright++ 1985, 1989, 1993
7  * -
8  * Copyright (c) 1985, 1989, 1993
9  * The Regents of the University of California. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  * must display the following acknowledgement:
21  * This product includes software developed by the University of
22  * California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  * may be used to endorse or promote products derived from this software
25  * without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  * -
39  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
40  *
41  * Permission to use, copy, modify, and distribute this software for any
42  * purpose with or without fee is hereby granted, provided that the above
43  * copyright notice and this permission notice appear in all copies, and that
44  * the name of Digital Equipment Corporation not be used in advertising or
45  * publicity pertaining to distribution of the document or software without
46  * specific, written prior permission.
47  *
48  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
49  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
50  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
51  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
52  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
53  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
54  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55  * SOFTWARE.
56  * -
57  * --Copyright--
58  */
59 
60 /*
61  * 10.Dec-97 Adapted for Watt-32 TCP/IP - G. Vanem (gvanem@yahoo.no)
62  *
63  */
64 
65 /*
66  * Send query to name server and wait for reply.
67  */
68 
69 #include "resolver.h"
70 
71 #if defined(USE_BIND)
72 
73 static sock_type *sock = NULL; /* socket used for communications */
74 static int vc = 0; /* is the socket a virtual ciruit? */
75 static int connected = 0; /* is the socket connected */
76 
77 static int name_server_send (int ns, struct sockaddr_in *nsap);
78 static void resolve_close (void);
79 
80 #define SAME_NS (-1)
81 #define NEXT_NS (-2)
82 
83 
84 #define Dprint(cond,args) if (cond) do { \
85  (*_printf) args; \
86  } while (0)
87 
88 #define DprintQ(cond,args,query,size) \
89  if (cond) do { \
90  (*_printf) args; \
91  __fp_nquery (query,size,stdout); \
92  } while (0)
93 
94 static void Aerror (const char *str, const char *error,
95  struct sockaddr_in address)
96 {
97  if (_res.options & RES_DEBUG)
98  (*_printf) ("res_send: %s (%s/%u): %s\n",
99  str, inet_ntoa(address.sin_addr),
100  ntohs(address.sin_port), error);
101 }
102 
103 static void Perror (const char *str, const char *error)
104 {
105  if (_res.options & RES_DEBUG)
106  (*_printf) ("res_send: %s: %s\n", str, error);
107 }
108 
109 static res_send_qhook Qhook = NULL;
110 static res_send_rhook Rhook = NULL;
111 
112 void W32_CALL res_send_setqhook (res_send_qhook hook)
113 {
114  Qhook = hook;
115 }
116 
117 void W32_CALL res_send_setrhook (res_send_rhook hook)
118 {
119  Rhook = hook;
120 }
121 
122 /*
123  * int res_isourserver(ina)
124  * looks up "ina" in _res.ns_addr_list[]
125  * returns:
126  * 0 : not found
127  * >0 : found
128  * author:
129  * paul vixie, 29may94
130  */
131 int W32_CALL res_isourserver (const struct sockaddr_in *inp)
132 {
133  struct sockaddr_in ina = *inp;
134  int ns;
135 
136  for (ns = 0; ns < _res.nscount; ns++)
137  {
138  const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
139 
140  if (srv->sin_family == ina.sin_family &&
141  srv->sin_port == ina.sin_port &&
142  (srv->sin_addr.s_addr == INADDR_ANY ||
143  srv->sin_addr.s_addr == ina.sin_addr.s_addr))
144  return (1);
145  }
146  return (0);
147 }
148 
149 /*
150  * int res_nameinquery(name, type, class, buf, eom)
151  * look for (name,type,class) in the query section of packet (buf,eom)
152  * returns:
153  * -1 : format error
154  * 0 : not found
155  * >0 : found
156  * author:
157  * paul vixie, 29may94
158  */
159 int W32_CALL res_nameinquery (const char *name, int type, int Class,
160  const u_char *buf, const u_char *eom)
161 {
162  const u_char *cp = buf + HFIXEDSZ;
163  int qdcount = ntohs (((HEADER*)buf)->qdcount);
164 
165  while (qdcount-- > 0)
166  {
167  char tname[MAXDNAME+1];
168  int n, ttype, tclass;
169 
170  n = dn_expand (buf, eom, cp, tname, sizeof(tname));
171  if (n < 0)
172  return (-1);
173  cp += n;
174  ttype = _getshort (cp);
175  cp += INT16SZ;
176  tclass = _getshort (cp);
177  cp += INT16SZ;
178  if (ttype == type && tclass == Class && !stricmp(tname,name))
179  return (1);
180  }
181  return (0);
182 }
183 
184 
185 /*
186  * int res_queriesmatch(buf1, eom1, buf2, eom2)
187  * is there a 1:1 mapping of (name,type,Class)
188  * in (buf1,eom1) and (buf2,eom2)?
189  * returns:
190  * -1 : format error
191  * 0 : not a 1:1 mapping
192  * >0 : is a 1:1 mapping
193  * author:
194  * paul vixie, 29may94
195  */
196 int W32_CALL res_queriesmatch (const u_char *buf1, const u_char *eom1,
197  const u_char *buf2, const u_char *eom2)
198 {
199  const u_char *cp = buf1 + HFIXEDSZ;
200  int qdcount = ntohs (((HEADER*)buf1)->qdcount);
201 
202  if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
203  return (0);
204 
205  while (qdcount-- > 0)
206  {
207  char tname[MAXDNAME+1];
208  int n, ttype, tclass;
209 
210  n = dn_expand (buf1, eom1, cp, tname, sizeof(tname));
211  if (n < 0)
212  return (-1);
213  cp += n;
214  ttype = _getshort (cp);
215  cp += INT16SZ;
216  tclass = _getshort (cp);
217  cp += INT16SZ;
218  if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
219  return (0);
220  }
221  return (1);
222 }
223 
224 /*--------------------------------------------------------------------*/
225 
226 static HEADER *hp, *anhp;
227 static int gotsomewhere, connreset, terrno, Try;
228 static int v_circuit, ns, n;
229 static int ns_buflen, ns_anssiz;
230 static u_long badns;
231 static u_char *ns_buf, *ns_ans;
232 
233 int W32_CALL res_send (const u_char *buf, int buflen, u_char *ans, int anssiz)
234 {
235  hp = (HEADER *) buf;
236  anhp = (HEADER *) ans;
237 
238  ns_buf = (u_char*)buf;
239  ns_ans = ans;
240  ns_buflen = buflen;
241  ns_anssiz = anssiz;
242 
243  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
244  {
245  /* errno should have been set by res_init() in this case
246  */
247  return (-1);
248  }
249  DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
250  (";; res_send()\n"), buf, buflen);
251 
252  v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
253  gotsomewhere = 0;
254  connreset = 0;
255  terrno = ETIMEDOUT;
256  badns = 0;
257 
258  /* Send request, RETRY times, or until successful
259  */
260  for (Try = 0; Try < _res.retry; Try++)
261  {
262  for (ns = 0; ns < _res.nscount; ns++)
263  {
264  struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
265  int rc;
266 
267  do
268  rc = name_server_send (ns, nsap);
269  while (rc == SAME_NS);
270 
271  if (rc != NEXT_NS)
272  return (rc);
273  }
274  }
275 
276  resolve_close();
277  if (!v_circuit)
278  {
279  if (!gotsomewhere)
280  SOCK_ERRNO (ECONNREFUSED); /* no nameservers found */
281  else SOCK_ERRNO (ETIMEDOUT); /* no answer obtained */
282  }
283  else
284  SOCK_ERRNO (terrno);
285  return (-1);
286 }
287 
288 /*------------------------------------------------------------------------*/
289 
290 #if defined(_MSC_VER)
291  #define ERROR_TYPE int volatile /* because '&errno' is used below */
292 #else
293  #define ERROR_TYPE int
294 #endif
295 
296 static int tcp_conn (_tcp_Socket *sock, ERROR_TYPE *error, DWORD timeout)
297 {
298  DWORD timer = set_timeout (timeout);
299  int status = _ip_delay0 ((sock_type*)sock, (int)timeout, NULL, NULL);
300 
301  if (status == -1)
302  {
303  *error = chk_timeout(timer) ? ETIMEDOUT : ECONNREFUSED;
304  return (0);
305  }
306  *error = 0;
307  return (1);
308 }
309 
310 /*------------------------------------------------------------------------*/
311 
312 static int tcp_read (_tcp_Socket *sock, u_char *buf, int len,
313  ERROR_TYPE *error, DWORD timeout)
314 {
315  int status = _ip_delay1 ((sock_type*)sock, (int)timeout, NULL, NULL);
316 
317  if (status == -1)
318  {
319  *error = ETIMEDOUT;
320  return (0);
321  }
322  if (status == 1)
323  {
324  *error = ECONNRESET;
325  return (0);
326  }
327  *error = 0;
328  return sock_fastread ((sock_type*)sock, (BYTE*)buf, len);
329 }
330 
331 /*------------------------------------------------------------------------*/
332 
333 static int udp_read (_udp_Socket *sock, u_char *buf, int len,
334  ERROR_TYPE *error, DWORD timeout)
335 {
336  int status = _ip_delay1 ((sock_type*)sock, (int)timeout, NULL, NULL);
337 
338  if (status == -1)
339  {
340  *error = ETIMEDOUT;
341  return (0);
342  }
343  *error = 0;
344  return sock_fastread ((sock_type*)sock, (BYTE*)buf, len);
345 }
346 
347 /*------------------------------------------------------------------------*/
348 
349 static int name_server_send (int ns, struct sockaddr_in *nsap)
350 {
351  int resplen = 0;
352 
353  if (badns & (1 << ns)) /* this NameServer already marked bad */
354  {
355  resolve_close();
356  return (NEXT_NS);
357  }
358 
359  if (Qhook)
360  {
361  int done = 0;
362  int loops = 0;
363  do
364  {
365  res_sendhookact act = (*Qhook) (&nsap, (const u_char**)&ns_buf,
366  &ns_buflen, ns_ans, ns_anssiz,
367  &resplen);
368  switch (act)
369  {
370  case res_goahead:
371  done = 1;
372  break;
373  case res_nextns:
374  resolve_close();
375  return (NEXT_NS);
376  case res_done:
377  return (resplen);
378  case res_modified:
379  /* give the hook another try */
380  if (++loops < 42)
381  break;
382  /* fallthrough */
383  case res_error:
384  /* fallthrough */
385  default:
386  return (-1);
387  }
388  }
389  while (!done);
390  }
391 
392  Dprint (_res.options & RES_DEBUG,
393  (";; Querying server (# %d) address = %s\n",
394  ns + 1, inet_ntoa(nsap->sin_addr)));
395 
396  if (v_circuit) /* i.e. TCP */
397  {
398  int truncated, slen;
399  u_short len;
400  u_char *cp;
401 
402  /* Use virtual circuit; at most one attempt per server.
403  */
404  Try = _res.retry;
405  truncated = 0;
406  if (!sock || !vc)
407  {
408  DWORD his_ip = ntohl (nsap->sin_addr.s_addr);
409  WORD his_port = ntohs (nsap->sin_port);
410 
411  if (sock)
412  resolve_close();
413 
414  sock = (sock_type*) calloc (sizeof(_tcp_Socket), 1);
415  if (!sock)
416  {
417  Perror ("calloc(vc)", "no memory");
418  return (-1);
419  }
420 
421  if (!tcp_open(&sock->tcp,0,his_ip,his_port,NULL) ||
422  !tcp_conn(&sock->tcp,&errno,dns_timeout))
423  {
424  Aerror ("tcp_open/vc", "failed/timeout", *nsap);
425  badns |= (1 << ns);
426  resolve_close();
427  return (NEXT_NS);
428  }
429  vc = 1;
430  }
431 
432  /* Send length & message
433  */
434  {
435  int send_len = INT16SZ + ns_buflen;
436  BYTE *send_buf = (BYTE*) alloca (send_len);
437 
438  PUTSHORT (ns_buflen, send_buf);
439  memcpy (send_buf + INT16SZ, ns_buf, ns_buflen);
440  if (sock_write(sock,send_buf,send_len) != send_len)
441  {
442  Perror ("sock_write() failed", sockerr(sock));
443  badns |= (1 << ns);
444  resolve_close();
445  return (NEXT_NS);
446  }
447  }
448 
449  /* Receive length & response
450  */
451  cp = ns_ans;
452  len = INT16SZ;
453  while ((n = tcp_read(&sock->tcp,cp,len,&errno,dns_timeout)) > 0)
454  {
455  cp += n;
456  len -= n;
457  slen = (int)len;
458  if (slen <= 0)
459  break;
460  }
461  if (n <= 0)
462  {
463  Perror ("tcp_read() failed", sockerr(sock));
464  resolve_close();
465  return (NEXT_NS);
466  }
467  resplen = _getshort (ns_ans);
468  if (resplen > ns_anssiz)
469  {
470  Dprint (_res.options & RES_DEBUG,(";; response truncated\n"));
471  truncated = 1;
472  len = ns_anssiz;
473  }
474  else
475  len = resplen;
476 
477  cp = ns_ans;
478  while (len && (n = tcp_read(&sock->tcp,cp,len,&errno,dns_timeout)) > 0)
479  {
480  cp += n;
481  len -= n;
482  }
483  if (n <= 0)
484  {
485  Perror ("tcp_read(vc)",sockerr(sock));
486  resolve_close();
487  return (NEXT_NS);
488  }
489  if (truncated)
490  {
491  /* Flush rest of answer so connection stays in synch.
492  */
493  anhp->tc = 1;
494  len = resplen - ns_anssiz;
495  while (len)
496  {
497  u_char junk[PACKETSZ];
498 
499  n = (len > sizeof(junk) ? sizeof(junk) : len);
500  n = tcp_read (&sock->tcp,junk,n,&errno,dns_timeout);
501  if (n > 0)
502  len -= n;
503  else break;
504  }
505  }
506  }
507  else /* !v_circuit, i.e. UDP */
508  {
509  DWORD timeout;
510 
511  if (!sock || vc)
512  {
513  if (vc)
514  resolve_close();
515 
516  sock = (sock_type*) calloc (sizeof(_udp_Socket), 1);
517  if (!sock)
518  {
519  Perror ("calloc(dg)", "no memory");
520  return (-1);
521  }
522  connected = 0;
523  }
524 
525  /* Connect only if we are sure we won't
526  * receive a response from another server.
527  */
528  if (!connected)
529  {
530  DWORD his_ip = ntohl (nsap->sin_addr.s_addr);
531  WORD his_port = ntohs (nsap->sin_port);
532 
533  if (!udp_open(&sock->udp,0,his_ip,his_port,NULL))
534  {
535  Aerror ("connect/dg", "ARP failed", *nsap);
536  badns |= (1 << ns);
537  resolve_close();
538  return (NEXT_NS);
539  }
540  connected = 1;
541  }
542  if (sock_write(sock,(const BYTE*)ns_buf,ns_buflen) != ns_buflen)
543  {
544  Perror ("sock_write() failed", "");
545  badns |= (1 << ns);
546  resolve_close();
547  return (NEXT_NS);
548  }
549 
550  /* Wait for reply
551  */
552  timeout = (unsigned)_res.retrans << Try;
553  if (Try > 0)
554  timeout /= _res.nscount;
555  if ((long)timeout <= 0)
556  timeout = 1;
557 
558  wait:
559 
560  n = udp_read (&sock->udp, ns_ans, ns_anssiz, &errno, timeout);
561  if (n == 0)
562  {
563  Dprint (_res.options & RES_DEBUG, (";; timeout\n"));
564  gotsomewhere = 1;
565  resolve_close();
566  return (NEXT_NS);
567  }
568  gotsomewhere = 1;
569  if (hp->id != anhp->id)
570  {
571  /* response from old query, ignore it.
572  * XXX - potential security hazard could be detected here.
573  */
574  DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY),
575  (";; old answer:\n"), ns_ans, resplen);
576  goto wait;
577  }
578 
579  if (!(_res.options & RES_INSECURE2) &&
580  !res_queriesmatch(ns_buf, ns_buf+ns_buflen, ns_ans, ns_ans+ns_anssiz))
581  {
582  /* response contains wrong query? ignore it.
583  * XXX - potential security hazard could be detected here.
584  */
585  DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY),
586  (";; wrong query name:\n"), ns_ans, resplen);
587  goto wait;
588  }
589  if (anhp->rcode == SERVFAIL ||
590  anhp->rcode == NOTIMP ||
591  anhp->rcode == REFUSED)
592  {
593  DprintQ (_res.options & RES_DEBUG,("server rejected query:\n"),
594  ns_ans,resplen);
595  badns |= (1 << ns);
596  resolve_close();
597 
598  /* don't retry if called from dig */
599  if (!_res.pfcode)
600  return (NEXT_NS);
601  }
602  if (!(_res.options & RES_IGNTC) && anhp->tc)
603  {
604  /* get rest of answer; use TCP with same server.
605  */
606  Dprint (_res.options & RES_DEBUG, (";; truncated answer\n"));
607  v_circuit = 1;
608  resolve_close();
609  return (SAME_NS);
610  }
611  } /* if vcicuit / dg */
612 
613  Dprint ((_res.options & RES_DEBUG) ||
614  ((_res.pfcode & RES_PRF_REPLY) && (_res.pfcode & RES_PRF_HEAD1)),
615  (";; got answer:\n"));
616 
617  DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY),
618  (" \b"), ns_ans, resplen);
619 
620  /*
621  * If using virtual circuits (TCP), we assume that the first server
622  * is preferred over the rest (i.e. it is on the local machine) and
623  * only keep that one open. If we have temporarily opened a virtual
624  * circuit, or if we haven't been asked to keep a socket open,
625  * close the socket.
626  */
627  if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
628  !(_res.options & RES_STAYOPEN))
629  resolve_close();
630 
631  if (Rhook)
632  {
633  int done = 0, loops = 0;
634 
635  do
636  {
637  res_sendhookact act = (*Rhook) (nsap, ns_buf, ns_buflen,
638  ns_ans, ns_anssiz, &resplen);
639  switch (act)
640  {
641  case res_goahead:
642  case res_done:
643  done = 1;
644  break;
645  case res_nextns:
646  resolve_close();
647  return (NEXT_NS);
648  case res_modified:
649  /* give the hook another try */
650  if (++loops < 42)
651  break;
652  /* fallthrough */
653  case res_error:
654  /* fallthrough */
655  default:
656  return (-1);
657  }
658  }
659  while (!done);
660  }
661  return (resplen);
662 }
663 
664 /*
665  * This routine is for closing the socket if a virtual circuit is used and
666  * the program wants to close it. This provides support for endhostent()
667  * which expects to close the socket.
668  *
669  * This routine is not expected to be user visible.
670  */
671 static void resolve_close (void)
672 {
673  if (sock)
674  {
675  sock_close (sock);
676 
677  if (sock->tcp.ip_type == TCP_PROTO &&
678  sock->tcp.state < tcp_StateCLOSED)
679  TCP_ABORT (&sock->tcp);
680 
681  free (sock);
682  sock = NULL;
683  connected = 0;
684  vc = 0;
685  }
686 }
687 #endif /* USE_BIND */
688 
int W32_CALL tcp_open(_tcp_Socket *s, WORD lport, DWORD ip, WORD rport, ProtoHandler handler)
Actively open a TCP connection.
Definition: pctcp.c:308
int W32_CALL udp_open(_udp_Socket *s, WORD lport, DWORD ip, WORD port, ProtoHandler handler)
UDP active open.
Definition: pctcp.c:192
int W32_CALL sock_close(sock_type *s)
Close a UDP/TCP socket.
Definition: pctcp.c:3139
int W32_CALL sock_write(sock_type *s, const BYTE *data, int len)
Writes data and returns length written.
Definition: pctcp.c:2960
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
static int tcp_read(_tcp_Socket *s, BYTE *buf, int maxlen)
Read from a TCP socket.
Definition: pctcp.c:1828
int W32_CALL sock_fastread(sock_type *s, BYTE *buf, int len)
Read a socket with maximum 'len' bytes.
Definition: pctcp.c:2931
static int udp_read(_udp_Socket *s, BYTE *buf, int maxlen)
Read from UDP socket.
Definition: pctcp.c:1571
BOOL W32_CALL chk_timeout(DWORD value)
Check if milli-sec value has expired:
Definition: timer.c:547