]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/hstcache.c
Declare __gethostbyaddr2_r and __gethostbyname3_r.
[thirdparty/glibc.git] / nscd / hstcache.c
CommitLineData
67479a70 1/* Cache handling for host lookup.
b21fa963 2 Copyright (C) 1998-2005, 2006, 2007 Free Software Foundation, Inc.
67479a70
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
43bc8ac6 6 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
67479a70 10
43bc8ac6 11 This program is distributed in the hope that it will be useful,
67479a70 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
67479a70 15
43bc8ac6
UD
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
67479a70 19
9caf4f1c 20#include <alloca.h>
67479a70
UD
21#include <assert.h>
22#include <errno.h>
23#include <error.h>
a95a08b4 24#include <libintl.h>
67479a70 25#include <netdb.h>
c7a9b6e2 26#include <stdbool.h>
67479a70
UD
27#include <stddef.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <time.h>
32#include <unistd.h>
33#include <arpa/inet.h>
9e56c380 34#include <arpa/nameser.h>
a95a08b4 35#include <sys/mman.h>
c7a9b6e2 36#include <stackinfo.h>
67479a70
UD
37
38#include "nscd.h"
39#include "dbg_log.h"
eac10791
UD
40#ifdef HAVE_SENDFILE
41# include <kernel-features.h>
42#endif
67479a70 43
67479a70
UD
44
45/* This is the standard reply in case the service is disabled. */
46static const hst_response_header disabled =
47{
c2e13112
RM
48 .version = NSCD_VERSION,
49 .found = -1,
50 .h_name_len = 0,
51 .h_aliases_cnt = 0,
52 .h_addrtype = -1,
53 .h_length = -1,
54 .h_addr_list_cnt = 0,
55 .error = NETDB_INTERNAL
67479a70
UD
56};
57
58/* This is the struct describing how to write this record. */
59const struct iovec hst_iov_disabled =
60{
c2e13112
RM
61 .iov_base = (void *) &disabled,
62 .iov_len = sizeof (disabled)
67479a70
UD
63};
64
65
66/* This is the standard reply in case we haven't found the dataset. */
67static const hst_response_header notfound =
68{
c2e13112
RM
69 .version = NSCD_VERSION,
70 .found = 0,
71 .h_name_len = 0,
72 .h_aliases_cnt = 0,
73 .h_addrtype = -1,
74 .h_length = -1,
75 .h_addr_list_cnt = 0,
76 .error = HOST_NOT_FOUND
67479a70
UD
77};
78
67479a70 79
67479a70 80static void
a95a08b4 81cache_addhst (struct database_dyn *db, int fd, request_header *req,
c207f23b 82 const void *key, struct hostent *hst, uid_t owner,
a95a08b4 83 struct hashentry *he, struct datahead *dh, int errval)
67479a70
UD
84{
85 ssize_t total;
86 ssize_t written;
87 time_t t = time (NULL);
88
a95a08b4
UD
89 /* We allocate all data in one memory block: the iov vector,
90 the response header and the dataset itself. */
91 struct dataset
92 {
93 struct datahead head;
94 hst_response_header resp;
95 char strdata[0];
96 } *dataset;
97
98 assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
99
67479a70
UD
100 if (hst == NULL)
101 {
a95a08b4
UD
102 if (he != NULL && errval == EAGAIN)
103 {
104 /* If we have an old record available but cannot find one
105 now because the service is not available we keep the old
106 record and make sure it does not get removed. */
107 if (reload_count != UINT_MAX)
108 /* Do not reset the value if we never not reload the record. */
109 dh->nreloads = reload_count - 1;
110
111 written = total = 0;
112 }
113 else
114 {
115 /* We have no data. This means we send the standard reply for this
116 case. */
117 written = total = sizeof (notfound);
67479a70 118
a95a08b4 119 if (fd != -1)
2c210d1e
UD
120 written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
121 MSG_NOSIGNAL));
67479a70 122
a95a08b4
UD
123 dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
124 /* If we cannot permanently store the result, so be it. */
125 if (dataset != NULL)
126 {
127 dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
128 dataset->head.recsize = total;
129 dataset->head.notfound = true;
130 dataset->head.nreloads = 0;
131 dataset->head.usable = true;
67479a70 132
a95a08b4
UD
133 /* Compute the timeout time. */
134 dataset->head.timeout = t + db->negtimeout;
67479a70 135
a95a08b4
UD
136 /* This is the reply. */
137 memcpy (&dataset->resp, &notfound, total);
67479a70 138
a95a08b4
UD
139 /* Copy the key data. */
140 memcpy (dataset->strdata, key, req->key_len);
67479a70 141
8c89236f
UD
142 /* If necessary, we also propagate the data to disk. */
143 if (db->persistent)
144 {
145 // XXX async OK?
146 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
147 msync ((void *) pval,
148 ((uintptr_t) dataset & pagesize_m1)
149 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
150 }
151
a95a08b4
UD
152 /* Now get the lock to safely insert the records. */
153 pthread_rwlock_rdlock (&db->lock);
154
155 if (cache_add (req->type, &dataset->strdata, req->key_len,
156 &dataset->head, true, db, owner) < 0)
157 /* Ensure the data can be recovered. */
158 dataset->head.usable = false;
159
160 pthread_rwlock_unlock (&db->lock);
161
162 /* Mark the old entry as obsolete. */
163 if (dh != NULL)
164 dh->usable = false;
165 }
166 else
167 ++db->head->addfailed;
99bb9f42 168 }
67479a70
UD
169 }
170 else
171 {
172 /* Determine the I/O structure. */
67479a70
UD
173 size_t h_name_len = strlen (hst->h_name) + 1;
174 size_t h_aliases_cnt;
3107c0c5 175 uint32_t *h_aliases_len;
67479a70
UD
176 size_t h_addr_list_cnt;
177 int addr_list_type;
178 char *addresses;
179 char *aliases;
180 char *key_copy = NULL;
181 char *cp;
182 size_t cnt;
183
184 /* Determine the number of aliases. */
185 h_aliases_cnt = 0;
186 for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
187 ++h_aliases_cnt;
188 /* Determine the length of all aliases. */
3107c0c5 189 h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
67479a70
UD
190 total = 0;
191 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
192 {
193 h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
194 total += h_aliases_len[cnt];
195 }
196
197 /* Determine the number of addresses. */
198 h_addr_list_cnt = 0;
1ce7d80d 199 while (hst->h_addr_list[h_addr_list_cnt] != NULL)
67479a70
UD
200 ++h_addr_list_cnt;
201
a95a08b4
UD
202 if (h_addr_list_cnt == 0)
203 /* Invalid entry. */
204 return;
205
206 total += (sizeof (struct dataset)
67479a70 207 + h_name_len
3107c0c5 208 + h_aliases_cnt * sizeof (uint32_t)
488fb3c7 209 + h_addr_list_cnt * hst->h_length);
a95a08b4 210 written = total;
67479a70 211
a95a08b4
UD
212 /* If we refill the cache, first assume the reconrd did not
213 change. Allocate memory on the cache since it is likely
214 discarded anyway. If it turns out to be necessary to have a
215 new record we can still allocate real memory. */
216 bool alloca_used = false;
217 dataset = NULL;
67479a70 218
a95a08b4
UD
219 /* If the record contains more than one IP address (used for
220 load balancing etc) don't cache the entry. This is something
221 the current cache handling cannot handle and it is more than
222 questionable whether it is worthwhile complicating the cache
223 handling just for handling such a special case. */
a30d41c1 224 if (he == NULL && h_addr_list_cnt == 1)
a95a08b4
UD
225 {
226 dataset = (struct dataset *) mempool_alloc (db,
227 total + req->key_len);
228 if (dataset == NULL)
229 ++db->head->addfailed;
230 }
67479a70 231
a95a08b4
UD
232 if (dataset == NULL)
233 {
234 /* We cannot permanently add the result in the moment. But
235 we can provide the result as is. Store the data in some
236 temporary memory. */
237 dataset = (struct dataset *) alloca (total + req->key_len);
238
239 /* We cannot add this record to the permanent database. */
240 alloca_used = true;
241 }
242
243 dataset->head.allocsize = total + req->key_len;
244 dataset->head.recsize = total - offsetof (struct dataset, resp);
245 dataset->head.notfound = false;
246 dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
247 dataset->head.usable = true;
248
249 /* Compute the timeout time. */
250 dataset->head.timeout = t + db->postimeout;
251
252 dataset->resp.version = NSCD_VERSION;
253 dataset->resp.found = 1;
254 dataset->resp.h_name_len = h_name_len;
255 dataset->resp.h_aliases_cnt = h_aliases_cnt;
256 dataset->resp.h_addrtype = hst->h_addrtype;
257 dataset->resp.h_length = hst->h_length;
258 dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
259 dataset->resp.error = NETDB_SUCCESS;
260
261 cp = dataset->strdata;
67479a70
UD
262
263 cp = mempcpy (cp, hst->h_name, h_name_len);
3107c0c5 264 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
67479a70
UD
265
266 /* The normal addresses first. */
267 addresses = cp;
268 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
269 cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
270
67479a70
UD
271 /* Then the aliases. */
272 aliases = cp;
273 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
274 cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
275
a95a08b4
UD
276 assert (cp
277 == dataset->strdata + total - offsetof (struct dataset,
278 strdata));
67479a70
UD
279
280 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
281 that the answer we get from the NSS does not contain the key
282 itself. This is the case if the resolver is used and the name
283 is extended by the domainnames from /etc/resolv.conf. Therefore
284 we explicitly add the name here. */
c207f23b 285 key_copy = memcpy (cp, key, req->key_len);
67479a70 286
a95a08b4
UD
287 /* Now we can determine whether on refill we have to create a new
288 record or not. */
289 if (he != NULL)
290 {
291 assert (fd == -1);
67479a70 292
a95a08b4
UD
293 if (total + req->key_len == dh->allocsize
294 && total - offsetof (struct dataset, resp) == dh->recsize
295 && memcmp (&dataset->resp, dh->data,
296 dh->allocsize - offsetof (struct dataset, resp)) == 0)
297 {
8c89236f 298 /* The data has not changed. We will just bump the
a95a08b4
UD
299 timeout value. Note that the new record has been
300 allocated on the stack and need not be freed. */
c44d3bdf 301 assert (h_addr_list_cnt == 1);
a95a08b4
UD
302 dh->timeout = dataset->head.timeout;
303 ++dh->nreloads;
304 }
305 else
306 {
c44d3bdf 307 if (h_addr_list_cnt == 1)
a95a08b4 308 {
c44d3bdf
UD
309 /* We have to create a new record. Just allocate
310 appropriate memory and copy it. */
311 struct dataset *newp
312 = (struct dataset *) mempool_alloc (db,
313 total + req->key_len);
314 if (newp != NULL)
315 {
316 /* Adjust pointers into the memory block. */
317 addresses = (char *) newp + (addresses
318 - (char *) dataset);
319 aliases = (char *) newp + (aliases - (char *) dataset);
320 assert (key_copy != NULL);
321 key_copy = (char *) newp + (key_copy - (char *) dataset);
322
323 dataset = memcpy (newp, dataset, total + req->key_len);
324 alloca_used = false;
325 }
a95a08b4
UD
326 }
327
328 /* Mark the old record as obsolete. */
329 dh->usable = false;
330 }
331 }
332 else
490998a5 333 {
a95a08b4
UD
334 /* We write the dataset before inserting it to the database
335 since while inserting this thread might block and so would
336 unnecessarily keep the receiver waiting. */
337 assert (fd != -1);
338
eac10791 339#ifdef HAVE_SENDFILE
74158740 340 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
eac10791
UD
341 {
342 assert (db->wr_fd != -1);
343 assert ((char *) &dataset->resp > (char *) db->data);
344 assert ((char *) &dataset->resp - (char *) db->head
345 + total
346 <= (sizeof (struct database_pers_head)
347 + db->head->module * sizeof (ref_t)
348 + db->head->data_size));
bd547139
UD
349 written = sendfileall (fd, db->wr_fd,
350 (char *) &dataset->resp
351 - (char *) db->head, total);
eac10791
UD
352# ifndef __ASSUME_SENDFILE
353 if (written == -1 && errno == ENOSYS)
354 goto use_write;
355# endif
356 }
357 else
358# ifndef __ASSUME_SENDFILE
359 use_write:
360# endif
361#endif
362 written = writeall (fd, &dataset->resp, total);
490998a5
UD
363 }
364
a95a08b4
UD
365 /* Add the record to the database. But only if it has not been
366 stored on the stack.
67479a70 367
a95a08b4
UD
368 If the record contains more than one IP address (used for
369 load balancing etc) don't cache the entry. This is something
370 the current cache handling cannot handle and it is more than
371 questionable whether it is worthwhile complicating the cache
372 handling just for handling such a special case. */
373 if (! alloca_used)
67479a70 374 {
a95a08b4
UD
375 /* If necessary, we also propagate the data to disk. */
376 if (db->persistent)
3418007e
UD
377 {
378 // XXX async OK?
379 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
380 msync ((void *) pval,
381 ((uintptr_t) dataset & pagesize_m1)
382 + total + req->key_len, MS_ASYNC);
383 }
a95a08b4
UD
384
385 addr_list_type = (hst->h_length == NS_INADDRSZ
386 ? GETHOSTBYADDR : GETHOSTBYADDRv6);
387
388 /* Now get the lock to safely insert the records. */
389 pthread_rwlock_rdlock (&db->lock);
390
391 /* NB: the following code is really complicated. It has
392 seemlingly duplicated code paths which do the same. The
393 problem is that we always must add the hash table entry
394 with the FIRST flag set first. Otherwise we get dangling
395 pointers in case memory allocation fails. */
c207f23b 396 assert (hst->h_addr_list[1] == NULL);
a95a08b4 397
a95a08b4
UD
398 /* Avoid adding names if more than one address is available. See
399 above for more info. */
c207f23b
UD
400 assert (req->type == GETHOSTBYNAME
401 || req->type == GETHOSTBYNAMEv6
402 || req->type == GETHOSTBYADDR
403 || req->type == GETHOSTBYADDRv6);
a95a08b4 404
c207f23b
UD
405 if (cache_add (req->type, key_copy, req->key_len,
406 &dataset->head, true, db, owner) < 0)
407 /* Could not allocate memory. Make sure the
408 data gets discarded. */
409 dataset->head.usable = false;
a95a08b4 410
a95a08b4 411 pthread_rwlock_unlock (&db->lock);
67479a70 412 }
67479a70
UD
413 }
414
23700036 415 if (__builtin_expect (written != total, 0) && debug_level > 0)
67479a70
UD
416 {
417 char buf[256];
418 dbg_log (_("short write in %s: %s"), __FUNCTION__,
419 strerror_r (errno, buf, sizeof (buf)));
420 }
421}
422
423
a95a08b4
UD
424static int
425lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
426 size_t buflen, struct hostent **hst)
427{
428 if (type == GETHOSTBYNAME)
429 return __gethostbyname2_r (key, AF_INET, resultbufp, buffer, buflen, hst,
430 &h_errno);
8c89236f 431 if (type == GETHOSTBYNAMEv6)
a95a08b4
UD
432 return __gethostbyname2_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
433 &h_errno);
8c89236f 434 if (type == GETHOSTBYADDR)
a95a08b4
UD
435 return __gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
436 buflen, hst, &h_errno);
8c89236f
UD
437 return __gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
438 buflen, hst, &h_errno);
a95a08b4
UD
439}
440
441
442static void
443addhstbyX (struct database_dyn *db, int fd, request_header *req,
444 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
67479a70
UD
445{
446 /* Search for the entry matching the key. Please note that we don't
447 look again in the table whether the dataset is now available. We
448 simply insert it. It does not matter if it is in there twice. The
449 pruning function only will look at the timestamp. */
c7a9b6e2
UD
450 int buflen = 1024;
451 char *buffer = (char *) alloca (buflen);
67479a70
UD
452 struct hostent resultbuf;
453 struct hostent *hst;
c7a9b6e2 454 bool use_malloc = false;
a95a08b4 455 int errval = 0;
67479a70 456
c7a9b6e2 457 if (__builtin_expect (debug_level > 0, 0))
a95a08b4 458 {
c207f23b
UD
459 const char *str;
460 char buf[INET6_ADDRSTRLEN + 1];
461 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
462 str = key;
463 else
464 str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
465 key, buf, sizeof (buf));
466
a95a08b4 467 if (he == NULL)
c207f23b 468 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
a95a08b4 469 else
c207f23b 470 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
a95a08b4 471 }
67479a70 472
a95a08b4 473 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst) != 0
67479a70 474 && h_errno == NETDB_INTERNAL
a95a08b4 475 && (errval = errno) == ERANGE)
67479a70
UD
476 {
477 errno = 0;
c7a9b6e2
UD
478
479 if (__builtin_expect (buflen > 32768, 0))
480 {
b21fa963 481 char *old_buffer = buffer;
4379b403 482 buflen *= 2;
c7a9b6e2
UD
483 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
484 if (buffer == NULL)
485 {
486 /* We ran out of memory. We cannot do anything but
487 sending a negative response. In reality this should
488 never happen. */
489 hst = NULL;
490 buffer = old_buffer;
a95a08b4
UD
491
492 /* We set the error to indicate this is (possibly) a
493 temporary error and that it does not mean the entry
494 is not available at all. */
495 errval = EAGAIN;
c7a9b6e2
UD
496 break;
497 }
498 use_malloc = true;
499 }
500 else
9caf4f1c
UD
501 /* Allocate a new buffer on the stack. If possible combine it
502 with the previously allocated buffer. */
4379b403 503 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
67479a70
UD
504 }
505
c207f23b 506 cache_addhst (db, fd, req, key, hst, uid, he, dh,
a95a08b4 507 h_errno == TRY_AGAIN ? errval : 0);
c7a9b6e2
UD
508
509 if (use_malloc)
510 free (buffer);
67479a70
UD
511}
512
513
514void
a95a08b4 515addhstbyname (struct database_dyn *db, int fd, request_header *req,
a1c542bf 516 void *key, uid_t uid)
67479a70 517{
a95a08b4
UD
518 addhstbyX (db, fd, req, key, uid, NULL, NULL);
519}
67479a70 520
67479a70 521
a95a08b4
UD
522void
523readdhstbyname (struct database_dyn *db, struct hashentry *he,
524 struct datahead *dh)
525{
526 request_header req =
a1c542bf 527 {
a95a08b4
UD
528 .type = GETHOSTBYNAME,
529 .key_len = he->len
530 };
a1c542bf 531
a95a08b4
UD
532 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
533}
c7a9b6e2 534
67479a70 535
a95a08b4
UD
536void
537addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
538 void *key, uid_t uid)
539{
540 addhstbyX (db, fd, req, key, uid, NULL, NULL);
541}
a1c542bf 542
c7a9b6e2 543
a95a08b4
UD
544void
545readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
546 struct datahead *dh)
547{
548 request_header req =
549 {
550 .type = GETHOSTBYADDR,
551 .key_len = he->len
552 };
553
554 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
555}
556
557
558void
a95a08b4 559addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 560 void *key, uid_t uid)
67479a70 561{
a95a08b4
UD
562 addhstbyX (db, fd, req, key, uid, NULL, NULL);
563}
67479a70 564
a1c542bf 565
a95a08b4
UD
566void
567readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
568 struct datahead *dh)
569{
570 request_header req =
67479a70 571 {
a95a08b4
UD
572 .type = GETHOSTBYNAMEv6,
573 .key_len = he->len
574 };
c7a9b6e2 575
a95a08b4 576 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
577}
578
579
580void
a95a08b4 581addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 582 void *key, uid_t uid)
67479a70 583{
a95a08b4
UD
584 addhstbyX (db, fd, req, key, uid, NULL, NULL);
585}
67479a70 586
67479a70 587
a95a08b4
UD
588void
589readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
590 struct datahead *dh)
591{
592 request_header req =
67479a70 593 {
a95a08b4
UD
594 .type = GETHOSTBYADDRv6,
595 .key_len = he->len
596 };
c7a9b6e2 597
a95a08b4 598 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70 599}