1 #include <sys/socket.h>
2 #include <netinet/in.h>
13 #include "stdio_impl.h"
17 static void cleanup(void *p
)
19 __syscall(SYS_close
, (intptr_t)p
);
22 static unsigned long mtime()
25 clock_gettime(CLOCK_REALTIME
, &ts
);
26 return (unsigned long)ts
.tv_sec
* 1000
27 + ts
.tv_nsec
/ 1000000;
30 int __res_msend_rc(int nqueries
, const unsigned char *const *queries
,
31 const int *qlens
, unsigned char *const *answers
, int *alens
, int asize
,
32 const struct resolvconf
*conf
)
35 int timeout
, attempts
, retry_interval
, servfail_retry
;
37 struct sockaddr_in sin
;
38 struct sockaddr_in6 sin6
;
39 } sa
= {0}, ns
[MAXNS
] = {{0}};
40 socklen_t sl
= sizeof sa
.sin
;
48 unsigned long t0
, t1
, t2
;
50 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
52 timeout
= 1000*conf
->timeout
;
53 attempts
= conf
->attempts
;
55 for (nns
=0; nns
<conf
->nns
; nns
++) {
56 const struct address
*iplit
= &conf
->ns
[nns
];
57 if (iplit
->family
== AF_INET
) {
58 memcpy(&ns
[nns
].sin
.sin_addr
, iplit
->addr
, 4);
59 ns
[nns
].sin
.sin_port
= htons(53);
60 ns
[nns
].sin
.sin_family
= AF_INET
;
63 memcpy(&ns
[nns
].sin6
.sin6_addr
, iplit
->addr
, 16);
64 ns
[nns
].sin6
.sin6_port
= htons(53);
65 ns
[nns
].sin6
.sin6_scope_id
= iplit
->scopeid
;
66 ns
[nns
].sin6
.sin6_family
= family
= AF_INET6
;
70 /* Get local address and open/bind a socket */
71 sa
.sin
.sin_family
= family
;
72 fd
= socket(family
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
74 /* Handle case where system lacks IPv6 support */
75 if (fd
< 0 && family
== AF_INET6
&& errno
== EAFNOSUPPORT
) {
76 fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
79 if (fd
< 0 || bind(fd
, (void *)&sa
, sl
) < 0) {
80 if (fd
>= 0) close(fd
);
81 pthread_setcancelstate(cs
, 0);
85 /* Past this point, there are no errors. Each individual query will
86 * yield either no reply (indicated by zero length) or an answer
87 * packet which is up to the caller to interpret. */
89 pthread_cleanup_push(cleanup
, (void *)(intptr_t)fd
);
90 pthread_setcancelstate(cs
, 0);
92 /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
93 if (family
== AF_INET6
) {
94 setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &(int){0}, sizeof 0);
95 for (i
=0; i
<nns
; i
++) {
96 if (ns
[i
].sin
.sin_family
!= AF_INET
) continue;
97 memcpy(ns
[i
].sin6
.sin6_addr
.s6_addr
+12,
98 &ns
[i
].sin
.sin_addr
, 4);
99 memcpy(ns
[i
].sin6
.sin6_addr
.s6_addr
,
100 "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
101 ns
[i
].sin6
.sin6_family
= AF_INET6
;
102 ns
[i
].sin6
.sin6_flowinfo
= 0;
103 ns
[i
].sin6
.sin6_scope_id
= 0;
107 memset(alens
, 0, sizeof *alens
* nqueries
);
111 retry_interval
= timeout
/ attempts
;
114 t1
= t2
- retry_interval
;
116 for (; t2
-t0
< timeout
; t2
=mtime()) {
117 if (t2
-t1
>= retry_interval
) {
118 /* Query all configured namservers in parallel */
119 for (i
=0; i
<nqueries
; i
++)
121 for (j
=0; j
<nns
; j
++)
122 sendto(fd
, queries
[i
],
123 qlens
[i
], MSG_NOSIGNAL
,
126 servfail_retry
= 2 * nqueries
;
129 /* Wait for a response, or until time to retry */
130 if (poll(&pfd
, 1, t1
+retry_interval
-t2
) <= 0) continue;
132 while ((rlen
= recvfrom(fd
, answers
[next
], asize
, 0,
133 (void *)&sa
, (socklen_t
[1]){sl
})) >= 0) {
135 /* Ignore non-identifiable packets */
136 if (rlen
< 4) continue;
138 /* Ignore replies from addresses we didn't send to */
139 for (j
=0; j
<nns
&& memcmp(ns
+j
, &sa
, sl
); j
++);
140 if (j
==nns
) continue;
142 /* Find which query this answer goes with, if any */
143 for (i
=next
; i
<nqueries
&& (
144 answers
[next
][0] != queries
[i
][0] ||
145 answers
[next
][1] != queries
[i
][1] ); i
++);
146 if (i
==nqueries
) continue;
147 if (alens
[i
]) continue;
149 /* Only accept positive or negative responses;
150 * retry immediately on server failure, and ignore
151 * all other codes such as refusal. */
152 switch (answers
[next
][3] & 15) {
157 if (servfail_retry
&& servfail_retry
--)
158 sendto(fd
, queries
[i
],
159 qlens
[i
], MSG_NOSIGNAL
,
165 /* Store answer in the right slot, or update next
166 * available temp slot if it's already in place. */
169 for (; next
<nqueries
&& alens
[next
]; next
++);
171 memcpy(answers
[i
], answers
[next
], rlen
);
173 if (next
== nqueries
) goto out
;
177 pthread_cleanup_pop(1);
182 int __res_msend(int nqueries
, const unsigned char *const *queries
,
183 const int *qlens
, unsigned char *const *answers
, int *alens
, int asize
)
185 struct resolvconf conf
;
186 if (__get_resolv_conf(&conf
, 0, 0) < 0) return -1;
187 return __res_msend_rc(nqueries
, queries
, qlens
, answers
, alens
, asize
, &conf
);