]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/hstcache.c
[BZ #4938]
[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;
199 for (cnt = 0; hst->h_addr_list[cnt]; ++cnt)
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. */
c207f23b 224 if (he == NULL && hst->h_addr_list[1] == NULL)
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. */
301 dh->timeout = dataset->head.timeout;
302 ++dh->nreloads;
303 }
304 else
305 {
306 /* We have to create a new record. Just allocate
307 appropriate memory and copy it. */
308 struct dataset *newp
309 = (struct dataset *) mempool_alloc (db, total + req->key_len);
310 if (newp != NULL)
311 {
312 /* Adjust pointers into the memory block. */
313 addresses = (char *) newp + (addresses - (char *) dataset);
314 aliases = (char *) newp + (aliases - (char *) dataset);
c8703f88
UD
315 assert (key_copy != NULL);
316 key_copy = (char *) newp + (key_copy - (char *) dataset);
a95a08b4
UD
317
318 dataset = memcpy (newp, dataset, total + req->key_len);
319 alloca_used = false;
320 }
321
322 /* Mark the old record as obsolete. */
323 dh->usable = false;
324 }
325 }
326 else
490998a5 327 {
a95a08b4
UD
328 /* We write the dataset before inserting it to the database
329 since while inserting this thread might block and so would
330 unnecessarily keep the receiver waiting. */
331 assert (fd != -1);
332
eac10791 333#ifdef HAVE_SENDFILE
74158740 334 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
eac10791
UD
335 {
336 assert (db->wr_fd != -1);
337 assert ((char *) &dataset->resp > (char *) db->data);
338 assert ((char *) &dataset->resp - (char *) db->head
339 + total
340 <= (sizeof (struct database_pers_head)
341 + db->head->module * sizeof (ref_t)
342 + db->head->data_size));
bd547139
UD
343 written = sendfileall (fd, db->wr_fd,
344 (char *) &dataset->resp
345 - (char *) db->head, total);
eac10791
UD
346# ifndef __ASSUME_SENDFILE
347 if (written == -1 && errno == ENOSYS)
348 goto use_write;
349# endif
350 }
351 else
352# ifndef __ASSUME_SENDFILE
353 use_write:
354# endif
355#endif
356 written = writeall (fd, &dataset->resp, total);
490998a5
UD
357 }
358
a95a08b4
UD
359 /* Add the record to the database. But only if it has not been
360 stored on the stack.
67479a70 361
a95a08b4
UD
362 If the record contains more than one IP address (used for
363 load balancing etc) don't cache the entry. This is something
364 the current cache handling cannot handle and it is more than
365 questionable whether it is worthwhile complicating the cache
366 handling just for handling such a special case. */
367 if (! alloca_used)
67479a70 368 {
a95a08b4
UD
369 /* If necessary, we also propagate the data to disk. */
370 if (db->persistent)
3418007e
UD
371 {
372 // XXX async OK?
373 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
374 msync ((void *) pval,
375 ((uintptr_t) dataset & pagesize_m1)
376 + total + req->key_len, MS_ASYNC);
377 }
a95a08b4
UD
378
379 addr_list_type = (hst->h_length == NS_INADDRSZ
380 ? GETHOSTBYADDR : GETHOSTBYADDRv6);
381
382 /* Now get the lock to safely insert the records. */
383 pthread_rwlock_rdlock (&db->lock);
384
385 /* NB: the following code is really complicated. It has
386 seemlingly duplicated code paths which do the same. The
387 problem is that we always must add the hash table entry
388 with the FIRST flag set first. Otherwise we get dangling
389 pointers in case memory allocation fails. */
c207f23b 390 assert (hst->h_addr_list[1] == NULL);
a95a08b4 391
a95a08b4
UD
392 /* Avoid adding names if more than one address is available. See
393 above for more info. */
c207f23b
UD
394 assert (req->type == GETHOSTBYNAME
395 || req->type == GETHOSTBYNAMEv6
396 || req->type == GETHOSTBYADDR
397 || req->type == GETHOSTBYADDRv6);
a95a08b4 398
c207f23b
UD
399 if (cache_add (req->type, key_copy, req->key_len,
400 &dataset->head, true, db, owner) < 0)
401 /* Could not allocate memory. Make sure the
402 data gets discarded. */
403 dataset->head.usable = false;
a95a08b4 404
a95a08b4 405 pthread_rwlock_unlock (&db->lock);
67479a70 406 }
67479a70
UD
407 }
408
23700036 409 if (__builtin_expect (written != total, 0) && debug_level > 0)
67479a70
UD
410 {
411 char buf[256];
412 dbg_log (_("short write in %s: %s"), __FUNCTION__,
413 strerror_r (errno, buf, sizeof (buf)));
414 }
415}
416
417
a95a08b4
UD
418static int
419lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
420 size_t buflen, struct hostent **hst)
421{
422 if (type == GETHOSTBYNAME)
423 return __gethostbyname2_r (key, AF_INET, resultbufp, buffer, buflen, hst,
424 &h_errno);
8c89236f 425 if (type == GETHOSTBYNAMEv6)
a95a08b4
UD
426 return __gethostbyname2_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
427 &h_errno);
8c89236f 428 if (type == GETHOSTBYADDR)
a95a08b4
UD
429 return __gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
430 buflen, hst, &h_errno);
8c89236f
UD
431 return __gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
432 buflen, hst, &h_errno);
a95a08b4
UD
433}
434
435
436static void
437addhstbyX (struct database_dyn *db, int fd, request_header *req,
438 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
67479a70
UD
439{
440 /* Search for the entry matching the key. Please note that we don't
441 look again in the table whether the dataset is now available. We
442 simply insert it. It does not matter if it is in there twice. The
443 pruning function only will look at the timestamp. */
c7a9b6e2
UD
444 int buflen = 1024;
445 char *buffer = (char *) alloca (buflen);
67479a70
UD
446 struct hostent resultbuf;
447 struct hostent *hst;
c7a9b6e2 448 bool use_malloc = false;
a95a08b4 449 int errval = 0;
67479a70 450
c7a9b6e2 451 if (__builtin_expect (debug_level > 0, 0))
a95a08b4 452 {
c207f23b
UD
453 const char *str;
454 char buf[INET6_ADDRSTRLEN + 1];
455 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
456 str = key;
457 else
458 str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
459 key, buf, sizeof (buf));
460
a95a08b4 461 if (he == NULL)
c207f23b 462 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
a95a08b4 463 else
c207f23b 464 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
a95a08b4 465 }
67479a70 466
a95a08b4 467 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst) != 0
67479a70 468 && h_errno == NETDB_INTERNAL
a95a08b4 469 && (errval = errno) == ERANGE)
67479a70
UD
470 {
471 errno = 0;
c7a9b6e2
UD
472
473 if (__builtin_expect (buflen > 32768, 0))
474 {
b21fa963 475 char *old_buffer = buffer;
4379b403 476 buflen *= 2;
c7a9b6e2
UD
477 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
478 if (buffer == NULL)
479 {
480 /* We ran out of memory. We cannot do anything but
481 sending a negative response. In reality this should
482 never happen. */
483 hst = NULL;
484 buffer = old_buffer;
a95a08b4
UD
485
486 /* We set the error to indicate this is (possibly) a
487 temporary error and that it does not mean the entry
488 is not available at all. */
489 errval = EAGAIN;
c7a9b6e2
UD
490 break;
491 }
492 use_malloc = true;
493 }
494 else
9caf4f1c
UD
495 /* Allocate a new buffer on the stack. If possible combine it
496 with the previously allocated buffer. */
4379b403 497 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
67479a70
UD
498 }
499
c207f23b 500 cache_addhst (db, fd, req, key, hst, uid, he, dh,
a95a08b4 501 h_errno == TRY_AGAIN ? errval : 0);
c7a9b6e2
UD
502
503 if (use_malloc)
504 free (buffer);
67479a70
UD
505}
506
507
508void
a95a08b4 509addhstbyname (struct database_dyn *db, int fd, request_header *req,
a1c542bf 510 void *key, uid_t uid)
67479a70 511{
a95a08b4
UD
512 addhstbyX (db, fd, req, key, uid, NULL, NULL);
513}
67479a70 514
67479a70 515
a95a08b4
UD
516void
517readdhstbyname (struct database_dyn *db, struct hashentry *he,
518 struct datahead *dh)
519{
520 request_header req =
a1c542bf 521 {
a95a08b4
UD
522 .type = GETHOSTBYNAME,
523 .key_len = he->len
524 };
a1c542bf 525
a95a08b4
UD
526 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
527}
c7a9b6e2 528
67479a70 529
a95a08b4
UD
530void
531addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
532 void *key, uid_t uid)
533{
534 addhstbyX (db, fd, req, key, uid, NULL, NULL);
535}
a1c542bf 536
c7a9b6e2 537
a95a08b4
UD
538void
539readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
540 struct datahead *dh)
541{
542 request_header req =
543 {
544 .type = GETHOSTBYADDR,
545 .key_len = he->len
546 };
547
548 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
549}
550
551
552void
a95a08b4 553addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 554 void *key, uid_t uid)
67479a70 555{
a95a08b4
UD
556 addhstbyX (db, fd, req, key, uid, NULL, NULL);
557}
67479a70 558
a1c542bf 559
a95a08b4
UD
560void
561readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
562 struct datahead *dh)
563{
564 request_header req =
67479a70 565 {
a95a08b4
UD
566 .type = GETHOSTBYNAMEv6,
567 .key_len = he->len
568 };
c7a9b6e2 569
a95a08b4 570 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
571}
572
573
574void
a95a08b4 575addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 576 void *key, uid_t uid)
67479a70 577{
a95a08b4
UD
578 addhstbyX (db, fd, req, key, uid, NULL, NULL);
579}
67479a70 580
67479a70 581
a95a08b4
UD
582void
583readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
584 struct datahead *dh)
585{
586 request_header req =
67479a70 587 {
a95a08b4
UD
588 .type = GETHOSTBYADDRv6,
589 .key_len = he->len
590 };
c7a9b6e2 591
a95a08b4 592 addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70 593}