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