]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
1 | Index: glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c |
2 | =================================================================== | |
3 | --- glibc-2.12-2-gc4ccff1.orig/resolv/nss_dns/dns-host.c | |
4 | +++ glibc-2.12-2-gc4ccff1/resolv/nss_dns/dns-host.c | |
5 | @@ -1043,7 +1043,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 | @@ -1217,7 +1220,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 | @@ -1231,11 +1241,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 | && (*errnop != ERANGE || *h_errnop == NO_RECOVERY))) | |
135 | @@ -1245,8 +1345,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: glibc-2.12-2-gc4ccff1/resolv/res_send.c | |
152 | =================================================================== | |
153 | --- glibc-2.12-2-gc4ccff1.orig/resolv/res_send.c | |
154 | +++ glibc-2.12-2-gc4ccff1/resolv/res_send.c | |
155 | @@ -1,3 +1,20 @@ | |
156 | +/* Copyright (C) 2016 Free Software Foundation, Inc. | |
157 | + This file is part of the GNU C Library. | |
158 | + | |
159 | + The GNU C Library is free software; you can redistribute it and/or | |
160 | + modify it under the terms of the GNU Lesser General Public | |
161 | + License as published by the Free Software Foundation; either | |
162 | + version 2.1 of the License, or (at your option) any later version. | |
163 | + | |
164 | + The GNU C Library is distributed in the hope that it will be useful, | |
165 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
166 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
167 | + Lesser General Public License for more details. | |
168 | + | |
169 | + You should have received a copy of the GNU Lesser General Public | |
170 | + License along with the GNU C Library; if not, see | |
171 | + <http://www.gnu.org/licenses/>. */ | |
172 | + | |
173 | /* | |
174 | * Copyright (c) 1985, 1989, 1993 | |
175 | * The Regents of the University of California. All rights reserved. | |
176 | @@ -360,6 +377,8 @@ __libc_res_nsend(res_state statp, const | |
177 | #ifdef USE_HOOKS | |
178 | if (__builtin_expect (statp->qhook || statp->rhook, 0)) { | |
179 | if (anssiz < MAXPACKET && ansp) { | |
180 | + /* Always allocate MAXPACKET, callers expect | |
181 | + this specific size. */ | |
182 | u_char *buf = malloc (MAXPACKET); | |
183 | if (buf == NULL) | |
184 | return (-1); | |
185 | @@ -652,6 +671,77 @@ libresolv_hidden_def (res_nsend) | |
186 | ||
187 | /* Private */ | |
188 | ||
189 | +/* The send_vc function is responsible for sending a DNS query over TCP | |
190 | + to the nameserver numbered NS from the res_state STATP i.e. | |
191 | + EXT(statp).nssocks[ns]. The function supports sending both IPv4 and | |
192 | + IPv6 queries at the same serially on the same socket. | |
193 | + | |
194 | + Please note that for TCP there is no way to disable sending both | |
195 | + queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP | |
196 | + and sends the queries serially and waits for the result after each | |
197 | + sent query. This implemetnation should be corrected to honour these | |
198 | + options. | |
199 | + | |
200 | + Please also note that for TCP we send both queries over the same | |
201 | + socket one after another. This technically violates best practice | |
202 | + since the server is allowed to read the first query, respond, and | |
203 | + then close the socket (to service another client). If the server | |
204 | + does this, then the remaining second query in the socket data buffer | |
205 | + will cause the server to send the client an RST which will arrive | |
206 | + asynchronously and the client's OS will likely tear down the socket | |
207 | + receive buffer resulting in a potentially short read and lost | |
208 | + response data. This will force the client to retry the query again, | |
209 | + and this process may repeat until all servers and connection resets | |
210 | + are exhausted and then the query will fail. It's not known if this | |
211 | + happens with any frequency in real DNS server implementations. This | |
212 | + implementation should be corrected to use two sockets by default for | |
213 | + parallel queries. | |
214 | + | |
215 | + The query stored in BUF of BUFLEN length is sent first followed by | |
216 | + the query stored in BUF2 of BUFLEN2 length. Queries are sent | |
217 | + serially on the same socket. | |
218 | + | |
219 | + Answers to the query are stored firstly in *ANSP up to a max of | |
220 | + *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP | |
221 | + is non-NULL (to indicate that modifying the answer buffer is allowed) | |
222 | + then malloc is used to allocate a new response buffer and ANSCP and | |
223 | + ANSP will both point to the new buffer. If more than *ANSSIZP bytes | |
224 | + are needed but ANSCP is NULL, then as much of the response as | |
225 | + possible is read into the buffer, but the results will be truncated. | |
226 | + When truncation happens because of a small answer buffer the DNS | |
227 | + packets header feild TC will bet set to 1, indicating a truncated | |
228 | + message and the rest of the socket data will be read and discarded. | |
229 | + | |
230 | + Answers to the query are stored secondly in *ANSP2 up to a max of | |
231 | + *ANSSIZP2 bytes, with the actual response length stored in | |
232 | + *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2 | |
233 | + is non-NULL (required for a second query) then malloc is used to | |
234 | + allocate a new response buffer, *ANSSIZP2 is set to the new buffer | |
235 | + size and *ANSP2_MALLOCED is set to 1. | |
236 | + | |
237 | + The ANSP2_MALLOCED argument will eventually be removed as the | |
238 | + change in buffer pointer can be used to detect the buffer has | |
239 | + changed and that the caller should use free on the new buffer. | |
240 | + | |
241 | + Note that the answers may arrive in any order from the server and | |
242 | + therefore the first and second answer buffers may not correspond to | |
243 | + the first and second queries. | |
244 | + | |
245 | + It is not supported to call this function with a non-NULL ANSP2 | |
246 | + but a NULL ANSCP. Put another way, you can call send_vc with a | |
247 | + single unmodifiable buffer or two modifiable buffers, but no other | |
248 | + combination is supported. | |
249 | + | |
250 | + It is the caller's responsibility to free the malloc allocated | |
251 | + buffers by detecting that the pointers have changed from their | |
252 | + original values i.e. *ANSCP or *ANSP2 has changed. | |
253 | + | |
254 | + If errors are encountered then *TERRNO is set to an appropriate | |
255 | + errno value and a zero result is returned for a recoverable error, | |
256 | + and a less-than zero result is returned for a non-recoverable error. | |
257 | + | |
258 | + If no errors are encountered then *TERRNO is left unmodified and | |
259 | + a the length of the first response in bytes is returned. */ | |
260 | static int | |
261 | send_vc(res_state statp, | |
262 | const u_char *buf, int buflen, const u_char *buf2, int buflen2, | |
263 | @@ -661,11 +751,7 @@ send_vc(res_state statp, | |
264 | { | |
265 | const HEADER *hp = (HEADER *) buf; | |
266 | const HEADER *hp2 = (HEADER *) buf2; | |
267 | - u_char *ans = *ansp; | |
268 | - int orig_anssizp = *anssizp; | |
269 | - // XXX REMOVE | |
270 | - // int anssiz = *anssizp; | |
271 | - HEADER *anhp = (HEADER *) ans; | |
272 | + HEADER *anhp = (HEADER *) *ansp; | |
273 | struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns]; | |
274 | int truncating, connreset, resplen, n; | |
275 | struct iovec iov[4]; | |
276 | @@ -741,6 +827,8 @@ send_vc(res_state statp, | |
277 | * Receive length & response | |
278 | */ | |
279 | int recvresp1 = 0; | |
280 | + /* Skip the second response if there is no second query. | |
281 | + To do that we mark the second response as received. */ | |
282 | int recvresp2 = buf2 == NULL; | |
283 | uint16_t rlen16; | |
284 | read_len: | |
285 | @@ -777,33 +865,14 @@ send_vc(res_state statp, | |
286 | u_char **thisansp; | |
287 | int *thisresplenp; | |
288 | if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { | |
289 | + /* We have not received any responses | |
290 | + yet or we only have one response to | |
291 | + receive. */ | |
292 | thisanssizp = anssizp; | |
293 | thisansp = anscp ?: ansp; | |
294 | assert (anscp != NULL || ansp2 == NULL); | |
295 | thisresplenp = &resplen; | |
296 | } else { | |
297 | - if (*anssizp != MAXPACKET) { | |
298 | - /* No buffer allocated for the first | |
299 | - reply. We can try to use the rest | |
300 | - of the user-provided buffer. */ | |
301 | -#ifdef _STRING_ARCH_unaligned | |
302 | - *anssizp2 = orig_anssizp - resplen; | |
303 | - *ansp2 = *ansp + resplen; | |
304 | -#else | |
305 | - int aligned_resplen | |
306 | - = ((resplen + __alignof__ (HEADER) - 1) | |
307 | - & ~(__alignof__ (HEADER) - 1)); | |
308 | - *anssizp2 = orig_anssizp - aligned_resplen; | |
309 | - *ansp2 = *ansp + aligned_resplen; | |
310 | -#endif | |
311 | - } else { | |
312 | - /* The first reply did not fit into the | |
313 | - user-provided buffer. Maybe the second | |
314 | - answer will. */ | |
315 | - *anssizp2 = orig_anssizp; | |
316 | - *ansp2 = *ansp; | |
317 | - } | |
318 | - | |
319 | thisanssizp = anssizp2; | |
320 | thisansp = ansp2; | |
321 | thisresplenp = resplen2; | |
322 | @@ -811,10 +880,14 @@ send_vc(res_state statp, | |
323 | anhp = (HEADER *) *thisansp; | |
324 | ||
325 | *thisresplenp = rlen; | |
326 | - if (rlen > *thisanssizp) { | |
327 | - /* Yes, we test ANSCP here. If we have two buffers | |
328 | - both will be allocatable. */ | |
329 | - if (__builtin_expect (anscp != NULL, 1)) { | |
330 | + /* Is the answer buffer too small? */ | |
331 | + if (*thisanssizp < rlen) { | |
332 | + /* If the current buffer is non-NULL and it's not | |
333 | + pointing at the static user-supplied buffer then | |
334 | + we can reallocate it. */ | |
335 | + if (thisansp != NULL && thisansp != ansp) { | |
336 | + /* Always allocate MAXPACKET, callers expect | |
337 | + this specific size. */ | |
338 | u_char *newp = malloc (MAXPACKET); | |
339 | if (newp == NULL) { | |
340 | *terrno = ENOMEM; | |
341 | @@ -824,6 +897,9 @@ send_vc(res_state statp, | |
342 | *thisanssizp = MAXPACKET; | |
343 | *thisansp = newp; | |
344 | anhp = (HEADER *) newp; | |
345 | + /* A uint16_t can't be larger than MAXPACKET | |
346 | + thus it's safe to allocate MAXPACKET but | |
347 | + read RLEN bytes instead. */ | |
348 | len = rlen; | |
349 | } else { | |
350 | Dprint(statp->options & RES_DEBUG, | |
351 | @@ -987,6 +1063,66 @@ reopen (res_state statp, int *terrno, in | |
352 | return 1; | |
353 | } | |
354 | ||
355 | +/* The send_dg function is responsible for sending a DNS query over UDP | |
356 | + to the nameserver numbered NS from the res_state STATP i.e. | |
357 | + EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries | |
358 | + along with the ability to send the query in parallel for both stacks | |
359 | + (default) or serially (RES_SINGLKUP). It also supports serial lookup | |
360 | + with a close and reopen of the socket used to talk to the server | |
361 | + (RES_SNGLKUPREOP) to work around broken name servers. | |
362 | + | |
363 | + The query stored in BUF of BUFLEN length is sent first followed by | |
364 | + the query stored in BUF2 of BUFLEN2 length. Queries are sent | |
365 | + in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP). | |
366 | + | |
367 | + Answers to the query are stored firstly in *ANSP up to a max of | |
368 | + *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP | |
369 | + is non-NULL (to indicate that modifying the answer buffer is allowed) | |
370 | + then malloc is used to allocate a new response buffer and ANSCP and | |
371 | + ANSP will both point to the new buffer. If more than *ANSSIZP bytes | |
372 | + are needed but ANSCP is NULL, then as much of the response as | |
373 | + possible is read into the buffer, but the results will be truncated. | |
374 | + When truncation happens because of a small answer buffer the DNS | |
375 | + packets header feild TC will bet set to 1, indicating a truncated | |
376 | + message, while the rest of the UDP packet is discarded. | |
377 | + | |
378 | + Answers to the query are stored secondly in *ANSP2 up to a max of | |
379 | + *ANSSIZP2 bytes, with the actual response length stored in | |
380 | + *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2 | |
381 | + is non-NULL (required for a second query) then malloc is used to | |
382 | + allocate a new response buffer, *ANSSIZP2 is set to the new buffer | |
383 | + size and *ANSP2_MALLOCED is set to 1. | |
384 | + | |
385 | + The ANSP2_MALLOCED argument will eventually be removed as the | |
386 | + change in buffer pointer can be used to detect the buffer has | |
387 | + changed and that the caller should use free on the new buffer. | |
388 | + | |
389 | + Note that the answers may arrive in any order from the server and | |
390 | + therefore the first and second answer buffers may not correspond to | |
391 | + the first and second queries. | |
392 | + | |
393 | + It is not supported to call this function with a non-NULL ANSP2 | |
394 | + but a NULL ANSCP. Put another way, you can call send_vc with a | |
395 | + single unmodifiable buffer or two modifiable buffers, but no other | |
396 | + combination is supported. | |
397 | + | |
398 | + It is the caller's responsibility to free the malloc allocated | |
399 | + buffers by detecting that the pointers have changed from their | |
400 | + original values i.e. *ANSCP or *ANSP2 has changed. | |
401 | + | |
402 | + If an answer is truncated because of UDP datagram DNS limits then | |
403 | + *V_CIRCUIT is set to 1 and the return value non-zero to indicate to | |
404 | + the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1 | |
405 | + if any progress was made reading a response from the nameserver and | |
406 | + is used by the caller to distinguish between ECONNREFUSED and | |
407 | + ETIMEDOUT (the latter if *GOTSOMEWHERE is 1). | |
408 | + | |
409 | + If errors are encountered then *TERRNO is set to an appropriate | |
410 | + errno value and a zero result is returned for a recoverable error, | |
411 | + and a less-than zero result is returned for a non-recoverable error. | |
412 | + | |
413 | + If no errors are encountered then *TERRNO is left unmodified and | |
414 | + a the length of the first response in bytes is returned. */ | |
415 | static int | |
416 | send_dg(res_state statp, | |
417 | const u_char *buf, int buflen, const u_char *buf2, int buflen2, | |
418 | @@ -996,8 +1132,6 @@ send_dg(res_state statp, | |
419 | { | |
420 | const HEADER *hp = (HEADER *) buf; | |
421 | const HEADER *hp2 = (HEADER *) buf2; | |
422 | - u_char *ans = *ansp; | |
423 | - int orig_anssizp = *anssizp; | |
424 | struct timespec now, timeout, finish; | |
425 | struct pollfd pfd[1]; | |
426 | int ptimeout; | |
427 | @@ -1029,6 +1163,8 @@ send_dg(res_state statp, | |
428 | int need_recompute = 0; | |
429 | int nwritten = 0; | |
430 | int recvresp1 = 0; | |
431 | + /* Skip the second response if there is no second query. | |
432 | + To do that we mark the second response as received. */ | |
433 | int recvresp2 = buf2 == NULL; | |
434 | pfd[0].fd = EXT(statp).nssocks[ns]; | |
435 | pfd[0].events = POLLOUT; | |
436 | @@ -1125,50 +1261,52 @@ send_dg(res_state statp, | |
437 | int *thisresplenp; | |
438 | ||
439 | if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { | |
440 | + /* We have not received any responses | |
441 | + yet or we only have one response to | |
442 | + receive. */ | |
443 | thisanssizp = anssizp; | |
444 | thisansp = anscp ?: ansp; | |
445 | assert (anscp != NULL || ansp2 == NULL); | |
446 | thisresplenp = &resplen; | |
447 | } else { | |
448 | - if (*anssizp != MAXPACKET) { | |
449 | - /* No buffer allocated for the first | |
450 | - reply. We can try to use the rest | |
451 | - of the user-provided buffer. */ | |
452 | -#ifdef _STRING_ARCH_unaligned | |
453 | - *anssizp2 = orig_anssizp - resplen; | |
454 | - *ansp2 = *ansp + resplen; | |
455 | -#else | |
456 | - int aligned_resplen | |
457 | - = ((resplen + __alignof__ (HEADER) - 1) | |
458 | - & ~(__alignof__ (HEADER) - 1)); | |
459 | - *anssizp2 = orig_anssizp - aligned_resplen; | |
460 | - *ansp2 = *ansp + aligned_resplen; | |
461 | -#endif | |
462 | - } else { | |
463 | - /* The first reply did not fit into the | |
464 | - user-provided buffer. Maybe the second | |
465 | - answer will. */ | |
466 | - *anssizp2 = orig_anssizp; | |
467 | - *ansp2 = *ansp; | |
468 | - } | |
469 | - | |
470 | thisanssizp = anssizp2; | |
471 | thisansp = ansp2; | |
472 | thisresplenp = resplen2; | |
473 | } | |
474 | ||
475 | if (*thisanssizp < MAXPACKET | |
476 | - /* Yes, we test ANSCP here. If we have two buffers | |
477 | - both will be allocatable. */ | |
478 | - && anscp | |
479 | + /* If the current buffer is non-NULL and it's not | |
480 | + pointing at the static user-supplied buffer then | |
481 | + we can reallocate it. */ | |
482 | + && (thisansp != NULL && thisansp != ansp) | |
483 | + /* Is the size too small? */ | |
484 | && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 | |
485 | - || *thisanssizp < *thisresplenp)) { | |
486 | + || *thisanssizp < *thisresplenp) | |
487 | + ) { | |
488 | + /* Always allocate MAXPACKET, callers expect | |
489 | + this specific size. */ | |
490 | u_char *newp = malloc (MAXPACKET); | |
491 | if (newp != NULL) { | |
492 | - *anssizp = MAXPACKET; | |
493 | - *thisansp = ans = newp; | |
494 | + *thisanssizp = MAXPACKET; | |
495 | + *thisansp = newp; | |
496 | } | |
497 | } | |
498 | + /* We could end up with truncation if anscp was NULL | |
499 | + (not allowed to change caller's buffer) and the | |
500 | + response buffer size is too small. This isn't a | |
501 | + reliable way to detect truncation because the ioctl | |
502 | + may be an inaccurate report of the UDP message size. | |
503 | + Therefore we use this only to issue debug output. | |
504 | + To do truncation accurately with UDP we need | |
505 | + MSG_TRUNC which is only available on Linux. We | |
506 | + can abstract out the Linux-specific feature in the | |
507 | + future to detect truncation. */ | |
508 | + if (__glibc_unlikely (*thisanssizp < *thisresplenp)) { | |
509 | + Dprint(statp->options & RES_DEBUG, | |
510 | + (stdout, ";; response may be truncated (UDP)\n") | |
511 | + ); | |
512 | + } | |
513 | + | |
514 | HEADER *anhp = (HEADER *) *thisansp; | |
515 | socklen_t fromlen = sizeof(struct sockaddr_in6); | |
516 | assert (sizeof(from) <= fromlen); | |
517 | Index: glibc-2.12-2-gc4ccff1/resolv/res_query.c | |
518 | =================================================================== | |
519 | --- glibc-2.12-2-gc4ccff1.orig/resolv/res_query.c | |
520 | +++ glibc-2.12-2-gc4ccff1/resolv/res_query.c | |
521 | @@ -391,6 +391,7 @@ __libc_res_nsearch(res_state statp, | |
522 | && (*answerp2 < answer || *answerp2 >= answer + anslen)) | |
523 | { | |
524 | free (*answerp2); | |
525 | + *nanswerp2 = 0; | |
526 | *answerp2 = NULL; | |
527 | } | |
528 | } | |
529 | @@ -431,6 +432,7 @@ __libc_res_nsearch(res_state statp, | |
530 | || *answerp2 >= answer + anslen)) | |
531 | { | |
532 | free (*answerp2); | |
533 | + *nanswerp2 = 0; | |
534 | *answerp2 = NULL; | |
535 | } | |
536 | ||
537 | @@ -503,6 +505,7 @@ __libc_res_nsearch(res_state statp, | |
538 | if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen)) | |
539 | { | |
540 | free (*answerp2); | |
541 | + *nanswerp2 = NULL; | |
542 | *answerp2 = NULL; | |
543 | } | |
544 | if (saved_herrno != -1) |