source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/res_send.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 29.2 KB
Line 
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)
68static const char sccsid[] = "@(#)res_send.c    8.1 (Berkeley) 6/4/93";
69static 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#define s6_addr32 __u6_addr.__u6_addr32
73/*
74 * Send query to name server and wait for reply.
75 */
76
77#include <assert.h>
78#include <sys/types.h>
79#include <sys/param.h>
80#include <sys/time.h>
81#include <sys/socket.h>
82#include <sys/uio.h>
83#include <sys/poll.h>
84
85#include <netinet/in.h>
86#include <arpa/nameser.h>
87#include <arpa/inet.h>
88#include <sys/ioctl.h>
89
90#include <errno.h>
91#include <fcntl.h>
92#include <netdb.h>
93#include <resolv.h>
94#include <signal.h>
95#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <unistd.h>
99#include "libc-symbols.h"
100
101#if PACKETSZ > 65536
102#define MAXPACKET       PACKETSZ
103#else
104#define MAXPACKET       65536
105#endif
106
107
108/* From ev_streams.c.  */
109
110static inline void
111__attribute ((always_inline))
112evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
113        memset(vec, 0xf5, sizeof (*vec));
114        vec->iov_base = buf;
115        vec->iov_len = cnt;
116}
117
118/* From ev_timers.c.  */
119
120#define BILLION 1000000000
121
122static inline void
123evConsTime(struct timespec *res, time_t sec, long nsec) {
124        res->tv_sec = sec;
125        res->tv_nsec = nsec;
126}
127
128static inline void
129evAddTime(struct timespec *res, const struct timespec *addend1,
130          const struct timespec *addend2) {
131        res->tv_sec = addend1->tv_sec + addend2->tv_sec;
132        res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
133        if (res->tv_nsec >= BILLION) {
134                res->tv_sec++;
135                res->tv_nsec -= BILLION;
136        }
137}
138
139static inline void
140evSubTime(struct timespec *res, const struct timespec *minuend,
141          const struct timespec *subtrahend) {
142       res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
143        if (minuend->tv_nsec >= subtrahend->tv_nsec)
144                res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
145        else {
146                res->tv_nsec = (BILLION
147                                - subtrahend->tv_nsec + minuend->tv_nsec);
148                res->tv_sec--;
149        }
150}
151
152static inline int
153evCmpTime(struct timespec a, struct timespec b) {
154        long x = a.tv_sec - b.tv_sec;
155
156        if (x == 0L)
157                x = a.tv_nsec - b.tv_nsec;
158        return (x < 0L ? (-1) : x > 0L ? (1) : (0));
159}
160
161static inline void
162evNowTime(struct timespec *res) {
163        struct timeval now;
164
165        if (gettimeofday(&now, NULL) < 0)
166                evConsTime(res, 0, 0);
167        else
168                TIMEVAL_TO_TIMESPEC (&now, res);
169}
170
171
172/* Options.  Leave them on. */
173/* #undef DEBUG */
174#include "res_debug.h"
175
176#define EXT(res) ((res)->_u._ext)
177
178/* Forward. */
179
180static int              send_vc(res_state, const u_char *, int,
181                                u_char **, int *, int *, int, u_char **);
182static int              send_dg(res_state, const u_char *, int,
183                                u_char **, int *, int *, int,
184                                int *, int *, u_char **);
185#ifdef DEBUG
186static void             Aerror(const res_state, FILE *, const char *, int,
187                               const struct sockaddr *);
188static void             Perror(const res_state, FILE *, const char *, int);
189#endif
190static int              sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
191
192/* Reachover. */
193
194static void convaddr4to6(struct sockaddr_in6 *sa);
195void res_pquery(const res_state, const u_char *, int, FILE *);
196
197/* Public. */
198
199/* int
200 * res_isourserver(ina)
201 *      looks up "ina" in _res.ns_addr_list[]
202 * returns:
203 *      0  : not found
204 *      >0 : found
205 * author:
206 *      paul vixie, 29may94
207 */
208int
209res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
210{
211        int ns;
212
213        if (inp->sin6_family == AF_INET) {
214            struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
215            in_port_t port = in4p->sin_port;
216            in_addr_t addr = in4p->sin_addr.s_addr;
217
218            for (ns = 0;  ns < MAXNS;  ns++) {
219                const struct sockaddr_in *srv =
220                    (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
221
222                if ((srv != NULL) && (srv->sin_family == AF_INET) &&
223                    (srv->sin_port == port) &&
224                    (srv->sin_addr.s_addr == INADDR_ANY ||
225                     srv->sin_addr.s_addr == addr))
226                    return (1);
227            }
228        } else if (inp->sin6_family == AF_INET6) {
229            for (ns = 0;  ns < MAXNS;  ns++) {
230                const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
231                if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
232                    (srv->sin6_port == inp->sin6_port) &&
233                    !(memcmp(&srv->sin6_addr, &in6addr_any,
234                             sizeof (struct in6_addr)) &&
235                      memcmp(&srv->sin6_addr, &inp->sin6_addr,
236                             sizeof (struct in6_addr))))
237                    return (1);
238            }
239        }
240        return (0);
241}
242
243/* int
244 * res_nameinquery(name, type, class, buf, eom)
245 *      look for (name,type,class) in the query section of packet (buf,eom)
246 * requires:
247 *      buf + HFIXEDSZ <= eom
248 * returns:
249 *      -1 : format error
250 *      0  : not found
251 *      >0 : found
252 * author:
253 *      paul vixie, 29may94
254 */
255int
256res_nameinquery(const char *name, int type, int class,
257                const u_char *buf, const u_char *eom)
258{
259        const u_char *cp = buf + HFIXEDSZ;
260        int qdcount = ntohs(((HEADER*)buf)->qdcount);
261
262        while (qdcount-- > 0) {
263                char tname[MAXDNAME+1];
264                int n, ttype, tclass;
265
266                n = dn_expand(buf, eom, cp, tname, sizeof tname);
267                if (n < 0)
268                        return (-1);
269                cp += n;
270                if (cp + 2 * INT16SZ > eom)
271                        return (-1);
272                ttype = ns_get16(cp); cp += INT16SZ;
273                tclass = ns_get16(cp); cp += INT16SZ;
274                if (ttype == type && tclass == class &&
275                    ns_samename(tname, name) == 1)
276                        return (1);
277        }
278        return (0);
279}
280libresolv_hidden_def (res_nameinquery)
281
282/* int
283 * res_queriesmatch(buf1, eom1, buf2, eom2)
284 *      is there a 1:1 mapping of (name,type,class)
285 *      in (buf1,eom1) and (buf2,eom2)?
286 * returns:
287 *      -1 : format error
288 *      0  : not a 1:1 mapping
289 *      >0 : is a 1:1 mapping
290 * author:
291 *      paul vixie, 29may94
292 */
293int
294res_queriesmatch(const u_char *buf1, const u_char *eom1,
295                 const u_char *buf2, const u_char *eom2)
296{
297        const u_char *cp = buf1 + HFIXEDSZ;
298        int qdcount = ntohs(((HEADER*)buf1)->qdcount);
299
300        if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
301                return (-1);
302
303        /*
304         * Only header section present in replies to
305         * dynamic update packets.
306         */
307        if ((((HEADER *)buf1)->opcode == ns_o_update) &&
308            (((HEADER *)buf2)->opcode == ns_o_update))
309                return (1);
310
311        if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
312                return (0);
313        while (qdcount-- > 0) {
314                char tname[MAXDNAME+1];
315                int n, ttype, tclass;
316
317                n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
318                if (n < 0)
319                        return (-1);
320                cp += n;
321                if (cp + 2 * INT16SZ > eom1)
322                        return (-1);
323                ttype = ns_get16(cp);   cp += INT16SZ;
324                tclass = ns_get16(cp); cp += INT16SZ;
325                if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
326                        return (0);
327        }
328        return (1);
329}
330libresolv_hidden_def (res_queriesmatch)
331
332int
333__libc_res_nsend(res_state statp, const u_char *buf, int buflen,
334                 u_char *ans, int anssiz, u_char **ansp)
335{
336        int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
337
338        if (statp->nscount == 0) {
339                __set_errno (ESRCH);
340                return (-1);
341        }
342
343        if (anssiz < HFIXEDSZ) {
344                __set_errno (EINVAL);
345                return (-1);
346        }
347
348        if ((statp->qhook || statp->rhook) && anssiz < MAXPACKET && ansp) {
349                u_char *buf = malloc (MAXPACKET);
350                if (buf == NULL)
351                        return (-1);
352                memcpy (buf, ans, HFIXEDSZ);
353                *ansp = buf;
354                ans = buf;
355                anssiz = MAXPACKET;
356        }
357
358        DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
359                (stdout, ";; res_send()\n"), buf, buflen);
360        v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
361        gotsomewhere = 0;
362        terrno = ETIMEDOUT;
363
364        /*
365         * If the ns_addr_list in the resolver context has changed, then
366         * invalidate our cached copy and the associated timing data.
367         */
368        if (EXT(statp).nsinit) {
369                int needclose = 0;
370
371                if (EXT(statp).nscount != statp->nscount)
372                        needclose++;
373                else
374                        for (ns = 0; ns < MAXNS; ns++) {
375                                unsigned int map = EXT(statp).nsmap[ns];
376                                if (map < MAXNS
377                                    && !sock_eq((struct sockaddr_in6 *)
378                                                &statp->nsaddr_list[map],
379                                                EXT(statp).nsaddrs[ns]))
380                                {
381                                        needclose++;
382                                        break;
383                                }
384                        }
385                if (needclose)
386                        res_nclose(statp);
387        }
388
389        /*
390         * Maybe initialize our private copy of the ns_addr_list.
391         */
392        if (EXT(statp).nsinit == 0) {
393                unsigned char map[MAXNS];
394
395                memset (map, MAXNS, sizeof (map));
396                for (n = 0; n < MAXNS; n++) {
397                        ns = EXT(statp).nsmap[n];
398                        if (ns < statp->nscount)
399                                map[ns] = n;
400                        else if (ns < MAXNS) {
401                                free(EXT(statp).nsaddrs[n]);
402                                EXT(statp).nsaddrs[n] = NULL;
403                                EXT(statp).nsmap[n] = MAXNS;
404                        }
405                }
406                n = statp->nscount;
407                if (statp->nscount > EXT(statp).nscount)
408                        for (n = EXT(statp).nscount, ns = 0;
409                             n < statp->nscount; n++) {
410                                while (ns < MAXNS
411                                       && EXT(statp).nsmap[ns] != MAXNS)
412                                        ns++;
413                                if (ns == MAXNS)
414                                        break;
415                                EXT(statp).nsmap[ns] = n;
416                                map[n] = ns++;
417                        }
418                EXT(statp).nscount = n;
419                for (ns = 0; ns < EXT(statp).nscount; ns++) {
420                        n = map[ns];
421                        if (EXT(statp).nsaddrs[n] == NULL)
422                                EXT(statp).nsaddrs[n] =
423                                    malloc(sizeof (struct sockaddr_in6));
424                        if (EXT(statp).nsaddrs[n] != NULL) {
425                                memcpy(EXT(statp).nsaddrs[n],
426                                       &statp->nsaddr_list[ns],
427                                       sizeof (struct sockaddr_in));
428                                EXT(statp).nssocks[n] = -1;
429                                n++;
430                        }
431                }
432                EXT(statp).nsinit = 1;
433        }
434
435        /*
436         * Some resolvers want to even out the load on their nameservers.
437         * Note that RES_BLAST overrides RES_ROTATE.
438         */
439        if ((statp->options & RES_ROTATE) != 0 &&
440            (statp->options & RES_BLAST) == 0) {
441                struct sockaddr_in6 *ina;
442                unsigned int map;
443
444                n = 0;
445                while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
446                        n++;
447                if (n < MAXNS) {
448                        ina = EXT(statp).nsaddrs[n];
449                        map = EXT(statp).nsmap[n];
450                        for (;;) {
451                                ns = n + 1;
452                                while (ns < MAXNS
453                                       && EXT(statp).nsmap[ns] == MAXNS)
454                                        ns++;
455                                if (ns == MAXNS)
456                                        break;
457                                EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
458                                EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
459                                n = ns;
460                        }
461                        EXT(statp).nsaddrs[n] = ina;
462                        EXT(statp).nsmap[n] = map;
463                }
464        }
465
466        /*
467         * Send request, RETRY times, or until successful.
468         */
469        for (try = 0; try < statp->retry; try++) {
470            for (ns = 0; ns < MAXNS; ns++)
471            {
472                struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
473
474                if (nsap == NULL)
475                        goto next_ns;
476 same_ns:
477                if (statp->qhook) {
478                        int done = 0, loops = 0;
479
480                        do {
481                                res_sendhookact act;
482
483                                struct sockaddr_in *nsap4;
484                                nsap4 = (struct sockaddr_in *) nsap;
485                                act = (*statp->qhook)(&nsap4, &buf, &buflen,
486                                                      ans, anssiz, &resplen);
487                                nsap = (struct sockaddr_in6 *) nsap4;
488                                switch (act) {
489                                case res_goahead:
490                                        done = 1;
491                                        break;
492                                case res_nextns:
493                                        res_nclose(statp);
494                                        goto next_ns;
495                                case res_done:
496                                        return (resplen);
497                                case res_modified:
498                                        /* give the hook another try */
499                                        if (++loops < 42) /*doug adams*/
500                                                break;
501                                        /*FALLTHROUGH*/
502                                case res_error:
503                                        /*FALLTHROUGH*/
504                                default:
505                                        return (-1);
506                                }
507                        } while (!done);
508                }
509
510#ifdef DEBUG
511                char tmpbuf[40];
512#endif
513                Dprint(statp->options & RES_DEBUG,
514                       (stdout, ";; Querying server (# %d) address = %s\n",
515                        ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
516                                          tmpbuf, sizeof (tmpbuf))));
517
518                if (v_circuit) {
519                        /* Use VC; at most one attempt per server. */
520                        try = statp->retry;
521                        n = send_vc(statp, buf, buflen, &ans, &anssiz, &terrno,
522                                    ns, ansp);
523                        if (n < 0)
524                                return (-1);
525                        if (n == 0)
526                                goto next_ns;
527                        resplen = n;
528                } else {
529                        /* Use datagrams. */
530                        n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
531                                    ns, &v_circuit, &gotsomewhere, ansp);
532                        if (n < 0)
533                                return (-1);
534                        if (n == 0)
535                                goto next_ns;
536                        if (v_circuit)
537                                goto same_ns;
538                        resplen = n;
539                }
540
541                Dprint((statp->options & RES_DEBUG) ||
542                       ((statp->pfcode & RES_PRF_REPLY) &&
543                        (statp->pfcode & RES_PRF_HEAD1)),
544                       (stdout, ";; got answer:\n"));
545
546                DprintQ((statp->options & RES_DEBUG) ||
547                        (statp->pfcode & RES_PRF_REPLY),
548                        (stdout, "%s", ""),
549                        ans, (resplen > anssiz) ? anssiz : resplen);
550
551                /*
552                 * If we have temporarily opened a virtual circuit,
553                 * or if we haven't been asked to keep a socket open,
554                 * close the socket.
555                 */
556                if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
557                    (statp->options & RES_STAYOPEN) == 0) {
558                        res_nclose(statp);
559                }
560                if (statp->rhook) {
561                        int done = 0, loops = 0;
562
563                        do {
564                                res_sendhookact act;
565
566                                act = (*statp->rhook)((struct sockaddr_in *)
567                                                      nsap, buf, buflen,
568                                                      ans, anssiz, &resplen);
569                                switch (act) {
570                                case res_goahead:
571                                case res_done:
572                                        done = 1;
573                                        break;
574                                case res_nextns:
575                                        res_nclose(statp);
576                                        goto next_ns;
577                                case res_modified:
578                                        /* give the hook another try */
579                                        if (++loops < 42) /*doug adams*/
580                                                break;
581                                        /*FALLTHROUGH*/
582                                case res_error:
583                                        /*FALLTHROUGH*/
584                                default:
585                                        return (-1);
586                                }
587                        } while (!done);
588
589                }
590                return (resplen);
591 next_ns: ;
592           } /*foreach ns*/
593        } /*foreach retry*/
594        res_nclose(statp);
595        if (!v_circuit) {
596                if (!gotsomewhere)
597                        __set_errno (ECONNREFUSED);     /* no nameservers found */
598                else
599                        __set_errno (ETIMEDOUT);        /* no answer obtained */
600        } else
601                __set_errno (terrno);
602        return (-1);
603}
604
605int
606res_nsend(res_state statp,
607          const u_char *buf, int buflen, u_char *ans, int anssiz)
608{
609        return __libc_res_nsend(statp, buf, buflen, ans, anssiz, NULL);
610}
611libresolv_hidden_def (res_nsend)
612
613/* Private */
614
615static int
616send_vc(res_state statp,
617        const u_char *buf, int buflen, u_char **ansp, int *anssizp,
618        int *terrno, int ns, u_char **anscp)
619{
620        const HEADER *hp = (HEADER *) buf;
621        u_char *ans = *ansp;
622        int anssiz = *anssizp;
623        HEADER *anhp = (HEADER *) ans;
624        struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
625        int truncating, connreset, resplen, n;
626        struct iovec iov[2];
627        u_short len;
628        u_char *cp;
629
630        connreset = 0;
631 same_ns:
632        truncating = 0;
633
634        /* Are we still talking to whom we want to talk to? */
635        if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
636                struct sockaddr_in6 peer;
637                int size = sizeof peer;
638
639                if (getpeername(statp->_vcsock,
640                                (struct sockaddr *)&peer, &size) < 0 ||
641                    !sock_eq(&peer, nsap)) {
642                        res_nclose(statp);
643                        statp->_flags &= ~RES_F_VC;
644                }
645        }
646
647        if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
648                if (statp->_vcsock >= 0)
649                        res_nclose(statp);
650
651                statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
652                if (statp->_vcsock < 0) {
653                        *terrno = errno;
654                        Perror(statp, stderr, "socket(vc)", errno);
655                        return (-1);
656                }
657                __set_errno (0);
658                if (connect(statp->_vcsock, (struct sockaddr *)nsap,
659                            sizeof *nsap) < 0) {
660                        *terrno = errno;
661                        Aerror(statp, stderr, "connect/vc", errno,
662                               (struct sockaddr *) nsap);
663                        res_nclose(statp);
664                        return (0);
665                }
666                statp->_flags |= RES_F_VC;
667        }
668
669        /*
670         * Send length & message
671         */
672        putshort((u_short)buflen, (u_char*)&len);
673        evConsIovec(&len, INT16SZ, &iov[0]);
674        evConsIovec((void*)buf, buflen, &iov[1]);
675        if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2))
676            != (INT16SZ + buflen)) {
677                *terrno = errno;
678                Perror(statp, stderr, "write failed", errno);
679                res_nclose(statp);
680                return (0);
681        }
682        /*
683         * Receive length & response
684         */
685 read_len:
686        cp = ans;
687        len = INT16SZ;
688        while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, (char *)cp,
689                                             (int)len))) > 0) {
690                cp += n;
691                if ((len -= n) <= 0)
692                        break;
693        }
694        if (n <= 0) {
695                *terrno = errno;
696                Perror(statp, stderr, "read failed", errno);
697                res_nclose(statp);
698                /*
699                 * A long running process might get its TCP
700                 * connection reset if the remote server was
701                 * restarted.  Requery the server instead of
702                 * trying a new one.  When there is only one
703                 * server, this means that a query might work
704                 * instead of failing.  We only allow one reset
705                 * per query to prevent looping.
706                 */
707                if (*terrno == ECONNRESET && !connreset) {
708                        connreset = 1;
709                        res_nclose(statp);
710                        goto same_ns;
711                }
712                res_nclose(statp);
713                return (0);
714        }
715        resplen = ns_get16(ans);
716        if (resplen > anssiz) {
717                if (anscp) {
718                        ans = malloc (MAXPACKET);
719                        if (ans == NULL) {
720                                *terrno = ENOMEM;
721                                res_nclose(statp);
722                                return (0);
723                        }
724                        anssiz = MAXPACKET;
725                        *anssizp = MAXPACKET;
726                        *ansp = ans;
727                        *anscp = ans;
728                        anhp = (HEADER *) ans;
729                        len = resplen;
730                } else {
731                        Dprint(statp->options & RES_DEBUG,
732                                (stdout, ";; response truncated\n")
733                        );
734                        truncating = 1;
735                        len = anssiz;
736                }
737        } else
738                len = resplen;
739        if (len < HFIXEDSZ) {
740                /*
741                 * Undersized message.
742                 */
743                Dprint(statp->options & RES_DEBUG,
744                       (stdout, ";; undersized: %d\n", len));
745                *terrno = EMSGSIZE;
746                res_nclose(statp);
747                return (0);
748        }
749        cp = ans;
750        while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
751                cp += n;
752                len -= n;
753        }
754        if (n <= 0) {
755                *terrno = errno;
756                Perror(statp, stderr, "read(vc)", errno);
757                res_nclose(statp);
758                return (0);
759        }
760        if (truncating) {
761                /*
762                 * Flush rest of answer so connection stays in synch.
763                 */
764                anhp->tc = 1;
765                len = resplen - anssiz;
766                while (len != 0) {
767                        char junk[PACKETSZ];
768
769                        n = read(statp->_vcsock, junk,
770                                 (len > sizeof junk) ? sizeof junk : len);
771                        if (n > 0)
772                                len -= n;
773                        else
774                                break;
775                }
776        }
777        /*
778         * If the calling applicating has bailed out of
779         * a previous call and failed to arrange to have
780         * the circuit closed or the server has got
781         * itself confused, then drop the packet and
782         * wait for the correct one.
783         */
784        if (hp->id != anhp->id) {
785                DprintQ((statp->options & RES_DEBUG) ||
786                        (statp->pfcode & RES_PRF_REPLY),
787                        (stdout, ";; old answer (unexpected):\n"),
788                        ans, (resplen > anssiz) ? anssiz: resplen);
789                goto read_len;
790        }
791
792        /*
793         * All is well, or the error is fatal.  Signal that the
794         * next nameserver ought not be tried.
795         */
796        return (resplen);
797}
798
799static int
800send_dg(res_state statp,
801        const u_char *buf, int buflen, u_char **ansp, int *anssizp,
802        int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp)
803{
804        const HEADER *hp = (HEADER *) buf;
805        u_char *ans = *ansp;
806        int anssiz = *anssizp;
807        HEADER *anhp = (HEADER *) ans;
808        struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
809        struct timespec now, timeout, finish;
810        struct pollfd pfd[1];
811        int ptimeout;
812        struct sockaddr_in6 from;
813        static int socket_pf = 0;
814        int fromlen, resplen, seconds, n;
815
816        if (EXT(statp).nssocks[ns] == -1) {
817                /* only try IPv6 if IPv6 NS and if not failed before */
818                if ((EXT(statp).nscount6 > 0) && (socket_pf != PF_INET)) {
819                        EXT(statp).nssocks[ns] =
820                            socket(PF_INET6, SOCK_DGRAM, 0);
821                        socket_pf = EXT(statp).nssocks[ns] < 0 ? PF_INET
822                                                               : PF_INET6;
823                }
824                if (EXT(statp).nssocks[ns] < 0)
825                        EXT(statp).nssocks[ns] = socket(PF_INET, SOCK_DGRAM, 0);
826                if (EXT(statp).nssocks[ns] < 0) {
827                        *terrno = errno;
828                        Perror(statp, stderr, "socket(dg)", errno);
829                        return (-1);
830                }
831                /* If IPv6 socket and nsap is IPv4, make it IPv4-mapped */
832                if ((socket_pf == PF_INET6) && (nsap->sin6_family == AF_INET))
833                        convaddr4to6(nsap);
834                /*
835                 * On a 4.3BSD+ machine (client and server,
836                 * actually), sending to a nameserver datagram
837                 * port with no nameserver will cause an
838                 * ICMP port unreachable message to be returned.
839                 * If our datagram socket is "connected" to the
840                 * server, we get an ECONNREFUSED error on the next
841                 * socket operation, and select returns if the
842                 * error message is received.  We can thus detect
843                 * the absence of a nameserver without timing out.
844                 */
845                if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap,
846                            sizeof *nsap) < 0) {
847                        Aerror(statp, stderr, "connect(dg)", errno,
848                               (struct sockaddr *) nsap);
849                        res_nclose(statp);
850                        return (0);
851                }
852                /* Make socket non-blocking.  */
853                int fl = fcntl (EXT(statp).nssocks[ns], F_GETFL);
854                if  (fl != -1)
855                        fcntl (EXT(statp).nssocks[ns], F_SETFL,
856                                 fl | O_NONBLOCK);
857                Dprint(statp->options & RES_DEBUG,
858                       (stdout, ";; new DG socket\n"))
859        }
860
861        /*
862         * Compute time for the total operation.
863         */
864        seconds = (statp->retrans << ns);
865        if (ns > 0)
866                seconds /= statp->nscount;
867        if (seconds <= 0)
868                seconds = 1;
869        evNowTime(&now);
870        evConsTime(&timeout, seconds, 0);
871        evAddTime(&finish, &now, &timeout);
872        int need_recompute = 0;
873        int nwritten = 0;
874        pfd[0].fd = EXT(statp).nssocks[ns];
875        pfd[0].events = POLLOUT;
876 wait:
877        if (need_recompute) {
878                evNowTime(&now);
879                if (evCmpTime(finish, now) <= 0) {
880                        Perror(statp, stderr, "select", errno);
881                        res_nclose(statp);
882                        return (0);
883                }
884                evSubTime(&timeout, &finish, &now);
885        }
886        /* Convert struct timespec in milliseconds.  */
887        ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
888
889        n = 0;
890        if (nwritten == 0)
891          n = poll (pfd, 1, 0);
892        if (__builtin_expect (n == 0, 0)) {
893                n = poll (pfd, 1, ptimeout);
894                need_recompute = 1;
895        }
896        if (n == 0) {
897                Dprint(statp->options & RES_DEBUG, (stdout,
898                                                    ";; timeout sending\n"));
899                *gotsomewhere = 1;
900                return (0);
901        }
902        if (n < 0) {
903                if (errno == EINTR) {
904                recompute_resend:
905                        evNowTime(&now);
906                        if (evCmpTime(finish, now) > 0) {
907                                evSubTime(&timeout, &finish, &now);
908                                goto wait;
909                        }
910                }
911                Perror(statp, stderr, "poll", errno);
912                res_nclose(statp);
913                return (0);
914        }
915        __set_errno (0);
916        if (pfd[0].revents & POLLOUT) {
917                if (send(pfd[0].fd, (char*)buf, buflen, 0) != buflen) {
918                        if (errno == EINTR || errno == EAGAIN)
919                                goto recompute_resend;
920                        Perror(statp, stderr, "send", errno);
921                        res_nclose(statp);
922                        return (0);
923                }
924                pfd[0].events = POLLIN;
925                ++nwritten;
926                goto wait;
927        } else if (pfd[0].revents & POLLIN) {
928                fromlen = sizeof(struct sockaddr_in6);
929                if (anssiz < MAXPACKET
930                    && anscp
931                    && (ioctl (pfd[0].fd, FIONREAD, &resplen) < 0
932                || anssiz < resplen)) {
933                        ans = malloc (MAXPACKET);
934                        if (ans == NULL)
935                                ans = *ansp;
936                        else {
937                                anssiz = MAXPACKET;
938                                *anssizp = MAXPACKET;
939                                *ansp = ans;
940                                *anscp = ans;
941                                anhp = (HEADER *) ans;
942                        }
943                }
944                resplen = recvfrom(pfd[0].fd, (char*)ans, anssiz,0,
945                                   (struct sockaddr *)&from, &fromlen);
946                if (resplen <= 0) {
947                        if (errno == EINTR || errno == EAGAIN) {
948                                need_recompute = 1;
949                                goto wait;
950                        }
951                        Perror(statp, stderr, "recvfrom", errno);
952                        res_nclose(statp);
953                        return (0);
954                }
955                *gotsomewhere = 1;
956                if (resplen < HFIXEDSZ) {
957                        /*
958                         * Undersized message.
959                         */
960                        Dprint(statp->options & RES_DEBUG,
961                               (stdout, ";; undersized: %d\n",
962                                resplen));
963                        *terrno = EMSGSIZE;
964                        res_nclose(statp);
965                        return (0);
966                }
967                if (hp->id != anhp->id) {
968                        /*
969                         * response from old query, ignore it.
970                         * XXX - potential security hazard could
971                         *       be detected here.
972                         */
973                        DprintQ((statp->options & RES_DEBUG) ||
974                                (statp->pfcode & RES_PRF_REPLY),
975                                (stdout, ";; old answer:\n"),
976                                ans, (resplen > anssiz) ? anssiz : resplen);
977                        goto wait;
978                }
979                if (!(statp->options & RES_INSECURE1) &&
980                    !res_ourserver_p(statp, &from)) {
981                        /*
982                         * response from wrong server? ignore it.
983                         * XXX - potential security hazard could
984                         *       be detected here.
985                         */
986                        DprintQ((statp->options & RES_DEBUG) ||
987                                (statp->pfcode & RES_PRF_REPLY),
988                                (stdout, ";; not our server:\n"),
989                                ans, (resplen > anssiz) ? anssiz : resplen);
990                        goto wait;
991                }
992                if (!(statp->options & RES_INSECURE2) &&
993                    !res_queriesmatch(buf, buf + buflen,
994                                      ans, ans + anssiz)) {
995                        /*
996                         * response contains wrong query? ignore it.
997                         * XXX - potential security hazard could
998                         *       be detected here.
999                         */
1000                        DprintQ((statp->options & RES_DEBUG) ||
1001                                (statp->pfcode & RES_PRF_REPLY),
1002                                (stdout, ";; wrong query name:\n"),
1003                                ans, (resplen > anssiz) ? anssiz : resplen);
1004                        goto wait;
1005                }
1006                if (anhp->rcode == SERVFAIL ||
1007                    anhp->rcode == NOTIMP ||
1008                    anhp->rcode == REFUSED) {
1009                        DprintQ(statp->options & RES_DEBUG,
1010                                (stdout, "server rejected query:\n"),
1011                                ans, (resplen > anssiz) ? anssiz : resplen);
1012                        res_nclose(statp);
1013                        /* don't retry if called from dig */
1014                        if (!statp->pfcode)
1015                                return (0);
1016                }
1017                if (!(statp->options & RES_IGNTC) && anhp->tc) {
1018                        /*
1019                         * To get the rest of answer,
1020                         * use TCP with same server.
1021                         */
1022                        Dprint(statp->options & RES_DEBUG,
1023                               (stdout, ";; truncated answer\n"));
1024                        *v_circuit = 1;
1025                        res_nclose(statp);
1026                        return (1);
1027                }
1028                /*
1029                 * All is well, or the error is fatal.  Signal that the
1030                 * next nameserver ought not be tried.
1031                 */
1032                return (resplen);
1033        } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1034                /* Something went wrong.  We can stop trying.  */
1035                res_nclose(statp);
1036                return (0);
1037        }
1038}
1039
1040#ifdef DEBUG
1041static void
1042Aerror(const res_state statp, FILE *file, const char *string, int error,
1043       const struct sockaddr *address)
1044{
1045        int save = errno;
1046
1047        if ((statp->options & RES_DEBUG) != 0) {
1048                char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
1049
1050                fprintf(file, "res_send: %s ([%s].%u): %s\n",
1051                        string,
1052                        inet_ntop(address->sa_family, address->sa_data,
1053                                  tmp, sizeof tmp),
1054                        (address->sa_family == AF_INET
1055                         ? ntohs(((struct sockaddr_in *) address)->sin_port)
1056                         : address->sa_family == AF_INET6
1057                         ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
1058                         : 0),
1059                        strerror(error));
1060        }
1061        __set_errno (save);
1062}
1063
1064static void
1065Perror(const res_state statp, FILE *file, const char *string, int error) {
1066        int save = errno;
1067
1068        if ((statp->options & RES_DEBUG) != 0)
1069                fprintf(file, "res_send: %s: %s\n",
1070                        string, strerror(error));
1071        __set_errno (save);
1072}
1073#endif
1074
1075static int
1076sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
1077        if (a1->sin6_family == a2->sin6_family) {
1078                if (a1->sin6_family == AF_INET)
1079                        return ((((struct sockaddr_in *)a1)->sin_port ==
1080                                 ((struct sockaddr_in *)a2)->sin_port) &&
1081                                (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
1082                                 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1083                else
1084                        return ((a1->sin6_port == a2->sin6_port) &&
1085                                !memcmp(&a1->sin6_addr, &a2->sin6_addr,
1086                                        sizeof (struct in6_addr)));
1087        }
1088        if (a1->sin6_family == AF_INET) {
1089                struct sockaddr_in6 *sap = a1;
1090                a1 = a2;
1091                a2 = sap;
1092        } /* assumes that AF_INET and AF_INET6 are the only possibilities */
1093        return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
1094                IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
1095                (a1->sin6_addr.s6_addr32[3] ==
1096                 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1097}
1098
1099/*
1100 * Converts IPv4 family, address and port to
1101 * IPv6 family, IPv4-mapped IPv6 address and port.
1102 */
1103static void
1104convaddr4to6(struct sockaddr_in6 *sa)
1105{
1106    struct sockaddr_in *sa4p = (struct sockaddr_in *) sa;
1107    in_port_t port = sa4p->sin_port;
1108    in_addr_t addr = sa4p->sin_addr.s_addr;
1109
1110    sa->sin6_family = AF_INET6;
1111    sa->sin6_port = port;
1112    sa->sin6_addr.s6_addr32[0] = 0;
1113    sa->sin6_addr.s6_addr32[1] = 0;
1114    sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
1115    sa->sin6_addr.s6_addr32[3] = addr;
1116}
Note: See TracBrowser for help on using the repository browser.