Commit | Line | Data |
---|---|---|
51db6920 VM |
1 | Index: b/resolv/nss_dns/dns-host.c |
2 | =================================================================== | |
3 | --- a/resolv/nss_dns/dns-host.c | |
4 | +++ b/resolv/nss_dns/dns-host.c | |
5 | @@ -1031,7 +1031,10 @@ gaih_getanswer_slice (const querybuf *an | |
6 | int h_namelen = 0; | |
7 | ||
8 | if (ancount == 0) | |
9 | - return NSS_STATUS_NOTFOUND; | |
10 | + { | |
11 | + *h_errnop = HOST_NOT_FOUND; | |
12 | + return NSS_STATUS_NOTFOUND; | |
13 | + } | |
14 | ||
15 | while (ancount-- > 0 && cp < end_of_message && had_error == 0) | |
16 | { | |
17 | @@ -1208,7 +1211,14 @@ gaih_getanswer_slice (const querybuf *an | |
18 | /* Special case here: if the resolver sent a result but it only | |
19 | contains a CNAME while we are looking for a T_A or T_AAAA record, | |
20 | we fail with NOTFOUND instead of TRYAGAIN. */ | |
21 | - return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; | |
22 | + if (canon != NULL) | |
23 | + { | |
24 | + *h_errnop = HOST_NOT_FOUND; | |
25 | + return NSS_STATUS_NOTFOUND; | |
26 | + } | |
27 | + | |
28 | + *h_errnop = NETDB_INTERNAL; | |
29 | + return NSS_STATUS_TRYAGAIN; | |
30 | } | |
31 | ||
32 | ||
33 | @@ -1222,11 +1232,101 @@ gaih_getanswer (const querybuf *answer1, | |
34 | ||
35 | enum nss_status status = NSS_STATUS_NOTFOUND; | |
36 | ||
37 | + /* Combining the NSS status of two distinct queries requires some | |
38 | + compromise and attention to symmetry (A or AAAA queries can be | |
39 | + returned in any order). What follows is a breakdown of how this | |
40 | + code is expected to work and why. We discuss only SUCCESS, | |
41 | + TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns | |
42 | + that apply (though RETURN and MERGE exist). We make a distinction | |
43 | + between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). | |
44 | + A recoverable TRYAGAIN is almost always due to buffer size issues | |
45 | + and returns ERANGE in errno and the caller is expected to retry | |
46 | + with a larger buffer. | |
47 | + | |
48 | + Lastly, you may be tempted to make significant changes to the | |
49 | + conditions in this code to bring about symmetry between responses. | |
50 | + Please don't change anything without due consideration for | |
51 | + expected application behaviour. Some of the synthesized responses | |
52 | + aren't very well thought out and sometimes appear to imply that | |
53 | + IPv4 responses are always answer 1, and IPv6 responses are always | |
54 | + answer 2, but that's not true (see the implemetnation of send_dg | |
55 | + and send_vc to see response can arrive in any order, particlarly | |
56 | + for UDP). However, we expect it holds roughly enough of the time | |
57 | + that this code works, but certainly needs to be fixed to make this | |
58 | + a more robust implementation. | |
59 | + | |
60 | + ---------------------------------------------- | |
61 | + | Answer 1 Status / | Synthesized | Reason | | |
62 | + | Answer 2 Status | Status | | | |
63 | + |--------------------------------------------| | |
64 | + | SUCCESS/SUCCESS | SUCCESS | [1] | | |
65 | + | SUCCESS/TRYAGAIN | TRYAGAIN | [5] | | |
66 | + | SUCCESS/TRYAGAIN' | SUCCESS | [1] | | |
67 | + | SUCCESS/NOTFOUND | SUCCESS | [1] | | |
68 | + | SUCCESS/UNAVAIL | SUCCESS | [1] | | |
69 | + | TRYAGAIN/SUCCESS | TRYAGAIN | [2] | | |
70 | + | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] | | |
71 | + | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] | | |
72 | + | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] | | |
73 | + | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] | | |
74 | + | TRYAGAIN'/SUCCESS | SUCCESS | [3] | | |
75 | + | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] | | |
76 | + | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] | | |
77 | + | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] | | |
78 | + | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] | | |
79 | + | NOTFOUND/SUCCESS | SUCCESS | [3] | | |
80 | + | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] | | |
81 | + | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] | | |
82 | + | NOTFOUND/NOTFOUND | NOTFOUND | [3] | | |
83 | + | NOTFOUND/UNAVAIL | UNAVAIL | [3] | | |
84 | + | UNAVAIL/SUCCESS | UNAVAIL | [4] | | |
85 | + | UNAVAIL/TRYAGAIN | UNAVAIL | [4] | | |
86 | + | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] | | |
87 | + | UNAVAIL/NOTFOUND | UNAVAIL | [4] | | |
88 | + | UNAVAIL/UNAVAIL | UNAVAIL | [4] | | |
89 | + ---------------------------------------------- | |
90 | + | |
91 | + [1] If the first response is a success we return success. | |
92 | + This ignores the state of the second answer and in fact | |
93 | + incorrectly sets errno and h_errno to that of the second | |
94 | + answer. However because the response is a success we ignore | |
95 | + *errnop and *h_errnop (though that means you touched errno on | |
96 | + success). We are being conservative here and returning the | |
97 | + likely IPv4 response in the first answer as a success. | |
98 | + | |
99 | + [2] If the first response is a recoverable TRYAGAIN we return | |
100 | + that instead of looking at the second response. The | |
101 | + expectation here is that we have failed to get an IPv4 response | |
102 | + and should retry both queries. | |
103 | + | |
104 | + [3] If the first response was not a SUCCESS and the second | |
105 | + response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN, | |
106 | + or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the | |
107 | + result from the second response, otherwise the first responses | |
108 | + status is used. Again we have some odd side-effects when the | |
109 | + second response is NOTFOUND because we overwrite *errnop and | |
110 | + *h_errnop that means that a first answer of NOTFOUND might see | |
111 | + its *errnop and *h_errnop values altered. Whether it matters | |
112 | + in practice that a first response NOTFOUND has the wrong | |
113 | + *errnop and *h_errnop is undecided. | |
114 | + | |
115 | + [4] If the first response is UNAVAIL we return that instead of | |
116 | + looking at the second response. The expectation here is that | |
117 | + it will have failed similarly e.g. configuration failure. | |
118 | + | |
119 | + [5] Testing this code is complicated by the fact that truncated | |
120 | + second response buffers might be returned as SUCCESS if the | |
121 | + first answer is a SUCCESS. To fix this we add symmetry to | |
122 | + TRYAGAIN with the second response. If the second response | |
123 | + is a recoverable error we now return TRYAGIN even if the first | |
124 | + response was SUCCESS. */ | |
125 | + | |
126 | if (anslen1 > 0) | |
127 | status = gaih_getanswer_slice(answer1, anslen1, qname, | |
128 | &pat, &buffer, &buflen, | |
129 | errnop, h_errnop, ttlp, | |
130 | &first); | |
131 | + | |
132 | if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND | |
133 | || (status == NSS_STATUS_TRYAGAIN | |
134 | /* We want to look at the second answer in case of an | |
135 | @@ -1242,8 +1342,15 @@ gaih_getanswer (const querybuf *answer1, | |
136 | &pat, &buffer, &buflen, | |
137 | errnop, h_errnop, ttlp, | |
138 | &first); | |
139 | + /* Use the second response status in some cases. */ | |
140 | if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) | |
141 | status = status2; | |
142 | + /* Do not return a truncated second response (unless it was | |
143 | + unavoidable e.g. unrecoverable TRYAGAIN). */ | |
144 | + if (status == NSS_STATUS_SUCCESS | |
145 | + && (status2 == NSS_STATUS_TRYAGAIN | |
146 | + && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) | |
147 | + status = NSS_STATUS_TRYAGAIN; | |
148 | } | |
149 | ||
150 | return status; | |
151 | Index: b/resolv/res_query.c | |
152 | =================================================================== | |
153 | --- a/resolv/res_query.c | |
154 | +++ b/resolv/res_query.c | |
155 | @@ -396,6 +396,7 @@ __libc_res_nsearch(res_state statp, | |
156 | { | |
157 | free (*answerp2); | |
158 | *answerp2 = NULL; | |
159 | + *nanswerp2 = 0; | |
160 | *answerp2_malloced = 0; | |
161 | } | |
162 | } | |
163 | @@ -447,6 +448,7 @@ __libc_res_nsearch(res_state statp, | |
164 | { | |
165 | free (*answerp2); | |
166 | *answerp2 = NULL; | |
167 | + *nanswerp2 = 0; | |
168 | *answerp2_malloced = 0; | |
169 | } | |
170 | ||
171 | @@ -521,6 +523,7 @@ __libc_res_nsearch(res_state statp, | |
172 | { | |
173 | free (*answerp2); | |
174 | *answerp2 = NULL; | |
175 | + *nanswerp2 = 0; | |
176 | *answerp2_malloced = 0; | |
177 | } | |
178 | if (saved_herrno != -1) | |
179 | Index: b/resolv/res_send.c | |
180 | =================================================================== | |
181 | --- a/resolv/res_send.c | |
182 | +++ b/resolv/res_send.c | |
183 | @@ -1,3 +1,20 @@ | |
184 | +/* Copyright (C) 2016 Free Software Foundation, Inc. | |
185 | + This file is part of the GNU C Library. | |
186 | + | |
187 | + The GNU C Library is free software; you can redistribute it and/or | |
188 | + modify it under the terms of the GNU Lesser General Public | |
189 | + License as published by the Free Software Foundation; either | |
190 | + version 2.1 of the License, or (at your option) any later version. | |
191 | + | |
192 | + The GNU C Library is distributed in the hope that it will be useful, | |
193 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
194 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
195 | + Lesser General Public License for more details. | |
196 | + | |
197 | + You should have received a copy of the GNU Lesser General Public | |
198 | + License along with the GNU C Library; if not, see | |
199 | + <http://www.gnu.org/licenses/>. */ | |
200 | + | |
201 | /* | |
202 | * Copyright (c) 1985, 1989, 1993 | |
203 | * The Regents of the University of California. All rights reserved. | |
204 | @@ -361,6 +378,8 @@ __libc_res_nsend(res_state statp, const | |
205 | #ifdef USE_HOOKS | |
206 | if (__glibc_unlikely (statp->qhook || statp->rhook)) { | |
207 | if (anssiz < MAXPACKET && ansp) { | |
208 | + /* Always allocate MAXPACKET, callers expect | |
209 | + this specific size. */ | |
210 | u_char *buf = malloc (MAXPACKET); | |
211 | if (buf == NULL) | |
212 | return (-1); | |
213 | @@ -660,6 +679,77 @@ libresolv_hidden_def (res_nsend) | |
214 | ||
215 | /* Private */ | |
216 | ||
217 | +/* The send_vc function is responsible for sending a DNS query over TCP | |
218 | + to the nameserver numbered NS from the res_state STATP i.e. | |
219 | + EXT(statp).nssocks[ns]. The function supports sending both IPv4 and | |
220 | + IPv6 queries at the same serially on the same socket. | |
221 | + | |
222 | + Please note that for TCP there is no way to disable sending both | |
223 | + queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP | |
224 | + and sends the queries serially and waits for the result after each | |
225 | + sent query. This implemetnation should be corrected to honour these | |
226 | + options. | |
227 | + | |
228 | + Please also note that for TCP we send both queries over the same | |
229 | + socket one after another. This technically violates best practice | |
230 | + since the server is allowed to read the first query, respond, and | |
231 | + then close the socket (to service another client). If the server | |
232 | + does this, then the remaining second query in the socket data buffer | |
233 | + will cause the server to send the client an RST which will arrive | |
234 | + asynchronously and the client's OS will likely tear down the socket | |
235 | + receive buffer resulting in a potentially short read and lost | |
236 | + response data. This will force the client to retry the query again, | |
237 | + and this process may repeat until all servers and connection resets | |
238 | + are exhausted and then the query will fail. It's not known if this | |
239 | + happens with any frequency in real DNS server implementations. This | |
240 | + implementation should be corrected to use two sockets by default for | |
241 | + parallel queries. | |
242 | + | |
243 | + The query stored in BUF of BUFLEN length is sent first followed by | |
244 | + the query stored in BUF2 of BUFLEN2 length. Queries are sent | |
245 | + serially on the same socket. | |
246 | + | |
247 | + Answers to the query are stored firstly in *ANSP up to a max of | |
248 | + *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP | |
249 | + is non-NULL (to indicate that modifying the answer buffer is allowed) | |
250 | + then malloc is used to allocate a new response buffer and ANSCP and | |
251 | + ANSP will both point to the new buffer. If more than *ANSSIZP bytes | |
252 | + are needed but ANSCP is NULL, then as much of the response as | |
253 | + possible is read into the buffer, but the results will be truncated. | |
254 | + When truncation happens because of a small answer buffer the DNS | |
255 | + packets header feild TC will bet set to 1, indicating a truncated | |
256 | + message and the rest of the socket data will be read and discarded. | |
257 | + | |
258 | + Answers to the query are stored secondly in *ANSP2 up to a max of | |
259 | + *ANSSIZP2 bytes, with the actual response length stored in | |
260 | + *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2 | |
261 | + is non-NULL (required for a second query) then malloc is used to | |
262 | + allocate a new response buffer, *ANSSIZP2 is set to the new buffer | |
263 | + size and *ANSP2_MALLOCED is set to 1. | |
264 | + | |
265 | + The ANSP2_MALLOCED argument will eventually be removed as the | |
266 | + change in buffer pointer can be used to detect the buffer has | |
267 | + changed and that the caller should use free on the new buffer. | |
268 | + | |
269 | + Note that the answers may arrive in any order from the server and | |
270 | + therefore the first and second answer buffers may not correspond to | |
271 | + the first and second queries. | |
272 | + | |
273 | + It is not supported to call this function with a non-NULL ANSP2 | |
274 | + but a NULL ANSCP. Put another way, you can call send_vc with a | |
275 | + single unmodifiable buffer or two modifiable buffers, but no other | |
276 | + combination is supported. | |
277 | + | |
278 | + It is the caller's responsibility to free the malloc allocated | |
279 | + buffers by detecting that the pointers have changed from their | |
280 | + original values i.e. *ANSCP or *ANSP2 has changed. | |
281 | + | |
282 | + If errors are encountered then *TERRNO is set to an appropriate | |
283 | + errno value and a zero result is returned for a recoverable error, | |
284 | + and a less-than zero result is returned for a non-recoverable error. | |
285 | + | |
286 | + If no errors are encountered then *TERRNO is left unmodified and | |
287 | + a the length of the first response in bytes is returned. */ | |
288 | static int | |
289 | send_vc(res_state statp, | |
290 | const u_char *buf, int buflen, const u_char *buf2, int buflen2, | |
291 | @@ -669,11 +759,7 @@ send_vc(res_state statp, | |
292 | { | |
293 | const HEADER *hp = (HEADER *) buf; | |
294 | const HEADER *hp2 = (HEADER *) buf2; | |
295 | - u_char *ans = *ansp; | |
296 | - int orig_anssizp = *anssizp; | |
297 | - // XXX REMOVE | |
298 | - // int anssiz = *anssizp; | |
299 | - HEADER *anhp = (HEADER *) ans; | |
300 | + HEADER *anhp = (HEADER *) *ansp; | |
301 | struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns]; | |
302 | int truncating, connreset, n; | |
303 | /* On some architectures compiler might emit a warning indicating | |
304 | @@ -766,6 +852,8 @@ send_vc(res_state statp, | |
305 | * Receive length & response | |
306 | */ | |
307 | int recvresp1 = 0; | |
308 | + /* Skip the second response if there is no second query. | |
309 | + To do that we mark the second response as received. */ | |
310 | int recvresp2 = buf2 == NULL; | |
311 | uint16_t rlen16; | |
312 | read_len: | |
313 | @@ -802,40 +890,14 @@ send_vc(res_state statp, | |
314 | u_char **thisansp; | |
315 | int *thisresplenp; | |
316 | if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { | |
317 | + /* We have not received any responses | |
318 | + yet or we only have one response to | |
319 | + receive. */ | |
320 | thisanssizp = anssizp; | |
321 | thisansp = anscp ?: ansp; | |
322 | assert (anscp != NULL || ansp2 == NULL); | |
323 | thisresplenp = &resplen; | |
324 | } else { | |
325 | - if (*anssizp != MAXPACKET) { | |
326 | - /* No buffer allocated for the first | |
327 | - reply. We can try to use the rest | |
328 | - of the user-provided buffer. */ | |
329 | -#if __GNUC_PREREQ (4, 7) | |
330 | - DIAG_PUSH_NEEDS_COMMENT; | |
331 | - DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); | |
332 | -#endif | |
333 | -#if _STRING_ARCH_unaligned | |
334 | - *anssizp2 = orig_anssizp - resplen; | |
335 | - *ansp2 = *ansp + resplen; | |
336 | -#else | |
337 | - int aligned_resplen | |
338 | - = ((resplen + __alignof__ (HEADER) - 1) | |
339 | - & ~(__alignof__ (HEADER) - 1)); | |
340 | - *anssizp2 = orig_anssizp - aligned_resplen; | |
341 | - *ansp2 = *ansp + aligned_resplen; | |
342 | -#endif | |
343 | -#if __GNUC_PREREQ (4, 7) | |
344 | - DIAG_POP_NEEDS_COMMENT; | |
345 | -#endif | |
346 | - } else { | |
347 | - /* The first reply did not fit into the | |
348 | - user-provided buffer. Maybe the second | |
349 | - answer will. */ | |
350 | - *anssizp2 = orig_anssizp; | |
351 | - *ansp2 = *ansp; | |
352 | - } | |
353 | - | |
354 | thisanssizp = anssizp2; | |
355 | thisansp = ansp2; | |
356 | thisresplenp = resplen2; | |
357 | @@ -843,10 +905,14 @@ send_vc(res_state statp, | |
358 | anhp = (HEADER *) *thisansp; | |
359 | ||
360 | *thisresplenp = rlen; | |
361 | - if (rlen > *thisanssizp) { | |
362 | - /* Yes, we test ANSCP here. If we have two buffers | |
363 | - both will be allocatable. */ | |
364 | - if (__glibc_likely (anscp != NULL)) { | |
365 | + /* Is the answer buffer too small? */ | |
366 | + if (*thisanssizp < rlen) { | |
367 | + /* If the current buffer is non-NULL and it's not | |
368 | + pointing at the static user-supplied buffer then | |
369 | + we can reallocate it. */ | |
370 | + if (thisansp != NULL && thisansp != ansp) { | |
371 | + /* Always allocate MAXPACKET, callers expect | |
372 | + this specific size. */ | |
373 | u_char *newp = malloc (MAXPACKET); | |
374 | if (newp == NULL) { | |
375 | *terrno = ENOMEM; | |
376 | @@ -858,6 +924,9 @@ send_vc(res_state statp, | |
377 | if (thisansp == ansp2) | |
378 | *ansp2_malloced = 1; | |
379 | anhp = (HEADER *) newp; | |
380 | + /* A uint16_t can't be larger than MAXPACKET | |
381 | + thus it's safe to allocate MAXPACKET but | |
382 | + read RLEN bytes instead. */ | |
383 | len = rlen; | |
384 | } else { | |
385 | Dprint(statp->options & RES_DEBUG, | |
386 | @@ -1021,6 +1090,66 @@ reopen (res_state statp, int *terrno, in | |
387 | return 1; | |
388 | } | |
389 | ||
390 | +/* The send_dg function is responsible for sending a DNS query over UDP | |
391 | + to the nameserver numbered NS from the res_state STATP i.e. | |
392 | + EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries | |
393 | + along with the ability to send the query in parallel for both stacks | |
394 | + (default) or serially (RES_SINGLKUP). It also supports serial lookup | |
395 | + with a close and reopen of the socket used to talk to the server | |
396 | + (RES_SNGLKUPREOP) to work around broken name servers. | |
397 | + | |
398 | + The query stored in BUF of BUFLEN length is sent first followed by | |
399 | + the query stored in BUF2 of BUFLEN2 length. Queries are sent | |
400 | + in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP). | |
401 | + | |
402 | + Answers to the query are stored firstly in *ANSP up to a max of | |
403 | + *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP | |
404 | + is non-NULL (to indicate that modifying the answer buffer is allowed) | |
405 | + then malloc is used to allocate a new response buffer and ANSCP and | |
406 | + ANSP will both point to the new buffer. If more than *ANSSIZP bytes | |
407 | + are needed but ANSCP is NULL, then as much of the response as | |
408 | + possible is read into the buffer, but the results will be truncated. | |
409 | + When truncation happens because of a small answer buffer the DNS | |
410 | + packets header feild TC will bet set to 1, indicating a truncated | |
411 | + message, while the rest of the UDP packet is discarded. | |
412 | + | |
413 | + Answers to the query are stored secondly in *ANSP2 up to a max of | |
414 | + *ANSSIZP2 bytes, with the actual response length stored in | |
415 | + *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2 | |
416 | + is non-NULL (required for a second query) then malloc is used to | |
417 | + allocate a new response buffer, *ANSSIZP2 is set to the new buffer | |
418 | + size and *ANSP2_MALLOCED is set to 1. | |
419 | + | |
420 | + The ANSP2_MALLOCED argument will eventually be removed as the | |
421 | + change in buffer pointer can be used to detect the buffer has | |
422 | + changed and that the caller should use free on the new buffer. | |
423 | + | |
424 | + Note that the answers may arrive in any order from the server and | |
425 | + therefore the first and second answer buffers may not correspond to | |
426 | + the first and second queries. | |
427 | + | |
428 | + It is not supported to call this function with a non-NULL ANSP2 | |
429 | + but a NULL ANSCP. Put another way, you can call send_vc with a | |
430 | + single unmodifiable buffer or two modifiable buffers, but no other | |
431 | + combination is supported. | |
432 | + | |
433 | + It is the caller's responsibility to free the malloc allocated | |
434 | + buffers by detecting that the pointers have changed from their | |
435 | + original values i.e. *ANSCP or *ANSP2 has changed. | |
436 | + | |
437 | + If an answer is truncated because of UDP datagram DNS limits then | |
438 | + *V_CIRCUIT is set to 1 and the return value non-zero to indicate to | |
439 | + the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1 | |
440 | + if any progress was made reading a response from the nameserver and | |
441 | + is used by the caller to distinguish between ECONNREFUSED and | |
442 | + ETIMEDOUT (the latter if *GOTSOMEWHERE is 1). | |
443 | + | |
444 | + If errors are encountered then *TERRNO is set to an appropriate | |
445 | + errno value and a zero result is returned for a recoverable error, | |
446 | + and a less-than zero result is returned for a non-recoverable error. | |
447 | + | |
448 | + If no errors are encountered then *TERRNO is left unmodified and | |
449 | + a the length of the first response in bytes is returned. */ | |
450 | static int | |
451 | send_dg(res_state statp, | |
452 | const u_char *buf, int buflen, const u_char *buf2, int buflen2, | |
453 | @@ -1030,8 +1159,6 @@ send_dg(res_state statp, | |
454 | { | |
455 | const HEADER *hp = (HEADER *) buf; | |
456 | const HEADER *hp2 = (HEADER *) buf2; | |
457 | - u_char *ans = *ansp; | |
458 | - int orig_anssizp = *anssizp; | |
459 | struct timespec now, timeout, finish; | |
460 | struct pollfd pfd[1]; | |
461 | int ptimeout; | |
462 | @@ -1064,6 +1191,8 @@ send_dg(res_state statp, | |
463 | int need_recompute = 0; | |
464 | int nwritten = 0; | |
465 | int recvresp1 = 0; | |
466 | + /* Skip the second response if there is no second query. | |
467 | + To do that we mark the second response as received. */ | |
468 | int recvresp2 = buf2 == NULL; | |
469 | pfd[0].fd = EXT(statp).nssocks[ns]; | |
470 | pfd[0].events = POLLOUT; | |
471 | @@ -1227,55 +1356,56 @@ send_dg(res_state statp, | |
472 | int *thisresplenp; | |
473 | ||
474 | if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { | |
475 | + /* We have not received any responses | |
476 | + yet or we only have one response to | |
477 | + receive. */ | |
478 | thisanssizp = anssizp; | |
479 | thisansp = anscp ?: ansp; | |
480 | assert (anscp != NULL || ansp2 == NULL); | |
481 | thisresplenp = &resplen; | |
482 | } else { | |
483 | - if (*anssizp != MAXPACKET) { | |
484 | - /* No buffer allocated for the first | |
485 | - reply. We can try to use the rest | |
486 | - of the user-provided buffer. */ | |
487 | -#if _STRING_ARCH_unaligned | |
488 | - *anssizp2 = orig_anssizp - resplen; | |
489 | - *ansp2 = *ansp + resplen; | |
490 | -#else | |
491 | - int aligned_resplen | |
492 | - = ((resplen + __alignof__ (HEADER) - 1) | |
493 | - & ~(__alignof__ (HEADER) - 1)); | |
494 | - *anssizp2 = orig_anssizp - aligned_resplen; | |
495 | - *ansp2 = *ansp + aligned_resplen; | |
496 | -#endif | |
497 | - } else { | |
498 | - /* The first reply did not fit into the | |
499 | - user-provided buffer. Maybe the second | |
500 | - answer will. */ | |
501 | - *anssizp2 = orig_anssizp; | |
502 | - *ansp2 = *ansp; | |
503 | - } | |
504 | - | |
505 | thisanssizp = anssizp2; | |
506 | thisansp = ansp2; | |
507 | thisresplenp = resplen2; | |
508 | } | |
509 | ||
510 | if (*thisanssizp < MAXPACKET | |
511 | - /* Yes, we test ANSCP here. If we have two buffers | |
512 | - both will be allocatable. */ | |
513 | - && anscp | |
514 | + /* If the current buffer is non-NULL and it's not | |
515 | + pointing at the static user-supplied buffer then | |
516 | + we can reallocate it. */ | |
517 | + && (thisansp != NULL && thisansp != ansp) | |
518 | #ifdef FIONREAD | |
519 | + /* Is the size too small? */ | |
520 | && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 | |
521 | || *thisanssizp < *thisresplenp) | |
522 | #endif | |
523 | ) { | |
524 | + /* Always allocate MAXPACKET, callers expect | |
525 | + this specific size. */ | |
526 | u_char *newp = malloc (MAXPACKET); | |
527 | if (newp != NULL) { | |
528 | - *anssizp = MAXPACKET; | |
529 | - *thisansp = ans = newp; | |
530 | + *thisanssizp = MAXPACKET; | |
531 | + *thisansp = newp; | |
532 | if (thisansp == ansp2) | |
533 | *ansp2_malloced = 1; | |
534 | } | |
535 | } | |
536 | + /* We could end up with truncation if anscp was NULL | |
537 | + (not allowed to change caller's buffer) and the | |
538 | + response buffer size is too small. This isn't a | |
539 | + reliable way to detect truncation because the ioctl | |
540 | + may be an inaccurate report of the UDP message size. | |
541 | + Therefore we use this only to issue debug output. | |
542 | + To do truncation accurately with UDP we need | |
543 | + MSG_TRUNC which is only available on Linux. We | |
544 | + can abstract out the Linux-specific feature in the | |
545 | + future to detect truncation. */ | |
546 | + if (__glibc_unlikely (*thisanssizp < *thisresplenp)) { | |
547 | + Dprint(statp->options & RES_DEBUG, | |
548 | + (stdout, ";; response may be truncated (UDP)\n") | |
549 | + ); | |
550 | + } | |
551 | + | |
552 | HEADER *anhp = (HEADER *) *thisansp; | |
553 | socklen_t fromlen = sizeof(struct sockaddr_in6); | |
554 | assert (sizeof(from) <= fromlen); | |
555 |