Updated to fedora-glibc-20080524T2218
[kopensolaris-gnu/glibc.git] / resolv / res_send.c
1 /*
2  * Copyright (c) 1985, 1989, 1993
3  *    The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  */
49
50 /*
51  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
52  *
53  * Permission to use, copy, modify, and distribute this software for any
54  * purpose with or without fee is hereby granted, provided that the above
55  * copyright notice and this permission notice appear in all copies.
56  *
57  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64  * SOFTWARE.
65  */
66
67 #if defined(LIBC_SCCS) && !defined(lint)
68 static const char sccsid[] = "@(#)res_send.c    8.1 (Berkeley) 6/4/93";
69 static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixie Exp $";
70 #endif /* LIBC_SCCS and not lint */
71
72 /*
73  * Send query to name server and wait for reply.
74  */
75
76 #include <assert.h>
77 #include <sys/types.h>
78 #include <sys/param.h>
79 #include <sys/time.h>
80 #include <sys/socket.h>
81 #include <sys/uio.h>
82 #include <sys/poll.h>
83
84 #include <netinet/in.h>
85 #include <arpa/nameser.h>
86 #include <arpa/inet.h>
87 #include <sys/ioctl.h>
88
89 #include <errno.h>
90 #include <fcntl.h>
91 #include <netdb.h>
92 #include <resolv.h>
93 #include <signal.h>
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <unistd.h>
98
99 #if PACKETSZ > 65536
100 #define MAXPACKET       PACKETSZ
101 #else
102 #define MAXPACKET       65536
103 #endif
104
105
106 /* From ev_streams.c.  */
107
108 static inline void
109 __attribute ((always_inline))
110 evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
111         memset(vec, 0xf5, sizeof (*vec));
112         vec->iov_base = buf;
113         vec->iov_len = cnt;
114 }
115
116 /* From ev_timers.c.  */
117
118 #define BILLION 1000000000
119
120 static inline void
121 evConsTime(struct timespec *res, time_t sec, long nsec) {
122         res->tv_sec = sec;
123         res->tv_nsec = nsec;
124 }
125
126 static inline void
127 evAddTime(struct timespec *res, const struct timespec *addend1,
128           const struct timespec *addend2) {
129         res->tv_sec = addend1->tv_sec + addend2->tv_sec;
130         res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
131         if (res->tv_nsec >= BILLION) {
132                 res->tv_sec++;
133                 res->tv_nsec -= BILLION;
134         }
135 }
136
137 static inline void
138 evSubTime(struct timespec *res, const struct timespec *minuend,
139           const struct timespec *subtrahend) {
140        res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
141         if (minuend->tv_nsec >= subtrahend->tv_nsec)
142                 res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
143         else {
144                 res->tv_nsec = (BILLION
145                                 - subtrahend->tv_nsec + minuend->tv_nsec);
146                 res->tv_sec--;
147         }
148 }
149
150 static inline int
151 evCmpTime(struct timespec a, struct timespec b) {
152         long x = a.tv_sec - b.tv_sec;
153
154         if (x == 0L)
155                 x = a.tv_nsec - b.tv_nsec;
156         return (x < 0L ? (-1) : x > 0L ? (1) : (0));
157 }
158
159 static inline void
160 evNowTime(struct timespec *res) {
161         struct timeval now;
162
163         if (gettimeofday(&now, NULL) < 0)
164                 evConsTime(res, 0, 0);
165         else
166                 TIMEVAL_TO_TIMESPEC (&now, res);
167 }
168
169
170 /* Options.  Leave them on. */
171 /* #undef DEBUG */
172 #include "res_debug.h"
173
174 #define EXT(res) ((res)->_u._ext)
175
176 /* Forward. */
177
178 static int              send_vc(res_state, const u_char *, int,
179                                 const u_char *, int,
180                                 u_char **, int *, int *, int, u_char **,
181                                 u_char **, int *, int *);
182 static int              send_dg(res_state, const u_char *, int,
183                                 const u_char *, int,
184                                 u_char **, int *, int *, int,
185                                 int *, int *, u_char **,
186                                 u_char **, int *, int *);
187 #ifdef DEBUG
188 static void             Aerror(const res_state, FILE *, const char *, int,
189                                const struct sockaddr *);
190 static void             Perror(const res_state, FILE *, const char *, int);
191 #endif
192 static int              sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
193
194 /* Reachover. */
195
196 static void convaddr4to6(struct sockaddr_in6 *sa);
197 void res_pquery(const res_state, const u_char *, int, FILE *);
198
199 /* Public. */
200
201 /* int
202  * res_isourserver(ina)
203  *      looks up "ina" in _res.ns_addr_list[]
204  * returns:
205  *      0  : not found
206  *      >0 : found
207  * author:
208  *      paul vixie, 29may94
209  */
210 int
211 res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
212 {
213         int ns;
214
215         if (inp->sin6_family == AF_INET) {
216             struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
217             in_port_t port = in4p->sin_port;
218             in_addr_t addr = in4p->sin_addr.s_addr;
219
220             for (ns = 0;  ns < MAXNS;  ns++) {
221                 const struct sockaddr_in *srv =
222                     (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
223
224                 if ((srv != NULL) && (srv->sin_family == AF_INET) &&
225                     (srv->sin_port == port) &&
226                     (srv->sin_addr.s_addr == INADDR_ANY ||
227                      srv->sin_addr.s_addr == addr))
228                     return (1);
229             }
230         } else if (inp->sin6_family == AF_INET6) {
231             for (ns = 0;  ns < MAXNS;  ns++) {
232                 const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
233                 if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
234                     (srv->sin6_port == inp->sin6_port) &&
235                     !(memcmp(&srv->sin6_addr, &in6addr_any,
236                              sizeof (struct in6_addr)) &&
237                       memcmp(&srv->sin6_addr, &inp->sin6_addr,
238                              sizeof (struct in6_addr))))
239                     return (1);
240             }
241         }
242         return (0);
243 }
244
245 /* int
246  * res_nameinquery(name, type, class, buf, eom)
247  *      look for (name,type,class) in the query section of packet (buf,eom)
248  * requires:
249  *      buf + HFIXEDSZ <= eom
250  * returns:
251  *      -1 : format error
252  *      0  : not found
253  *      >0 : found
254  * author:
255  *      paul vixie, 29may94
256  */
257 int
258 res_nameinquery(const char *name, int type, int class,
259                 const u_char *buf, const u_char *eom)
260 {
261         const u_char *cp = buf + HFIXEDSZ;
262         int qdcount = ntohs(((HEADER*)buf)->qdcount);
263
264         while (qdcount-- > 0) {
265                 char tname[MAXDNAME+1];
266                 int n, ttype, tclass;
267
268                 n = dn_expand(buf, eom, cp, tname, sizeof tname);
269                 if (n < 0)
270                         return (-1);
271                 cp += n;
272                 if (cp + 2 * INT16SZ > eom)
273                         return (-1);
274                 NS_GET16(ttype, cp);
275                 NS_GET16(tclass, cp);
276                 if (ttype == type && tclass == class &&
277                     ns_samename(tname, name) == 1)
278                         return (1);
279         }
280         return (0);
281 }
282 libresolv_hidden_def (res_nameinquery)
283
284 /* int
285  * res_queriesmatch(buf1, eom1, buf2, eom2)
286  *      is there a 1:1 mapping of (name,type,class)
287  *      in (buf1,eom1) and (buf2,eom2)?
288  * returns:
289  *      -1 : format error
290  *      0  : not a 1:1 mapping
291  *      >0 : is a 1:1 mapping
292  * author:
293  *      paul vixie, 29may94
294  */
295 int
296 res_queriesmatch(const u_char *buf1, const u_char *eom1,
297                  const u_char *buf2, const u_char *eom2)
298 {
299         if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
300                 return (-1);
301
302         /*
303          * Only header section present in replies to
304          * dynamic update packets.
305          */
306         if ((((HEADER *)buf1)->opcode == ns_o_update) &&
307             (((HEADER *)buf2)->opcode == ns_o_update))
308                 return (1);
309
310         /* Note that we initially do not convert QDCOUNT to the host byte
311            order.  We can compare it with the second buffer's QDCOUNT
312            value without doing this.  */
313         int qdcount = ((HEADER*)buf1)->qdcount;
314         if (qdcount != ((HEADER*)buf2)->qdcount)
315                 return (0);
316
317         qdcount = htons (qdcount);
318         const u_char *cp = buf1 + HFIXEDSZ;
319
320         while (qdcount-- > 0) {
321                 char tname[MAXDNAME+1];
322                 int n, ttype, tclass;
323
324                 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
325                 if (n < 0)
326                         return (-1);
327                 cp += n;
328                 if (cp + 2 * INT16SZ > eom1)
329                         return (-1);
330                 NS_GET16(ttype, cp);
331                 NS_GET16(tclass, cp);
332                 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
333                         return (0);
334         }
335         return (1);
336 }
337 libresolv_hidden_def (res_queriesmatch)
338
339 int
340 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
341                  const u_char *buf2, int buflen2,
342                  u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
343                  int *nansp2)
344 {
345   int gotsomewhere, terrno, try, v_circuit, resplen, resplen2, ns, n;
346
347         if (statp->nscount == 0) {
348                 __set_errno (ESRCH);
349                 return (-1);
350         }
351
352         if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
353                 __set_errno (EINVAL);
354                 return (-1);
355         }
356
357 #ifdef USE_HOOKS
358         if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
359                 if (anssiz < MAXPACKET && ansp) {
360                         u_char *buf = malloc (MAXPACKET);
361                         if (buf == NULL)
362                                 return (-1);
363                         memcpy (buf, ans, HFIXEDSZ);
364                         *ansp = buf;
365                         ans = buf;
366                         anssiz = MAXPACKET;
367                 }
368         }
369 #endif
370
371         DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
372                 (stdout, ";; res_send()\n"), buf, buflen);
373         v_circuit = ((statp->options & RES_USEVC)
374                      || buflen > PACKETSZ
375                      || buflen2 > PACKETSZ);
376         gotsomewhere = 0;
377         terrno = ETIMEDOUT;
378
379         /*
380          * If the ns_addr_list in the resolver context has changed, then
381          * invalidate our cached copy and the associated timing data.
382          */
383         if (EXT(statp).nsinit) {
384                 int needclose = 0;
385
386                 if (EXT(statp).nscount != statp->nscount)
387                         needclose++;
388                 else
389                         for (ns = 0; ns < MAXNS; ns++) {
390                                 unsigned int map = EXT(statp).nsmap[ns];
391                                 if (map < MAXNS
392                                     && !sock_eq((struct sockaddr_in6 *)
393                                                 &statp->nsaddr_list[map],
394                                                 EXT(statp).nsaddrs[ns]))
395                                 {
396                                         needclose++;
397                                         break;
398                                 }
399                         }
400                 if (needclose)
401                         __res_iclose(statp, false);
402         }
403
404         /*
405          * Maybe initialize our private copy of the ns_addr_list.
406          */
407         if (EXT(statp).nsinit == 0) {
408                 unsigned char map[MAXNS];
409
410                 memset (map, MAXNS, sizeof (map));
411                 for (n = 0; n < MAXNS; n++) {
412                         ns = EXT(statp).nsmap[n];
413                         if (ns < statp->nscount)
414                                 map[ns] = n;
415                         else if (ns < MAXNS) {
416                                 free(EXT(statp).nsaddrs[n]);
417                                 EXT(statp).nsaddrs[n] = NULL;
418                                 EXT(statp).nsmap[n] = MAXNS;
419                         }
420                 }
421                 n = statp->nscount;
422                 if (statp->nscount > EXT(statp).nscount)
423                         for (n = EXT(statp).nscount, ns = 0;
424                              n < statp->nscount; n++) {
425                                 while (ns < MAXNS
426                                        && EXT(statp).nsmap[ns] != MAXNS)
427                                         ns++;
428                                 if (ns == MAXNS)
429                                         break;
430                                 EXT(statp).nsmap[ns] = n;
431                                 map[n] = ns++;
432                         }
433                 EXT(statp).nscount = n;
434                 for (ns = 0; ns < EXT(statp).nscount; ns++) {
435                         n = map[ns];
436                         if (EXT(statp).nsaddrs[n] == NULL)
437                                 EXT(statp).nsaddrs[n] =
438                                     malloc(sizeof (struct sockaddr_in6));
439                         if (EXT(statp).nsaddrs[n] != NULL) {
440                                 memset (mempcpy(EXT(statp).nsaddrs[n],
441                                                 &statp->nsaddr_list[ns],
442                                                 sizeof (struct sockaddr_in)),
443                                         '\0',
444                                         sizeof (struct sockaddr_in6)
445                                         - sizeof (struct sockaddr_in));
446                                 EXT(statp).nssocks[n] = -1;
447                                 n++;
448                         }
449                 }
450                 EXT(statp).nsinit = 1;
451         }
452
453         /*
454          * Some resolvers want to even out the load on their nameservers.
455          * Note that RES_BLAST overrides RES_ROTATE.
456          */
457         if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
458             (statp->options & RES_BLAST) == 0) {
459                 struct sockaddr_in6 *ina;
460                 unsigned int map;
461
462                 n = 0;
463                 while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
464                         n++;
465                 if (n < MAXNS) {
466                         ina = EXT(statp).nsaddrs[n];
467                         map = EXT(statp).nsmap[n];
468                         for (;;) {
469                                 ns = n + 1;
470                                 while (ns < MAXNS
471                                        && EXT(statp).nsmap[ns] == MAXNS)
472                                         ns++;
473                                 if (ns == MAXNS)
474                                         break;
475                                 EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
476                                 EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
477                                 n = ns;
478                         }
479                         EXT(statp).nsaddrs[n] = ina;
480                         EXT(statp).nsmap[n] = map;
481                 }
482         }
483
484         /*
485          * Send request, RETRY times, or until successful.
486          */
487         for (try = 0; try < statp->retry; try++) {
488             for (ns = 0; ns < MAXNS; ns++)
489             {
490                 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
491
492                 if (nsap == NULL)
493                         goto next_ns;
494             same_ns:
495 #ifdef USE_HOOKS
496                 if (__builtin_expect (statp->qhook != NULL, 0)) {
497                         int done = 0, loops = 0;
498
499                         do {
500                                 res_sendhookact act;
501
502                                 struct sockaddr_in *nsap4;
503                                 nsap4 = (struct sockaddr_in *) nsap;
504                                 act = (*statp->qhook)(&nsap4, &buf, &buflen,
505                                                       ans, anssiz, &resplen);
506                                 nsap = (struct sockaddr_in6 *) nsap4;
507                                 switch (act) {
508                                 case res_goahead:
509                                         done = 1;
510                                         break;
511                                 case res_nextns:
512                                         __res_iclose(statp, false);
513                                         goto next_ns;
514                                 case res_done:
515                                         return (resplen);
516                                 case res_modified:
517                                         /* give the hook another try */
518                                         if (++loops < 42) /*doug adams*/
519                                                 break;
520                                         /*FALLTHROUGH*/
521                                 case res_error:
522                                         /*FALLTHROUGH*/
523                                 default:
524                                         return (-1);
525                                 }
526                         } while (!done);
527                 }
528 #endif
529
530 #ifdef DEBUG
531                 char tmpbuf[40];
532 #endif
533                 Dprint(statp->options & RES_DEBUG,
534                        (stdout, ";; Querying server (# %d) address = %s\n",
535                         ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
536                                           tmpbuf, sizeof (tmpbuf))));
537
538                 if (__builtin_expect (v_circuit, 0)) {
539                         /* Use VC; at most one attempt per server. */
540                         try = statp->retry;
541                         n = send_vc(statp, buf, buflen, buf2, buflen2,
542                                     &ans, &anssiz, &terrno,
543                                     ns, ansp, ansp2, nansp2, &resplen2);
544                         if (n < 0)
545                                 return (-1);
546                         if (n == 0)
547                                 goto next_ns;
548                 } else {
549                         /* Use datagrams. */
550                         n = send_dg(statp, buf, buflen, buf2, buflen2,
551                                     &ans, &anssiz, &terrno,
552                                     ns, &v_circuit, &gotsomewhere, ansp,
553                                     ansp2, nansp2, &resplen2);
554                         if (n < 0)
555                                 return (-1);
556                         if (n == 0)
557                                 goto next_ns;
558                         if (v_circuit)
559                           // XXX Check whether both requests failed or
560                           // XXX whether one have been answered successfully
561                                 goto same_ns;
562                 }
563
564                 resplen = n;
565
566                 Dprint((statp->options & RES_DEBUG) ||
567                        ((statp->pfcode & RES_PRF_REPLY) &&
568                         (statp->pfcode & RES_PRF_HEAD1)),
569                        (stdout, ";; got answer:\n"));
570
571                 DprintQ((statp->options & RES_DEBUG) ||
572                         (statp->pfcode & RES_PRF_REPLY),
573                         (stdout, "%s", ""),
574                         ans, (resplen > anssiz) ? anssiz : resplen);
575                 if (buf2 != NULL)
576                   DprintQ((statp->options & RES_DEBUG) ||
577                           (statp->pfcode & RES_PRF_REPLY),
578                           (stdout, "%s", ""),
579                           *ansp2, (resplen2 > *nansp2) ? *nansp2 : resplen2);
580
581                 /*
582                  * If we have temporarily opened a virtual circuit,
583                  * or if we haven't been asked to keep a socket open,
584                  * close the socket.
585                  */
586                 if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
587                     (statp->options & RES_STAYOPEN) == 0) {
588                         __res_iclose(statp, false);
589                 }
590 #ifdef USE_HOOKS
591                 if (__builtin_expect (statp->rhook, 0)) {
592                         int done = 0, loops = 0;
593
594                         do {
595                                 res_sendhookact act;
596
597                                 act = (*statp->rhook)((struct sockaddr_in *)
598                                                       nsap, buf, buflen,
599                                                       ans, anssiz, &resplen);
600                                 switch (act) {
601                                 case res_goahead:
602                                 case res_done:
603                                         done = 1;
604                                         break;
605                                 case res_nextns:
606                                         __res_iclose(statp, false);
607                                         goto next_ns;
608                                 case res_modified:
609                                         /* give the hook another try */
610                                         if (++loops < 42) /*doug adams*/
611                                                 break;
612                                         /*FALLTHROUGH*/
613                                 case res_error:
614                                         /*FALLTHROUGH*/
615                                 default:
616                                         return (-1);
617                                 }
618                         } while (!done);
619
620                 }
621 #endif
622                 return (resplen);
623  next_ns: ;
624            } /*foreach ns*/
625         } /*foreach retry*/
626         __res_iclose(statp, false);
627         if (!v_circuit) {
628                 if (!gotsomewhere)
629                         __set_errno (ECONNREFUSED);     /* no nameservers found */
630                 else
631                         __set_errno (ETIMEDOUT);        /* no answer obtained */
632         } else
633                 __set_errno (terrno);
634         return (-1);
635 }
636
637 int
638 res_nsend(res_state statp,
639           const u_char *buf, int buflen, u_char *ans, int anssiz)
640 {
641   return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
642                           NULL, NULL, NULL);
643 }
644 libresolv_hidden_def (res_nsend)
645
646 /* Private */
647
648 static int
649 send_vc(res_state statp,
650         const u_char *buf, int buflen, const u_char *buf2, int buflen2,
651         u_char **ansp, int *anssizp,
652         int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
653         int *resplen2)
654 {
655         const HEADER *hp = (HEADER *) buf;
656         const HEADER *hp2 = (HEADER *) buf2;
657         u_char *ans = *ansp;
658         int orig_anssizp = *anssizp;
659         // XXX REMOVE
660         // int anssiz = *anssizp;
661         HEADER *anhp = (HEADER *) ans;
662         struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
663         int truncating, connreset, resplen, n;
664         struct iovec iov[4];
665         u_short len;
666         u_short len2;
667         u_char *cp;
668
669         connreset = 0;
670  same_ns:
671         truncating = 0;
672
673         /* Are we still talking to whom we want to talk to? */
674         if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
675                 struct sockaddr_in6 peer;
676                 socklen_t size = sizeof peer;
677
678                 if (getpeername(statp->_vcsock,
679                                 (struct sockaddr *)&peer, &size) < 0 ||
680                     !sock_eq(&peer, nsap)) {
681                   __res_iclose(statp, false);
682                         statp->_flags &= ~RES_F_VC;
683                 }
684         }
685
686         if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
687                 if (statp->_vcsock >= 0)
688                   __res_iclose(statp, false);
689
690                 statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
691                 if (statp->_vcsock < 0) {
692                         *terrno = errno;
693                         Perror(statp, stderr, "socket(vc)", errno);
694                         return (-1);
695                 }
696                 __set_errno (0);
697                 if (connect(statp->_vcsock, (struct sockaddr *)nsap,
698                             nsap->sin6_family == AF_INET
699                             ? sizeof (struct sockaddr_in)
700                             : sizeof (struct sockaddr_in6)) < 0) {
701                         *terrno = errno;
702                         Aerror(statp, stderr, "connect/vc", errno,
703                                (struct sockaddr *) nsap);
704                         __res_iclose(statp, false);
705                         return (0);
706                 }
707                 statp->_flags |= RES_F_VC;
708         }
709
710         /*
711          * Send length & message
712          */
713         len = htons ((u_short) buflen);
714         evConsIovec(&len, INT16SZ, &iov[0]);
715         evConsIovec((void*)buf, buflen, &iov[1]);
716         int niov = 2;
717         ssize_t explen = INT16SZ + buflen;
718         if (buf2 != NULL) {
719                 len2 = htons ((u_short) buflen2);
720                 evConsIovec(&len2, INT16SZ, &iov[2]);
721                 evConsIovec((void*)buf2, buflen2, &iov[3]);
722                 niov = 4;
723                 explen += INT16SZ + buflen2;
724         }
725         if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
726                 *terrno = errno;
727                 Perror(statp, stderr, "write failed", errno);
728                 __res_iclose(statp, false);
729                 return (0);
730         }
731         /*
732          * Receive length & response
733          */
734         int recvresp1 = 0;
735         int recvresp2 = buf2 == NULL;
736  read_len:
737         cp = ans;
738         len = INT16SZ;
739         while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, (char *)cp,
740                                              (int)len))) > 0) {
741                 cp += n;
742                 if ((len -= n) <= 0)
743                         break;
744         }
745         if (n <= 0) {
746                 *terrno = errno;
747                 Perror(statp, stderr, "read failed", errno);
748                 __res_iclose(statp, false);
749                 /*
750                  * A long running process might get its TCP
751                  * connection reset if the remote server was
752                  * restarted.  Requery the server instead of
753                  * trying a new one.  When there is only one
754                  * server, this means that a query might work
755                  * instead of failing.  We only allow one reset
756                  * per query to prevent looping.
757                  */
758                 if (*terrno == ECONNRESET && !connreset) {
759                         connreset = 1;
760                         goto same_ns;
761                 }
762                 return (0);
763         }
764 #ifdef _STRING_ARCH_unaligned
765         resplen = ntohs (*(uint16_t *) ans);
766 #else
767         resplen = ns_get16(ans);
768 #endif
769
770         int *thisanssizp;
771         u_char **thisansp;
772         int *thisresplenp;
773         if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
774                 thisanssizp = anssizp;
775                 thisansp = anscp ?: ansp;
776                 assert (anscp != NULL || ansp2 == NULL);
777                 thisresplenp = &resplen;
778         } else {
779                 if (*anssizp != MAXPACKET) {
780                         /* No buffer allocated for the first
781                            reply.  We can try to use the rest
782                            of the user-provided buffer.  */
783                         *anssizp2 = orig_anssizp - resplen;
784                         *ansp2 = *ansp + resplen;
785                 } else {
786                         /* The first reply did not fit into the
787                            user-provided buffer.  Maybe the second
788                            answer will.  */
789                         *anssizp2 = orig_anssizp;
790                         *ansp2 = *ansp;
791                 }
792
793                 thisanssizp = anssizp2;
794                 thisansp = ansp2;
795                 thisresplenp = resplen2;
796         }
797         anhp = (HEADER *) *thisansp;
798
799         *thisresplenp = resplen;
800         if (resplen > *thisanssizp) {
801                 /* Yes, we test ANSCP here.  If we have two buffers
802                    both will be allocatable.  */
803                 if (anscp) {
804                         u_char *newp = malloc (MAXPACKET);
805                         if (newp == NULL) {
806                                 *terrno = ENOMEM;
807                                 __res_iclose(statp, false);
808                                 return (0);
809                         }
810                         *thisanssizp = MAXPACKET;
811                         *thisansp = newp;
812                         anhp = (HEADER *) newp;
813                         len = resplen;
814                 } else {
815                         Dprint(statp->options & RES_DEBUG,
816                                 (stdout, ";; response truncated\n")
817                         );
818                         truncating = 1;
819                         len = *thisanssizp;
820                 }
821         } else
822                 len = resplen;
823
824         if (len < HFIXEDSZ) {
825                 /*
826                  * Undersized message.
827                  */
828                 Dprint(statp->options & RES_DEBUG,
829                        (stdout, ";; undersized: %d\n", len));
830                 *terrno = EMSGSIZE;
831                 __res_iclose(statp, false);
832                 return (0);
833         }
834
835         cp = *thisansp;
836         while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
837                 cp += n;
838                 len -= n;
839         }
840         if (n <= 0) {
841                 *terrno = errno;
842                 Perror(statp, stderr, "read(vc)", errno);
843                 __res_iclose(statp, false);
844                 return (0);
845         }
846         if (truncating) {
847                 /*
848                  * Flush rest of answer so connection stays in synch.
849                  */
850                 anhp->tc = 1;
851                 len = resplen - *thisanssizp;
852                 while (len != 0) {
853                         char junk[PACKETSZ];
854
855                         n = read(statp->_vcsock, junk,
856                                  (len > sizeof junk) ? sizeof junk : len);
857                         if (n > 0)
858                                 len -= n;
859                         else
860                                 break;
861                 }
862         }
863         /*
864          * If the calling applicating has bailed out of
865          * a previous call and failed to arrange to have
866          * the circuit closed or the server has got
867          * itself confused, then drop the packet and
868          * wait for the correct one.
869          */
870         if ((recvresp1 || hp->id != anhp->id)
871             && (recvresp2 || hp2->id != anhp->id)) {
872                 DprintQ((statp->options & RES_DEBUG) ||
873                         (statp->pfcode & RES_PRF_REPLY),
874                         (stdout, ";; old answer (unexpected):\n"),
875                         *thisansp,
876                         (resplen > *thisanssiz) ? *thisanssiz: resplen);
877                 goto read_len;
878         }
879
880         /* Mark which reply we received.  */
881         if (recvresp1 == 0 && hp->id == anhp->id)
882           recvresp1 = 1;
883         else
884           recvresp2 = 1;
885         /* Repeat waiting if we have a second answer to arrive.  */
886         if ((recvresp1 & recvresp2) == 0)
887                 goto read_len;
888
889         /*
890          * All is well, or the error is fatal.  Signal that the
891          * next nameserver ought not be tried.
892          */
893         return (resplen);
894 }
895
896 static int
897 send_dg(res_state statp,
898         const u_char *buf, int buflen, const u_char *buf2, int buflen2,
899         u_char **ansp, int *anssizp,
900         int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
901         u_char **ansp2, int *anssizp2, int *resplen2)
902 {
903         const HEADER *hp = (HEADER *) buf;
904         const HEADER *hp2 = (HEADER *) buf2;
905         u_char *ans = *ansp;
906         int orig_anssizp = *anssizp;
907         struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
908         struct timespec now, timeout, finish;
909         struct pollfd pfd[1];
910         int ptimeout;
911         struct sockaddr_in6 from;
912         int resplen, seconds, n;
913
914         if (EXT(statp).nssocks[ns] == -1) {
915                 /* only try IPv6 if IPv6 NS and if not failed before */
916                 if ((EXT(statp).nscount6 > 0) && !statp->ipv6_unavail) {
917                         EXT(statp).nssocks[ns] =
918                             socket(PF_INET6, SOCK_DGRAM, 0);
919                         if (EXT(statp).nssocks[ns] < 0)
920                             statp->ipv6_unavail = errno == EAFNOSUPPORT;
921                         /* If IPv6 socket and nsap is IPv4, make it
922                            IPv4-mapped */
923                         else if (nsap->sin6_family == AF_INET)
924                             convaddr4to6(nsap);
925                 }
926                 if (EXT(statp).nssocks[ns] < 0)
927                         EXT(statp).nssocks[ns] = socket(PF_INET, SOCK_DGRAM, 0);
928                 if (EXT(statp).nssocks[ns] < 0) {
929                         *terrno = errno;
930                         Perror(statp, stderr, "socket(dg)", errno);
931                         return (-1);
932                 }
933
934                 /*
935                  * On a 4.3BSD+ machine (client and server,
936                  * actually), sending to a nameserver datagram
937                  * port with no nameserver will cause an
938                  * ICMP port unreachable message to be returned.
939                  * If our datagram socket is "connected" to the
940                  * server, we get an ECONNREFUSED error on the next
941                  * socket operation, and select returns if the
942                  * error message is received.  We can thus detect
943                  * the absence of a nameserver without timing out.
944                  */
945                 if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap,
946                             sizeof *nsap) < 0) {
947                         Aerror(statp, stderr, "connect(dg)", errno,
948                                (struct sockaddr *) nsap);
949                         __res_iclose(statp, false);
950                         return (0);
951                 }
952                 /* Make socket non-blocking.  */
953                 int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
954                 if  (fl != -1)
955                         __fcntl (EXT(statp).nssocks[ns], F_SETFL,
956                                  fl | O_NONBLOCK);
957                 Dprint(statp->options & RES_DEBUG,
958                        (stdout, ";; new DG socket\n"))
959         }
960
961         /*
962          * Compute time for the total operation.
963          */
964         seconds = (statp->retrans << ns);
965         if (ns > 0)
966                 seconds /= statp->nscount;
967         if (seconds <= 0)
968                 seconds = 1;
969         evNowTime(&now);
970         evConsTime(&timeout, seconds, 0);
971         evAddTime(&finish, &now, &timeout);
972         int need_recompute = 0;
973         int nwritten = 0;
974         int recvresp1 = 0;
975         int recvresp2 = buf2 == NULL;
976         pfd[0].fd = EXT(statp).nssocks[ns];
977         pfd[0].events = POLLOUT;
978         if (resplen2 != NULL)
979           *resplen2 = 0;
980  wait:
981         if (need_recompute) {
982         recompute_resend:
983                 evNowTime(&now);
984                 if (evCmpTime(finish, now) <= 0) {
985                 poll_err_out:
986                         Perror(statp, stderr, "poll", errno);
987                 err_out:
988                         __res_iclose(statp, false);
989                         return (0);
990                 }
991                 evSubTime(&timeout, &finish, &now);
992         }
993         /* Convert struct timespec in milliseconds.  */
994         ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
995
996         n = 0;
997         if (nwritten == 0)
998           n = __poll (pfd, 1, 0);
999         if (__builtin_expect (n == 0, 0)) {
1000                 n = __poll (pfd, 1, ptimeout);
1001                 need_recompute = 1;
1002         }
1003         if (n == 0) {
1004                 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1005                 if (recvresp1 || (buf2 != NULL && recvresp2))
1006                   {
1007                     *resplen2 = 1;
1008                     return resplen;
1009                   }
1010
1011                 *gotsomewhere = 1;
1012                 return (0);
1013         }
1014         if (n < 0) {
1015                 if (errno == EINTR)
1016                         goto recompute_resend;
1017
1018                 goto poll_err_out;
1019         }
1020         __set_errno (0);
1021         if (pfd[0].revents & POLLOUT) {
1022                 ssize_t sr;
1023                 if (nwritten != 0)
1024                   sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
1025                 else
1026                   sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
1027
1028                 if (sr != buflen) {
1029                         if (errno == EINTR || errno == EAGAIN)
1030                                 goto recompute_resend;
1031                         Perror(statp, stderr, "send", errno);
1032                         goto err_out;
1033                 }
1034                 if (nwritten != 0 || buf2 == NULL)
1035                   pfd[0].events = POLLIN;
1036                 else
1037                   pfd[0].events = POLLIN | POLLOUT;
1038                 ++nwritten;
1039                 goto wait;
1040         } else if (pfd[0].revents & POLLIN) {
1041                 int *thisanssizp;
1042                 u_char **thisansp;
1043                 int *thisresplenp;
1044
1045                 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
1046                         thisanssizp = anssizp;
1047                         thisansp = anscp ?: ansp;
1048                         assert (anscp != NULL || ansp2 == NULL);
1049                         thisresplenp = &resplen;
1050                 } else {
1051                         if (*anssizp != MAXPACKET) {
1052                                 /* No buffer allocated for the first
1053                                    reply.  We can try to use the rest
1054                                    of the user-provided buffer.  */
1055                                 *anssizp2 = orig_anssizp - resplen;
1056                                 *ansp2 = *ansp + resplen;
1057                         } else {
1058                                 /* The first reply did not fit into the
1059                                    user-provided buffer.  Maybe the second
1060                                    answer will.  */
1061                                 *anssizp2 = orig_anssizp;
1062                                 *ansp2 = *ansp;
1063                         }
1064
1065                         thisanssizp = anssizp2;
1066                         thisansp = ansp2;
1067                         thisresplenp = resplen2;
1068                 }
1069
1070                 if (*thisanssizp < MAXPACKET
1071                     /* Yes, we test ANSCP here.  If we have two buffers
1072                        both will be allocatable.  */
1073                     && anscp
1074                     && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
1075                         || *thisanssizp < *thisresplenp)) {
1076                         u_char *newp = malloc (MAXPACKET);
1077                         if (newp != NULL) {
1078                                 *anssizp = MAXPACKET;
1079                                 *thisansp = ans = newp;
1080                         }
1081                 }
1082                 HEADER *anhp = (HEADER *) *thisansp;
1083                 socklen_t fromlen = sizeof(struct sockaddr_in6);
1084                 assert (sizeof(from) <= fromlen);
1085                 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
1086                                          *thisanssizp, 0,
1087                                         (struct sockaddr *)&from, &fromlen);
1088                 if (*thisresplenp <= 0) {
1089                         if (errno == EINTR || errno == EAGAIN) {
1090                                 need_recompute = 1;
1091                                 goto wait;
1092                         }
1093                         Perror(statp, stderr, "recvfrom", errno);
1094                         goto err_out;
1095                 }
1096                 *gotsomewhere = 1;
1097                 if (*thisresplenp < HFIXEDSZ) {
1098                         /*
1099                          * Undersized message.
1100                          */
1101                         Dprint(statp->options & RES_DEBUG,
1102                                (stdout, ";; undersized: %d\n",
1103                                 *thisresplen));
1104                         *terrno = EMSGSIZE;
1105                         goto err_out;
1106                 }
1107                 if ((recvresp1 || hp->id != anhp->id)
1108                     && (recvresp2 || hp2->id != anhp->id)) {
1109                         /*
1110                          * response from old query, ignore it.
1111                          * XXX - potential security hazard could
1112                          *       be detected here.
1113                          */
1114                         DprintQ((statp->options & RES_DEBUG) ||
1115                                 (statp->pfcode & RES_PRF_REPLY),
1116                                 (stdout, ";; old answer:\n"),
1117                                 thisansp,
1118                                 (*thisresplen > *thisanssiz)
1119                                 ? *thisanssiz : *thisresplen);
1120                         goto wait;
1121                 }
1122                 if (!(statp->options & RES_INSECURE1) &&
1123                     !res_ourserver_p(statp, &from)) {
1124                         /*
1125                          * response from wrong server? ignore it.
1126                          * XXX - potential security hazard could
1127                          *       be detected here.
1128                          */
1129                         DprintQ((statp->options & RES_DEBUG) ||
1130                                 (statp->pfcode & RES_PRF_REPLY),
1131                                 (stdout, ";; not our server:\n"),
1132                                 thisansp,
1133                                 (*thisresplen > *thisanssiz)
1134                                 ? *thisanssiz : *thisresplen);
1135                         goto wait;
1136                 }
1137 #ifdef RES_USE_EDNS0
1138                 if (anhp->rcode == FORMERR
1139                     && (statp->options & RES_USE_EDNS0) != 0U) {
1140                         /*
1141                          * Do not retry if the server does not understand
1142                          * EDNS0.  The case has to be captured here, as
1143                          * FORMERR packet do not carry query section, hence
1144                          * res_queriesmatch() returns 0.
1145                          */
1146                         DprintQ(statp->options & RES_DEBUG,
1147                                 (stdout,
1148                                  "server rejected query with EDNS0:\n"),
1149                                 thisans,
1150                                 (*thisresplen > *thisanssiz)
1151                                 ? *thisanssiz : *thisresplen);
1152                         /* record the error */
1153                         statp->_flags |= RES_F_EDNS0ERR;
1154                         goto err_out;
1155         }
1156 #endif
1157                 if (!(statp->options & RES_INSECURE2)
1158                     && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
1159                                                        *thisansp,
1160                                                        *thisansp
1161                                                        + *thisanssizp))
1162                     && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
1163                                                        *thisansp,
1164                                                        *thisansp
1165                                                        + *thisanssizp))) {
1166                         /*
1167                          * response contains wrong query? ignore it.
1168                          * XXX - potential security hazard could
1169                          *       be detected here.
1170                          */
1171                         DprintQ((statp->options & RES_DEBUG) ||
1172                                 (statp->pfcode & RES_PRF_REPLY),
1173                                 (stdout, ";; wrong query name:\n"),
1174                                 thisansp,
1175                                 (*thisresplen > *thisanssiz)
1176                                 ? *thisanssiz : *thisresplen);
1177                         goto wait;
1178                 }
1179                 if (anhp->rcode == SERVFAIL ||
1180                     anhp->rcode == NOTIMP ||
1181                     anhp->rcode == REFUSED) {
1182                         DprintQ(statp->options & RES_DEBUG,
1183                                 (stdout, "server rejected query:\n"),
1184                                 thisansp,
1185                                 (*thisresplen > *thisanssiz)
1186                                 ? *thisanssiz : *thisresplen);
1187
1188                         if (recvresp1 || (buf2 != NULL && recvresp2))
1189                           {
1190                             *resplen2 = 1;
1191                             return resplen;
1192                           }
1193                         if (buf2 != NULL)
1194                           {
1195                             /* We are waiting for a possible second reply.  */
1196                             resplen = 1;
1197                             if (hp->id == anhp->id)
1198                               recvresp1 = 1;
1199                             else
1200                               recvresp2 = 1;
1201
1202                             goto wait;
1203                           }
1204
1205                 next_ns:
1206                         __res_iclose(statp, false);
1207                         /* don't retry if called from dig */
1208                         if (!statp->pfcode)
1209                                 return (0);
1210                 }
1211                 if (anhp->rcode == NOERROR && anhp->ancount == 0
1212                     && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
1213                         DprintQ(statp->options & RES_DEBUG,
1214                                 (stdout, "referred query:\n"),
1215                                 thisansp,
1216                                 (*thisresplen > *thisanssiz)
1217                                 ? *thisanssiz : *thisresplen);
1218                         goto next_ns;
1219                 }
1220                 if (!(statp->options & RES_IGNTC) && anhp->tc) {
1221                         /*
1222                          * To get the rest of answer,
1223                          * use TCP with same server.
1224                          */
1225                         Dprint(statp->options & RES_DEBUG,
1226                                (stdout, ";; truncated answer\n"));
1227                         *v_circuit = 1;
1228                         __res_iclose(statp, false);
1229                         // XXX if we have received one reply we could
1230                         // XXX use it and not repeat it over TCP...
1231                         return (1);
1232                 }
1233                 /* Mark which reply we received.  */
1234                 if (recvresp1 == 0 && hp->id == anhp->id)
1235                         recvresp1 = 1;
1236                 else
1237                         recvresp2 = 1;
1238                 /* Repeat waiting if we have a second answer to arrive.  */
1239                 if ((recvresp1 & recvresp2) == 0)
1240                         goto wait;
1241                 /*
1242                  * All is well, or the error is fatal.  Signal that the
1243                  * next nameserver ought not be tried.
1244                  */
1245                 return (resplen);
1246         } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1247                 /* Something went wrong.  We can stop trying.  */
1248                 goto err_out;
1249         }
1250         else {
1251                 /* poll should not have returned > 0 in this case.  */
1252                 abort ();
1253         }
1254 }
1255
1256 #ifdef DEBUG
1257 static void
1258 Aerror(const res_state statp, FILE *file, const char *string, int error,
1259        const struct sockaddr *address)
1260 {
1261         int save = errno;
1262
1263         if ((statp->options & RES_DEBUG) != 0) {
1264                 char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
1265
1266                 fprintf(file, "res_send: %s ([%s].%u): %s\n",
1267                         string,
1268                         (address->sa_family == AF_INET
1269                          ? inet_ntop(address->sa_family,
1270                                      &((const struct sockaddr_in *) address)->sin_addr,
1271                                      tmp, sizeof tmp)
1272                          : inet_ntop(address->sa_family,
1273                                      &((const struct sockaddr_in6 *) address)->sin6_addr,
1274                                      tmp, sizeof tmp)),
1275                         (address->sa_family == AF_INET
1276                          ? ntohs(((struct sockaddr_in *) address)->sin_port)
1277                          : address->sa_family == AF_INET6
1278                          ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
1279                          : 0),
1280                         strerror(error));
1281         }
1282         __set_errno (save);
1283 }
1284
1285 static void
1286 Perror(const res_state statp, FILE *file, const char *string, int error) {
1287         int save = errno;
1288
1289         if ((statp->options & RES_DEBUG) != 0)
1290                 fprintf(file, "res_send: %s: %s\n",
1291                         string, strerror(error));
1292         __set_errno (save);
1293 }
1294 #endif
1295
1296 static int
1297 sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
1298         if (a1->sin6_family == a2->sin6_family) {
1299                 if (a1->sin6_family == AF_INET)
1300                         return ((((struct sockaddr_in *)a1)->sin_port ==
1301                                  ((struct sockaddr_in *)a2)->sin_port) &&
1302                                 (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
1303                                  ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1304                 else
1305                         return ((a1->sin6_port == a2->sin6_port) &&
1306                                 !memcmp(&a1->sin6_addr, &a2->sin6_addr,
1307                                         sizeof (struct in6_addr)));
1308         }
1309         if (a1->sin6_family == AF_INET) {
1310                 struct sockaddr_in6 *sap = a1;
1311                 a1 = a2;
1312                 a2 = sap;
1313         } /* assumes that AF_INET and AF_INET6 are the only possibilities */
1314         return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
1315                 IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
1316                 (a1->sin6_addr.s6_addr32[3] ==
1317                  ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1318 }
1319
1320 /*
1321  * Converts IPv4 family, address and port to
1322  * IPv6 family, IPv4-mapped IPv6 address and port.
1323  */
1324 static void
1325 convaddr4to6(struct sockaddr_in6 *sa)
1326 {
1327     struct sockaddr_in *sa4p = (struct sockaddr_in *) sa;
1328     in_port_t port = sa4p->sin_port;
1329     in_addr_t addr = sa4p->sin_addr.s_addr;
1330
1331     sa->sin6_family = AF_INET6;
1332     sa->sin6_port = port;
1333     sa->sin6_addr.s6_addr32[0] = 0;
1334     sa->sin6_addr.s6_addr32[1] = 0;
1335     sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
1336     sa->sin6_addr.s6_addr32[3] = addr;
1337 }