* init.c (__pthread_initialize_minimal_internal): Cheat a bit by
[glibc.git] / resolv / res_send.c
blobf75a26ec23e4a870679058f2889ae6222181bd9d
1 /*
2 * Copyright (c) 1985, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
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.
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.
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
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.
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.
51 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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.
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 */
73 * Send query to name server and wait for reply.
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>
84 #include <netinet/in.h>
85 #include <arpa/nameser.h>
86 #include <arpa/inet.h>
87 #include <sys/ioctl.h>
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 #include <kernel-features.h>
100 #if PACKETSZ > 65536
101 #define MAXPACKET PACKETSZ
102 #else
103 #define MAXPACKET 65536
104 #endif
107 #ifndef __ASSUME_SOCK_CLOEXEC
108 static int __have_o_nonblock;
109 #else
110 # define __have_o_nonblock 0
111 #endif
114 /* From ev_streams.c. */
116 static inline void
117 __attribute ((always_inline))
118 evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
119 memset(vec, 0xf5, sizeof (*vec));
120 vec->iov_base = buf;
121 vec->iov_len = cnt;
124 /* From ev_timers.c. */
126 #define BILLION 1000000000
128 static inline void
129 evConsTime(struct timespec *res, time_t sec, long nsec) {
130 res->tv_sec = sec;
131 res->tv_nsec = nsec;
134 static inline void
135 evAddTime(struct timespec *res, const struct timespec *addend1,
136 const struct timespec *addend2) {
137 res->tv_sec = addend1->tv_sec + addend2->tv_sec;
138 res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
139 if (res->tv_nsec >= BILLION) {
140 res->tv_sec++;
141 res->tv_nsec -= BILLION;
145 static inline void
146 evSubTime(struct timespec *res, const struct timespec *minuend,
147 const struct timespec *subtrahend) {
148 res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
149 if (minuend->tv_nsec >= subtrahend->tv_nsec)
150 res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
151 else {
152 res->tv_nsec = (BILLION
153 - subtrahend->tv_nsec + minuend->tv_nsec);
154 res->tv_sec--;
158 static inline int
159 evCmpTime(struct timespec a, struct timespec b) {
160 long x = a.tv_sec - b.tv_sec;
162 if (x == 0L)
163 x = a.tv_nsec - b.tv_nsec;
164 return (x < 0L ? (-1) : x > 0L ? (1) : (0));
167 static inline void
168 evNowTime(struct timespec *res) {
169 struct timeval now;
171 if (gettimeofday(&now, NULL) < 0)
172 evConsTime(res, 0, 0);
173 else
174 TIMEVAL_TO_TIMESPEC (&now, res);
178 /* Options. Leave them on. */
179 /* #undef DEBUG */
180 #include "res_debug.h"
182 #define EXT(res) ((res)->_u._ext)
184 /* Forward. */
186 static int send_vc(res_state, const u_char *, int,
187 const u_char *, int,
188 u_char **, int *, int *, int, u_char **,
189 u_char **, int *, int *);
190 static int send_dg(res_state, const u_char *, int,
191 const u_char *, int,
192 u_char **, int *, int *, int,
193 int *, int *, u_char **,
194 u_char **, int *, int *);
195 #ifdef DEBUG
196 static void Aerror(const res_state, FILE *, const char *, int,
197 const struct sockaddr *);
198 static void Perror(const res_state, FILE *, const char *, int);
199 #endif
200 static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
202 /* Reachover. */
204 static void convaddr4to6(struct sockaddr_in6 *sa);
206 /* Public. */
208 /* int
209 * res_isourserver(ina)
210 * looks up "ina" in _res.ns_addr_list[]
211 * returns:
212 * 0 : not found
213 * >0 : found
214 * author:
215 * paul vixie, 29may94
218 res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
220 int ns;
222 if (inp->sin6_family == AF_INET) {
223 struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
224 in_port_t port = in4p->sin_port;
225 in_addr_t addr = in4p->sin_addr.s_addr;
227 for (ns = 0; ns < MAXNS; ns++) {
228 const struct sockaddr_in *srv =
229 (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
231 if ((srv != NULL) && (srv->sin_family == AF_INET) &&
232 (srv->sin_port == port) &&
233 (srv->sin_addr.s_addr == INADDR_ANY ||
234 srv->sin_addr.s_addr == addr))
235 return (1);
237 } else if (inp->sin6_family == AF_INET6) {
238 for (ns = 0; ns < MAXNS; ns++) {
239 const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
240 if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
241 (srv->sin6_port == inp->sin6_port) &&
242 !(memcmp(&srv->sin6_addr, &in6addr_any,
243 sizeof (struct in6_addr)) &&
244 memcmp(&srv->sin6_addr, &inp->sin6_addr,
245 sizeof (struct in6_addr))))
246 return (1);
249 return (0);
252 /* int
253 * res_nameinquery(name, type, class, buf, eom)
254 * look for (name,type,class) in the query section of packet (buf,eom)
255 * requires:
256 * buf + HFIXEDSZ <= eom
257 * returns:
258 * -1 : format error
259 * 0 : not found
260 * >0 : found
261 * author:
262 * paul vixie, 29may94
265 res_nameinquery(const char *name, int type, int class,
266 const u_char *buf, const u_char *eom)
268 const u_char *cp = buf + HFIXEDSZ;
269 int qdcount = ntohs(((HEADER*)buf)->qdcount);
271 while (qdcount-- > 0) {
272 char tname[MAXDNAME+1];
273 int n, ttype, tclass;
275 n = dn_expand(buf, eom, cp, tname, sizeof tname);
276 if (n < 0)
277 return (-1);
278 cp += n;
279 if (cp + 2 * INT16SZ > eom)
280 return (-1);
281 NS_GET16(ttype, cp);
282 NS_GET16(tclass, cp);
283 if (ttype == type && tclass == class &&
284 ns_samename(tname, name) == 1)
285 return (1);
287 return (0);
289 libresolv_hidden_def (res_nameinquery)
291 /* int
292 * res_queriesmatch(buf1, eom1, buf2, eom2)
293 * is there a 1:1 mapping of (name,type,class)
294 * in (buf1,eom1) and (buf2,eom2)?
295 * returns:
296 * -1 : format error
297 * 0 : not a 1:1 mapping
298 * >0 : is a 1:1 mapping
299 * author:
300 * paul vixie, 29may94
303 res_queriesmatch(const u_char *buf1, const u_char *eom1,
304 const u_char *buf2, const u_char *eom2)
306 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
307 return (-1);
310 * Only header section present in replies to
311 * dynamic update packets.
313 if ((((HEADER *)buf1)->opcode == ns_o_update) &&
314 (((HEADER *)buf2)->opcode == ns_o_update))
315 return (1);
317 /* Note that we initially do not convert QDCOUNT to the host byte
318 order. We can compare it with the second buffer's QDCOUNT
319 value without doing this. */
320 int qdcount = ((HEADER*)buf1)->qdcount;
321 if (qdcount != ((HEADER*)buf2)->qdcount)
322 return (0);
324 qdcount = htons (qdcount);
325 const u_char *cp = buf1 + HFIXEDSZ;
327 while (qdcount-- > 0) {
328 char tname[MAXDNAME+1];
329 int n, ttype, tclass;
331 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
332 if (n < 0)
333 return (-1);
334 cp += n;
335 if (cp + 2 * INT16SZ > eom1)
336 return (-1);
337 NS_GET16(ttype, cp);
338 NS_GET16(tclass, cp);
339 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
340 return (0);
342 return (1);
344 libresolv_hidden_def (res_queriesmatch)
347 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
348 const u_char *buf2, int buflen2,
349 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
350 int *nansp2, int *resplen2)
352 int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
354 if (statp->nscount == 0) {
355 __set_errno (ESRCH);
356 return (-1);
359 if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
360 __set_errno (EINVAL);
361 return (-1);
364 #ifdef USE_HOOKS
365 if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
366 if (anssiz < MAXPACKET && ansp) {
367 u_char *buf = malloc (MAXPACKET);
368 if (buf == NULL)
369 return (-1);
370 memcpy (buf, ans, HFIXEDSZ);
371 *ansp = buf;
372 ans = buf;
373 anssiz = MAXPACKET;
376 #endif
378 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
379 (stdout, ";; res_send()\n"), buf, buflen);
380 v_circuit = ((statp->options & RES_USEVC)
381 || buflen > PACKETSZ
382 || buflen2 > PACKETSZ);
383 gotsomewhere = 0;
384 terrno = ETIMEDOUT;
387 * If the ns_addr_list in the resolver context has changed, then
388 * invalidate our cached copy and the associated timing data.
390 if (EXT(statp).nsinit) {
391 int needclose = 0;
393 if (EXT(statp).nscount != statp->nscount)
394 needclose++;
395 else
396 for (ns = 0; ns < MAXNS; ns++) {
397 unsigned int map = EXT(statp).nsmap[ns];
398 if (map < MAXNS
399 && !sock_eq((struct sockaddr_in6 *)
400 &statp->nsaddr_list[map],
401 EXT(statp).nsaddrs[ns]))
403 needclose++;
404 break;
407 if (needclose)
408 __res_iclose(statp, false);
412 * Maybe initialize our private copy of the ns_addr_list.
414 if (EXT(statp).nsinit == 0) {
415 unsigned char map[MAXNS];
417 memset (map, MAXNS, sizeof (map));
418 for (n = 0; n < MAXNS; n++) {
419 ns = EXT(statp).nsmap[n];
420 if (ns < statp->nscount)
421 map[ns] = n;
422 else if (ns < MAXNS) {
423 free(EXT(statp).nsaddrs[n]);
424 EXT(statp).nsaddrs[n] = NULL;
425 EXT(statp).nsmap[n] = MAXNS;
428 n = statp->nscount;
429 if (statp->nscount > EXT(statp).nscount)
430 for (n = EXT(statp).nscount, ns = 0;
431 n < statp->nscount; n++) {
432 while (ns < MAXNS
433 && EXT(statp).nsmap[ns] != MAXNS)
434 ns++;
435 if (ns == MAXNS)
436 break;
437 EXT(statp).nsmap[ns] = n;
438 map[n] = ns++;
440 EXT(statp).nscount = n;
441 for (ns = 0; ns < EXT(statp).nscount; ns++) {
442 n = map[ns];
443 if (EXT(statp).nsaddrs[n] == NULL)
444 EXT(statp).nsaddrs[n] =
445 malloc(sizeof (struct sockaddr_in6));
446 if (EXT(statp).nsaddrs[n] != NULL) {
447 memset (mempcpy(EXT(statp).nsaddrs[n],
448 &statp->nsaddr_list[ns],
449 sizeof (struct sockaddr_in)),
450 '\0',
451 sizeof (struct sockaddr_in6)
452 - sizeof (struct sockaddr_in));
453 EXT(statp).nssocks[n] = -1;
454 n++;
457 EXT(statp).nsinit = 1;
461 * Some resolvers want to even out the load on their nameservers.
462 * Note that RES_BLAST overrides RES_ROTATE.
464 if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
465 (statp->options & RES_BLAST) == 0) {
466 struct sockaddr_in6 *ina;
467 unsigned int map;
469 n = 0;
470 while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
471 n++;
472 if (n < MAXNS) {
473 ina = EXT(statp).nsaddrs[n];
474 map = EXT(statp).nsmap[n];
475 for (;;) {
476 ns = n + 1;
477 while (ns < MAXNS
478 && EXT(statp).nsmap[ns] == MAXNS)
479 ns++;
480 if (ns == MAXNS)
481 break;
482 EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
483 EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
484 n = ns;
486 EXT(statp).nsaddrs[n] = ina;
487 EXT(statp).nsmap[n] = map;
492 * Send request, RETRY times, or until successful.
494 for (try = 0; try < statp->retry; try++) {
495 for (ns = 0; ns < MAXNS; ns++)
497 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
499 if (nsap == NULL)
500 goto next_ns;
501 same_ns:
502 #ifdef USE_HOOKS
503 if (__builtin_expect (statp->qhook != NULL, 0)) {
504 int done = 0, loops = 0;
506 do {
507 res_sendhookact act;
509 struct sockaddr_in *nsap4;
510 nsap4 = (struct sockaddr_in *) nsap;
511 act = (*statp->qhook)(&nsap4, &buf, &buflen,
512 ans, anssiz, &resplen);
513 nsap = (struct sockaddr_in6 *) nsap4;
514 switch (act) {
515 case res_goahead:
516 done = 1;
517 break;
518 case res_nextns:
519 __res_iclose(statp, false);
520 goto next_ns;
521 case res_done:
522 return (resplen);
523 case res_modified:
524 /* give the hook another try */
525 if (++loops < 42) /*doug adams*/
526 break;
527 /*FALLTHROUGH*/
528 case res_error:
529 /*FALLTHROUGH*/
530 default:
531 return (-1);
533 } while (!done);
535 #endif
537 #ifdef DEBUG
538 char tmpbuf[40];
539 #endif
540 Dprint(statp->options & RES_DEBUG,
541 (stdout, ";; Querying server (# %d) address = %s\n",
542 ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
543 tmpbuf, sizeof (tmpbuf))));
545 if (__builtin_expect (v_circuit, 0)) {
546 /* Use VC; at most one attempt per server. */
547 try = statp->retry;
548 n = send_vc(statp, buf, buflen, buf2, buflen2,
549 &ans, &anssiz, &terrno,
550 ns, ansp, ansp2, nansp2, resplen2);
551 if (n < 0)
552 return (-1);
553 if (n == 0)
554 goto next_ns;
555 } else {
556 /* Use datagrams. */
557 n = send_dg(statp, buf, buflen, buf2, buflen2,
558 &ans, &anssiz, &terrno,
559 ns, &v_circuit, &gotsomewhere, ansp,
560 ansp2, nansp2, resplen2);
561 if (n < 0)
562 return (-1);
563 if (n == 0)
564 goto next_ns;
565 if (v_circuit)
566 // XXX Check whether both requests failed or
567 // XXX whether one has been answered successfully
568 goto same_ns;
571 resplen = n;
573 Dprint((statp->options & RES_DEBUG) ||
574 ((statp->pfcode & RES_PRF_REPLY) &&
575 (statp->pfcode & RES_PRF_HEAD1)),
576 (stdout, ";; got answer:\n"));
578 DprintQ((statp->options & RES_DEBUG) ||
579 (statp->pfcode & RES_PRF_REPLY),
580 (stdout, "%s", ""),
581 ans, (resplen > anssiz) ? anssiz : resplen);
582 if (buf2 != NULL)
583 DprintQ((statp->options & RES_DEBUG) ||
584 (statp->pfcode & RES_PRF_REPLY),
585 (stdout, "%s", ""),
586 *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
589 * If we have temporarily opened a virtual circuit,
590 * or if we haven't been asked to keep a socket open,
591 * close the socket.
593 if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
594 (statp->options & RES_STAYOPEN) == 0) {
595 __res_iclose(statp, false);
597 #ifdef USE_HOOKS
598 if (__builtin_expect (statp->rhook, 0)) {
599 int done = 0, loops = 0;
601 do {
602 res_sendhookact act;
604 act = (*statp->rhook)((struct sockaddr_in *)
605 nsap, buf, buflen,
606 ans, anssiz, &resplen);
607 switch (act) {
608 case res_goahead:
609 case res_done:
610 done = 1;
611 break;
612 case res_nextns:
613 __res_iclose(statp, false);
614 goto next_ns;
615 case res_modified:
616 /* give the hook another try */
617 if (++loops < 42) /*doug adams*/
618 break;
619 /*FALLTHROUGH*/
620 case res_error:
621 /*FALLTHROUGH*/
622 default:
623 return (-1);
625 } while (!done);
628 #endif
629 return (resplen);
630 next_ns: ;
631 } /*foreach ns*/
632 } /*foreach retry*/
633 __res_iclose(statp, false);
634 if (!v_circuit) {
635 if (!gotsomewhere)
636 __set_errno (ECONNREFUSED); /* no nameservers found */
637 else
638 __set_errno (ETIMEDOUT); /* no answer obtained */
639 } else
640 __set_errno (terrno);
641 return (-1);
645 res_nsend(res_state statp,
646 const u_char *buf, int buflen, u_char *ans, int anssiz)
648 return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
649 NULL, NULL, NULL, NULL);
651 libresolv_hidden_def (res_nsend)
653 /* Private */
655 static int
656 send_vc(res_state statp,
657 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
658 u_char **ansp, int *anssizp,
659 int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
660 int *resplen2)
662 const HEADER *hp = (HEADER *) buf;
663 const HEADER *hp2 = (HEADER *) buf2;
664 u_char *ans = *ansp;
665 int orig_anssizp = *anssizp;
666 // XXX REMOVE
667 // int anssiz = *anssizp;
668 HEADER *anhp = (HEADER *) ans;
669 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
670 int truncating, connreset, resplen, n;
671 struct iovec iov[4];
672 u_short len;
673 u_short len2;
674 u_char *cp;
676 if (resplen2 != NULL)
677 *resplen2 = 0;
678 connreset = 0;
679 same_ns:
680 truncating = 0;
682 /* Are we still talking to whom we want to talk to? */
683 if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
684 struct sockaddr_in6 peer;
685 socklen_t size = sizeof peer;
687 if (getpeername(statp->_vcsock,
688 (struct sockaddr *)&peer, &size) < 0 ||
689 !sock_eq(&peer, nsap)) {
690 __res_iclose(statp, false);
691 statp->_flags &= ~RES_F_VC;
695 if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
696 if (statp->_vcsock >= 0)
697 __res_iclose(statp, false);
699 statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
700 if (statp->_vcsock < 0) {
701 *terrno = errno;
702 Perror(statp, stderr, "socket(vc)", errno);
703 return (-1);
705 __set_errno (0);
706 if (connect(statp->_vcsock, (struct sockaddr *)nsap,
707 nsap->sin6_family == AF_INET
708 ? sizeof (struct sockaddr_in)
709 : sizeof (struct sockaddr_in6)) < 0) {
710 *terrno = errno;
711 Aerror(statp, stderr, "connect/vc", errno,
712 (struct sockaddr *) nsap);
713 __res_iclose(statp, false);
714 return (0);
716 statp->_flags |= RES_F_VC;
720 * Send length & message
722 len = htons ((u_short) buflen);
723 evConsIovec(&len, INT16SZ, &iov[0]);
724 evConsIovec((void*)buf, buflen, &iov[1]);
725 int niov = 2;
726 ssize_t explen = INT16SZ + buflen;
727 if (buf2 != NULL) {
728 len2 = htons ((u_short) buflen2);
729 evConsIovec(&len2, INT16SZ, &iov[2]);
730 evConsIovec((void*)buf2, buflen2, &iov[3]);
731 niov = 4;
732 explen += INT16SZ + buflen2;
734 if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
735 *terrno = errno;
736 Perror(statp, stderr, "write failed", errno);
737 __res_iclose(statp, false);
738 return (0);
741 * Receive length & response
743 int recvresp1 = 0;
744 int recvresp2 = buf2 == NULL;
745 uint16_t rlen16;
746 read_len:
747 cp = (u_char *)&rlen16;
748 len = sizeof(rlen16);
749 while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
750 (int)len))) > 0) {
751 cp += n;
752 if ((len -= n) <= 0)
753 break;
755 if (n <= 0) {
756 *terrno = errno;
757 Perror(statp, stderr, "read failed", errno);
758 __res_iclose(statp, false);
760 * A long running process might get its TCP
761 * connection reset if the remote server was
762 * restarted. Requery the server instead of
763 * trying a new one. When there is only one
764 * server, this means that a query might work
765 * instead of failing. We only allow one reset
766 * per query to prevent looping.
768 if (*terrno == ECONNRESET && !connreset) {
769 connreset = 1;
770 goto same_ns;
772 return (0);
774 int rlen = ntohs (rlen16);
776 int *thisanssizp;
777 u_char **thisansp;
778 int *thisresplenp;
779 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
780 thisanssizp = anssizp;
781 thisansp = anscp ?: ansp;
782 assert (anscp != NULL || ansp2 == NULL);
783 thisresplenp = &resplen;
784 } else {
785 if (*anssizp != MAXPACKET) {
786 /* No buffer allocated for the first
787 reply. We can try to use the rest
788 of the user-provided buffer. */
789 #ifdef _STRING_ARCH_unaligned
790 *anssizp2 = orig_anssizp - resplen;
791 *ansp2 = *ansp + resplen;
792 #else
793 int aligned_resplen
794 = ((resplen + __alignof__ (HEADER) - 1)
795 & ~(__alignof__ (HEADER) - 1));
796 *anssizp2 = orig_anssizp - aligned_resplen;
797 *ansp2 = *ansp + aligned_resplen;
798 #endif
799 } else {
800 /* The first reply did not fit into the
801 user-provided buffer. Maybe the second
802 answer will. */
803 *anssizp2 = orig_anssizp;
804 *ansp2 = *ansp;
807 thisanssizp = anssizp2;
808 thisansp = ansp2;
809 thisresplenp = resplen2;
811 anhp = (HEADER *) *thisansp;
813 *thisresplenp = rlen;
814 if (rlen > *thisanssizp) {
815 /* Yes, we test ANSCP here. If we have two buffers
816 both will be allocatable. */
817 if (__builtin_expect (anscp != NULL, 1)) {
818 u_char *newp = malloc (MAXPACKET);
819 if (newp == NULL) {
820 *terrno = ENOMEM;
821 __res_iclose(statp, false);
822 return (0);
824 *thisanssizp = MAXPACKET;
825 *thisansp = newp;
826 anhp = (HEADER *) newp;
827 len = rlen;
828 } else {
829 Dprint(statp->options & RES_DEBUG,
830 (stdout, ";; response truncated\n")
832 truncating = 1;
833 len = *thisanssizp;
835 } else
836 len = rlen;
838 if (__builtin_expect (len < HFIXEDSZ, 0)) {
840 * Undersized message.
842 Dprint(statp->options & RES_DEBUG,
843 (stdout, ";; undersized: %d\n", len));
844 *terrno = EMSGSIZE;
845 __res_iclose(statp, false);
846 return (0);
849 cp = *thisansp;
850 while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
851 cp += n;
852 len -= n;
854 if (__builtin_expect (n <= 0, 0)) {
855 *terrno = errno;
856 Perror(statp, stderr, "read(vc)", errno);
857 __res_iclose(statp, false);
858 return (0);
860 if (__builtin_expect (truncating, 0)) {
862 * Flush rest of answer so connection stays in synch.
864 anhp->tc = 1;
865 len = rlen - *thisanssizp;
866 while (len != 0) {
867 char junk[PACKETSZ];
869 n = read(statp->_vcsock, junk,
870 (len > sizeof junk) ? sizeof junk : len);
871 if (n > 0)
872 len -= n;
873 else
874 break;
878 * If the calling applicating has bailed out of
879 * a previous call and failed to arrange to have
880 * the circuit closed or the server has got
881 * itself confused, then drop the packet and
882 * wait for the correct one.
884 if ((recvresp1 || hp->id != anhp->id)
885 && (recvresp2 || hp2->id != anhp->id)) {
886 DprintQ((statp->options & RES_DEBUG) ||
887 (statp->pfcode & RES_PRF_REPLY),
888 (stdout, ";; old answer (unexpected):\n"),
889 *thisansp,
890 (rlen > *thisanssiz) ? *thisanssiz: rlen);
891 goto read_len;
894 /* Mark which reply we received. */
895 if (recvresp1 == 0 && hp->id == anhp->id)
896 recvresp1 = 1;
897 else
898 recvresp2 = 1;
899 /* Repeat waiting if we have a second answer to arrive. */
900 if ((recvresp1 & recvresp2) == 0)
901 goto read_len;
904 * All is well, or the error is fatal. Signal that the
905 * next nameserver ought not be tried.
907 return resplen;
910 static int
911 send_dg(res_state statp,
912 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
913 u_char **ansp, int *anssizp,
914 int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
915 u_char **ansp2, int *anssizp2, int *resplen2)
917 const HEADER *hp = (HEADER *) buf;
918 const HEADER *hp2 = (HEADER *) buf2;
919 u_char *ans = *ansp;
920 int orig_anssizp = *anssizp;
921 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
922 struct timespec now, timeout, finish;
923 struct pollfd pfd[1];
924 int ptimeout;
925 struct sockaddr_in6 from;
926 int resplen, seconds, n;
928 if (EXT(statp).nssocks[ns] == -1) {
929 /* only try IPv6 if IPv6 NS and if not failed before */
930 if ((EXT(statp).nscount6 > 0) && !statp->ipv6_unavail) {
931 if (__have_o_nonblock >= 0) {
932 EXT(statp).nssocks[ns] =
933 socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK,
935 #ifndef __ASSUME_SOCK_CLOEXEC
936 if (__have_o_nonblock == 0)
937 __have_o_nonblock
938 = (EXT(statp).nssocks[ns] == -1
939 && errno == EINVAL ? -1 : 1);
940 #endif
942 if (__have_o_nonblock < 0)
943 EXT(statp).nssocks[ns] =
944 socket(PF_INET6, SOCK_DGRAM, 0);
945 if (EXT(statp).nssocks[ns] < 0)
946 statp->ipv6_unavail = errno == EAFNOSUPPORT;
947 /* If IPv6 socket and nsap is IPv4, make it
948 IPv4-mapped */
949 else if (nsap->sin6_family == AF_INET)
950 convaddr4to6(nsap);
952 if (EXT(statp).nssocks[ns] < 0) {
953 if (__have_o_nonblock >= 0) {
954 EXT(statp).nssocks[ns]
955 = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK,
957 #ifndef __ASSUME_SOCK_CLOEXEC
958 if (__have_o_nonblock == 0)
959 __have_o_nonblock
960 = (EXT(statp).nssocks[ns] == -1
961 && errno == EINVAL ? -1 : 1);
962 #endif
964 if (__have_o_nonblock < 0)
965 EXT(statp).nssocks[ns]
966 = socket(PF_INET, SOCK_DGRAM, 0);
968 if (EXT(statp).nssocks[ns] < 0) {
969 *terrno = errno;
970 Perror(statp, stderr, "socket(dg)", errno);
971 return (-1);
975 * On a 4.3BSD+ machine (client and server,
976 * actually), sending to a nameserver datagram
977 * port with no nameserver will cause an
978 * ICMP port unreachable message to be returned.
979 * If our datagram socket is "connected" to the
980 * server, we get an ECONNREFUSED error on the next
981 * socket operation, and select returns if the
982 * error message is received. We can thus detect
983 * the absence of a nameserver without timing out.
985 if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap,
986 sizeof *nsap) < 0) {
987 Aerror(statp, stderr, "connect(dg)", errno,
988 (struct sockaddr *) nsap);
989 __res_iclose(statp, false);
990 return (0);
992 if (__have_o_nonblock < 0) {
993 /* Make socket non-blocking. */
994 int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
995 if (fl != -1)
996 __fcntl (EXT(statp).nssocks[ns], F_SETFL,
997 fl | O_NONBLOCK);
998 Dprint(statp->options & RES_DEBUG,
999 (stdout, ";; new DG socket\n"))
1004 * Compute time for the total operation.
1006 seconds = (statp->retrans << ns);
1007 if (ns > 0)
1008 seconds /= statp->nscount;
1009 if (seconds <= 0)
1010 seconds = 1;
1011 evNowTime(&now);
1012 evConsTime(&timeout, seconds, 0);
1013 evAddTime(&finish, &now, &timeout);
1014 int need_recompute = 0;
1015 int nwritten = 0;
1016 int recvresp1 = 0;
1017 int recvresp2 = buf2 == NULL;
1018 pfd[0].fd = EXT(statp).nssocks[ns];
1019 pfd[0].events = POLLOUT;
1020 if (resplen2 != NULL)
1021 *resplen2 = 0;
1022 wait:
1023 if (need_recompute) {
1024 recompute_resend:
1025 evNowTime(&now);
1026 if (evCmpTime(finish, now) <= 0) {
1027 poll_err_out:
1028 Perror(statp, stderr, "poll", errno);
1029 err_out:
1030 __res_iclose(statp, false);
1031 return (0);
1033 evSubTime(&timeout, &finish, &now);
1035 /* Convert struct timespec in milliseconds. */
1036 ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
1038 n = 0;
1039 if (nwritten == 0)
1040 n = __poll (pfd, 1, 0);
1041 if (__builtin_expect (n == 0, 0)) {
1042 n = __poll (pfd, 1, ptimeout);
1043 need_recompute = 1;
1045 if (n == 0) {
1046 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1047 if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
1049 *resplen2 = 1;
1050 return resplen;
1053 *gotsomewhere = 1;
1054 return (0);
1056 if (n < 0) {
1057 if (errno == EINTR)
1058 goto recompute_resend;
1060 goto poll_err_out;
1062 __set_errno (0);
1063 if (pfd[0].revents & POLLOUT) {
1064 ssize_t sr;
1065 if (nwritten != 0)
1066 sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
1067 else
1068 sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
1070 if (sr != buflen) {
1071 if (errno == EINTR || errno == EAGAIN)
1072 goto recompute_resend;
1073 Perror(statp, stderr, "send", errno);
1074 goto err_out;
1076 if (nwritten != 0 || buf2 == NULL)
1077 pfd[0].events = POLLIN;
1078 else
1079 pfd[0].events = POLLIN | POLLOUT;
1080 ++nwritten;
1081 goto wait;
1082 } else if (pfd[0].revents & POLLIN) {
1083 int *thisanssizp;
1084 u_char **thisansp;
1085 int *thisresplenp;
1087 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
1088 thisanssizp = anssizp;
1089 thisansp = anscp ?: ansp;
1090 assert (anscp != NULL || ansp2 == NULL);
1091 thisresplenp = &resplen;
1092 } else {
1093 if (*anssizp != MAXPACKET) {
1094 /* No buffer allocated for the first
1095 reply. We can try to use the rest
1096 of the user-provided buffer. */
1097 #ifdef _STRING_ARCH_unaligned
1098 *anssizp2 = orig_anssizp - resplen;
1099 *ansp2 = *ansp + resplen;
1100 #else
1101 int aligned_resplen
1102 = ((resplen + __alignof__ (HEADER) - 1)
1103 & ~(__alignof__ (HEADER) - 1));
1104 *anssizp2 = orig_anssizp - aligned_resplen;
1105 *ansp2 = *ansp + aligned_resplen;
1106 #endif
1107 } else {
1108 /* The first reply did not fit into the
1109 user-provided buffer. Maybe the second
1110 answer will. */
1111 *anssizp2 = orig_anssizp;
1112 *ansp2 = *ansp;
1115 thisanssizp = anssizp2;
1116 thisansp = ansp2;
1117 thisresplenp = resplen2;
1120 if (*thisanssizp < MAXPACKET
1121 /* Yes, we test ANSCP here. If we have two buffers
1122 both will be allocatable. */
1123 && anscp
1124 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
1125 || *thisanssizp < *thisresplenp)) {
1126 u_char *newp = malloc (MAXPACKET);
1127 if (newp != NULL) {
1128 *anssizp = MAXPACKET;
1129 *thisansp = ans = newp;
1132 HEADER *anhp = (HEADER *) *thisansp;
1133 socklen_t fromlen = sizeof(struct sockaddr_in6);
1134 assert (sizeof(from) <= fromlen);
1135 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
1136 *thisanssizp, 0,
1137 (struct sockaddr *)&from, &fromlen);
1138 if (__builtin_expect (*thisresplenp <= 0, 0)) {
1139 if (errno == EINTR || errno == EAGAIN) {
1140 need_recompute = 1;
1141 goto wait;
1143 Perror(statp, stderr, "recvfrom", errno);
1144 goto err_out;
1146 *gotsomewhere = 1;
1147 if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
1149 * Undersized message.
1151 Dprint(statp->options & RES_DEBUG,
1152 (stdout, ";; undersized: %d\n",
1153 *thisresplen));
1154 *terrno = EMSGSIZE;
1155 goto err_out;
1157 if ((recvresp1 || hp->id != anhp->id)
1158 && (recvresp2 || hp2->id != anhp->id)) {
1160 * response from old query, ignore it.
1161 * XXX - potential security hazard could
1162 * be detected here.
1164 DprintQ((statp->options & RES_DEBUG) ||
1165 (statp->pfcode & RES_PRF_REPLY),
1166 (stdout, ";; old answer:\n"),
1167 thisansp,
1168 (*thisresplen > *thisanssiz)
1169 ? *thisanssiz : *thisresplen);
1170 goto wait;
1172 if (!(statp->options & RES_INSECURE1) &&
1173 !res_ourserver_p(statp, &from)) {
1175 * response from wrong server? ignore it.
1176 * XXX - potential security hazard could
1177 * be detected here.
1179 DprintQ((statp->options & RES_DEBUG) ||
1180 (statp->pfcode & RES_PRF_REPLY),
1181 (stdout, ";; not our server:\n"),
1182 thisansp,
1183 (*thisresplen > *thisanssiz)
1184 ? *thisanssiz : *thisresplen);
1185 goto wait;
1187 #ifdef RES_USE_EDNS0
1188 if (anhp->rcode == FORMERR
1189 && (statp->options & RES_USE_EDNS0) != 0U) {
1191 * Do not retry if the server does not understand
1192 * EDNS0. The case has to be captured here, as
1193 * FORMERR packet do not carry query section, hence
1194 * res_queriesmatch() returns 0.
1196 DprintQ(statp->options & RES_DEBUG,
1197 (stdout,
1198 "server rejected query with EDNS0:\n"),
1199 thisans,
1200 (*thisresplen > *thisanssiz)
1201 ? *thisanssiz : *thisresplen);
1202 /* record the error */
1203 statp->_flags |= RES_F_EDNS0ERR;
1204 goto err_out;
1206 #endif
1207 if (!(statp->options & RES_INSECURE2)
1208 && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
1209 *thisansp,
1210 *thisansp
1211 + *thisanssizp))
1212 && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
1213 *thisansp,
1214 *thisansp
1215 + *thisanssizp))) {
1217 * response contains wrong query? ignore it.
1218 * XXX - potential security hazard could
1219 * be detected here.
1221 DprintQ((statp->options & RES_DEBUG) ||
1222 (statp->pfcode & RES_PRF_REPLY),
1223 (stdout, ";; wrong query name:\n"),
1224 thisansp,
1225 (*thisresplen > *thisanssiz)
1226 ? *thisanssiz : *thisresplen);
1227 goto wait;
1229 if (anhp->rcode == SERVFAIL ||
1230 anhp->rcode == NOTIMP ||
1231 anhp->rcode == REFUSED) {
1232 DprintQ(statp->options & RES_DEBUG,
1233 (stdout, "server rejected query:\n"),
1234 thisansp,
1235 (*thisresplen > *thisanssiz)
1236 ? *thisanssiz : *thisresplen);
1238 if (recvresp1 || (buf2 != NULL && recvresp2))
1240 *resplen2 = 1;
1241 return resplen;
1243 if (buf2 != NULL)
1245 /* We are waiting for a possible second reply. */
1246 resplen = 1;
1247 if (hp->id == anhp->id)
1248 recvresp1 = 1;
1249 else
1250 recvresp2 = 1;
1252 goto wait;
1255 next_ns:
1256 __res_iclose(statp, false);
1257 /* don't retry if called from dig */
1258 if (!statp->pfcode)
1259 return (0);
1261 if (anhp->rcode == NOERROR && anhp->ancount == 0
1262 && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
1263 DprintQ(statp->options & RES_DEBUG,
1264 (stdout, "referred query:\n"),
1265 thisansp,
1266 (*thisresplen > *thisanssiz)
1267 ? *thisanssiz : *thisresplen);
1268 goto next_ns;
1270 if (!(statp->options & RES_IGNTC) && anhp->tc) {
1272 * To get the rest of answer,
1273 * use TCP with same server.
1275 Dprint(statp->options & RES_DEBUG,
1276 (stdout, ";; truncated answer\n"));
1277 *v_circuit = 1;
1278 __res_iclose(statp, false);
1279 // XXX if we have received one reply we could
1280 // XXX use it and not repeat it over TCP...
1281 return (1);
1283 /* Mark which reply we received. */
1284 if (recvresp1 == 0 && hp->id == anhp->id)
1285 recvresp1 = 1;
1286 else
1287 recvresp2 = 1;
1288 /* Repeat waiting if we have a second answer to arrive. */
1289 if ((recvresp1 & recvresp2) == 0)
1290 goto wait;
1292 * All is well, or the error is fatal. Signal that the
1293 * next nameserver ought not be tried.
1295 return (resplen);
1296 } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1297 /* Something went wrong. We can stop trying. */
1298 goto err_out;
1300 else {
1301 /* poll should not have returned > 0 in this case. */
1302 abort ();
1306 #ifdef DEBUG
1307 static void
1308 Aerror(const res_state statp, FILE *file, const char *string, int error,
1309 const struct sockaddr *address)
1311 int save = errno;
1313 if ((statp->options & RES_DEBUG) != 0) {
1314 char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
1316 fprintf(file, "res_send: %s ([%s].%u): %s\n",
1317 string,
1318 (address->sa_family == AF_INET
1319 ? inet_ntop(address->sa_family,
1320 &((const struct sockaddr_in *) address)->sin_addr,
1321 tmp, sizeof tmp)
1322 : inet_ntop(address->sa_family,
1323 &((const struct sockaddr_in6 *) address)->sin6_addr,
1324 tmp, sizeof tmp)),
1325 (address->sa_family == AF_INET
1326 ? ntohs(((struct sockaddr_in *) address)->sin_port)
1327 : address->sa_family == AF_INET6
1328 ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
1329 : 0),
1330 strerror(error));
1332 __set_errno (save);
1335 static void
1336 Perror(const res_state statp, FILE *file, const char *string, int error) {
1337 int save = errno;
1339 if ((statp->options & RES_DEBUG) != 0)
1340 fprintf(file, "res_send: %s: %s\n",
1341 string, strerror(error));
1342 __set_errno (save);
1344 #endif
1346 static int
1347 sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
1348 if (a1->sin6_family == a2->sin6_family) {
1349 if (a1->sin6_family == AF_INET)
1350 return ((((struct sockaddr_in *)a1)->sin_port ==
1351 ((struct sockaddr_in *)a2)->sin_port) &&
1352 (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
1353 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1354 else
1355 return ((a1->sin6_port == a2->sin6_port) &&
1356 !memcmp(&a1->sin6_addr, &a2->sin6_addr,
1357 sizeof (struct in6_addr)));
1359 if (a1->sin6_family == AF_INET) {
1360 struct sockaddr_in6 *sap = a1;
1361 a1 = a2;
1362 a2 = sap;
1363 } /* assumes that AF_INET and AF_INET6 are the only possibilities */
1364 return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
1365 IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
1366 (a1->sin6_addr.s6_addr32[3] ==
1367 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1371 * Converts IPv4 family, address and port to
1372 * IPv6 family, IPv4-mapped IPv6 address and port.
1374 static void
1375 convaddr4to6(struct sockaddr_in6 *sa)
1377 struct sockaddr_in *sa4p = (struct sockaddr_in *) sa;
1378 in_port_t port = sa4p->sin_port;
1379 in_addr_t addr = sa4p->sin_addr.s_addr;
1381 sa->sin6_family = AF_INET6;
1382 sa->sin6_port = port;
1383 sa->sin6_addr.s6_addr32[0] = 0;
1384 sa->sin6_addr.s6_addr32[1] = 0;
1385 sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
1386 sa->sin6_addr.s6_addr32[3] = addr;