1 /* Cache handling for host lookup.
2 Copyright (C) 1998-2008, 2009, 2011 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
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.
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.
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. */
33 #include <arpa/inet.h>
34 #include <arpa/nameser.h>
36 #include <stackinfo.h>
41 # include <kernel-features.h>
45 /* This is the standard reply in case the service is disabled. */
46 static const hst_response_header disabled
=
48 .version
= NSCD_VERSION
,
55 .error
= NETDB_INTERNAL
58 /* This is the struct describing how to write this record. */
59 const struct iovec hst_iov_disabled
=
61 .iov_base
= (void *) &disabled
,
62 .iov_len
= sizeof (disabled
)
66 /* This is the standard reply in case we haven't found the dataset. */
67 static const hst_response_header notfound
=
69 .version
= NSCD_VERSION
,
76 .error
= HOST_NOT_FOUND
80 /* This is the standard reply in case there are temporary problems. */
81 static const hst_response_header tryagain
=
83 .version
= NSCD_VERSION
,
95 cache_addhst (struct database_dyn
*db
, int fd
, request_header
*req
,
96 const void *key
, struct hostent
*hst
, uid_t owner
,
97 struct hashentry
*const he
, struct datahead
*dh
, int errval
,
100 bool all_written
= true;
101 time_t t
= time (NULL
);
103 /* We allocate all data in one memory block: the iov vector,
104 the response header and the dataset itself. */
107 struct datahead head
;
108 hst_response_header resp
;
112 assert (offsetof (struct dataset
, resp
) == offsetof (struct datahead
, data
));
114 time_t timeout
= MAX_TIMEOUT_VALUE
;
117 if (he
!= NULL
&& errval
== EAGAIN
)
119 /* If we have an old record available but cannot find one
120 now because the service is not available we keep the old
121 record and make sure it does not get removed. */
122 if (reload_count
!= UINT_MAX
)
123 /* Do not reset the value if we never not reload the record. */
124 dh
->nreloads
= reload_count
- 1;
126 /* Reload with the same time-to-live value. */
127 timeout
= dh
->timeout
= t
+ dh
->ttl
;
131 /* We have no data. This means we send the standard reply for this
132 case. Possibly this is only temporary. */
133 ssize_t total
= sizeof (notfound
);
134 assert (sizeof (notfound
) == sizeof (tryagain
));
136 const hst_response_header
*resp
= (errval
== EAGAIN
137 ? &tryagain
: ¬found
);
140 TEMP_FAILURE_RETRY (send (fd
, resp
, total
,
141 MSG_NOSIGNAL
)) != total
)
144 /* If we cannot permanently store the result, so be it. */
145 if (__builtin_expect (db
->negtimeout
== 0, 0))
147 /* Mark the old entry as obsolete. */
151 else if ((dataset
= mempool_alloc (db
, (sizeof (struct dataset
)
152 + req
->key_len
), 1)) != NULL
)
154 dataset
->head
.allocsize
= sizeof (struct dataset
) + req
->key_len
;
155 dataset
->head
.recsize
= total
;
156 dataset
->head
.notfound
= true;
157 dataset
->head
.nreloads
= 0;
158 dataset
->head
.usable
= true;
160 /* Compute the timeout time. */
161 dataset
->head
.ttl
= ttl
== INT32_MAX
? db
->negtimeout
: ttl
;
162 timeout
= dataset
->head
.timeout
= t
+ dataset
->head
.ttl
;
164 /* This is the reply. */
165 memcpy (&dataset
->resp
, resp
, total
);
167 /* Copy the key data. */
168 memcpy (dataset
->strdata
, key
, req
->key_len
);
170 /* If necessary, we also propagate the data to disk. */
174 uintptr_t pval
= (uintptr_t) dataset
& ~pagesize_m1
;
175 msync ((void *) pval
,
176 ((uintptr_t) dataset
& pagesize_m1
)
177 + sizeof (struct dataset
) + req
->key_len
, MS_ASYNC
);
180 (void) cache_add (req
->type
, &dataset
->strdata
, req
->key_len
,
181 &dataset
->head
, true, db
, owner
, he
== NULL
);
183 pthread_rwlock_unlock (&db
->lock
);
185 /* Mark the old entry as obsolete. */
193 /* Determine the I/O structure. */
194 size_t h_name_len
= strlen (hst
->h_name
) + 1;
195 size_t h_aliases_cnt
;
196 uint32_t *h_aliases_len
;
197 size_t h_addr_list_cnt
;
200 char *key_copy
= NULL
;
205 /* Determine the number of aliases. */
207 for (cnt
= 0; hst
->h_aliases
[cnt
] != NULL
; ++cnt
)
209 /* Determine the length of all aliases. */
210 h_aliases_len
= (uint32_t *) alloca (h_aliases_cnt
* sizeof (uint32_t));
212 for (cnt
= 0; cnt
< h_aliases_cnt
; ++cnt
)
214 h_aliases_len
[cnt
] = strlen (hst
->h_aliases
[cnt
]) + 1;
215 total
+= h_aliases_len
[cnt
];
218 /* Determine the number of addresses. */
220 while (hst
->h_addr_list
[h_addr_list_cnt
] != NULL
)
223 if (h_addr_list_cnt
== 0)
225 return MAX_TIMEOUT_VALUE
;
227 total
+= (sizeof (struct dataset
)
229 + h_aliases_cnt
* sizeof (uint32_t)
230 + h_addr_list_cnt
* hst
->h_length
);
232 /* If we refill the cache, first assume the reconrd did not
233 change. Allocate memory on the cache since it is likely
234 discarded anyway. If it turns out to be necessary to have a
235 new record we can still allocate real memory. */
236 bool alloca_used
= false;
239 /* If the record contains more than one IP address (used for
240 load balancing etc) don't cache the entry. This is something
241 the current cache handling cannot handle and it is more than
242 questionable whether it is worthwhile complicating the cache
243 handling just for handling such a special case. */
244 if (he
== NULL
&& h_addr_list_cnt
== 1)
245 dataset
= (struct dataset
*) mempool_alloc (db
, total
+ req
->key_len
,
250 /* We cannot permanently add the result in the moment. But
251 we can provide the result as is. Store the data in some
253 dataset
= (struct dataset
*) alloca (total
+ req
->key_len
);
255 /* We cannot add this record to the permanent database. */
259 dataset
->head
.allocsize
= total
+ req
->key_len
;
260 dataset
->head
.recsize
= total
- offsetof (struct dataset
, resp
);
261 dataset
->head
.notfound
= false;
262 dataset
->head
.nreloads
= he
== NULL
? 0 : (dh
->nreloads
+ 1);
263 dataset
->head
.usable
= true;
265 /* Compute the timeout time. */
266 dataset
->head
.ttl
= ttl
== INT32_MAX
? db
->postimeout
: ttl
;
267 timeout
= dataset
->head
.timeout
= t
+ dataset
->head
.ttl
;
269 dataset
->resp
.version
= NSCD_VERSION
;
270 dataset
->resp
.found
= 1;
271 dataset
->resp
.h_name_len
= h_name_len
;
272 dataset
->resp
.h_aliases_cnt
= h_aliases_cnt
;
273 dataset
->resp
.h_addrtype
= hst
->h_addrtype
;
274 dataset
->resp
.h_length
= hst
->h_length
;
275 dataset
->resp
.h_addr_list_cnt
= h_addr_list_cnt
;
276 dataset
->resp
.error
= NETDB_SUCCESS
;
278 /* Make sure there is no gap. */
279 assert ((char *) (&dataset
->resp
.error
+ 1) == dataset
->strdata
);
281 cp
= dataset
->strdata
;
283 cp
= mempcpy (cp
, hst
->h_name
, h_name_len
);
284 cp
= mempcpy (cp
, h_aliases_len
, h_aliases_cnt
* sizeof (uint32_t));
286 /* The normal addresses first. */
288 for (cnt
= 0; cnt
< h_addr_list_cnt
; ++cnt
)
289 cp
= mempcpy (cp
, hst
->h_addr_list
[cnt
], hst
->h_length
);
291 /* Then the aliases. */
293 for (cnt
= 0; cnt
< h_aliases_cnt
; ++cnt
)
294 cp
= mempcpy (cp
, hst
->h_aliases
[cnt
], h_aliases_len
[cnt
]);
297 == dataset
->strdata
+ total
- offsetof (struct dataset
,
300 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
301 that the answer we get from the NSS does not contain the key
302 itself. This is the case if the resolver is used and the name
303 is extended by the domainnames from /etc/resolv.conf. Therefore
304 we explicitly add the name here. */
305 key_copy
= memcpy (cp
, key
, req
->key_len
);
307 assert ((char *) &dataset
->resp
+ dataset
->head
.recsize
== cp
);
309 /* Now we can determine whether on refill we have to create a new
315 if (total
+ req
->key_len
== dh
->allocsize
316 && total
- offsetof (struct dataset
, resp
) == dh
->recsize
317 && memcmp (&dataset
->resp
, dh
->data
,
318 dh
->allocsize
- offsetof (struct dataset
, resp
)) == 0)
320 /* The data has not changed. We will just bump the
321 timeout value. Note that the new record has been
322 allocated on the stack and need not be freed. */
323 assert (h_addr_list_cnt
== 1);
324 dh
->ttl
= dataset
->head
.ttl
;
325 dh
->timeout
= dataset
->head
.timeout
;
330 if (h_addr_list_cnt
== 1)
332 /* We have to create a new record. Just allocate
333 appropriate memory and copy it. */
335 = (struct dataset
*) mempool_alloc (db
,
336 total
+ req
->key_len
,
340 /* Adjust pointers into the memory block. */
341 addresses
= (char *) newp
+ (addresses
343 aliases
= (char *) newp
+ (aliases
- (char *) dataset
);
344 assert (key_copy
!= NULL
);
345 key_copy
= (char *) newp
+ (key_copy
- (char *) dataset
);
347 dataset
= memcpy (newp
, dataset
, total
+ req
->key_len
);
352 /* Mark the old record as obsolete. */
358 /* We write the dataset before inserting it to the database
359 since while inserting this thread might block and so would
360 unnecessarily keep the receiver waiting. */
364 if (__builtin_expect (db
->mmap_used
, 1) && !alloca_used
)
366 assert (db
->wr_fd
!= -1);
367 assert ((char *) &dataset
->resp
> (char *) db
->data
);
368 assert ((char *) dataset
- (char *) db
->head
370 <= (sizeof (struct database_pers_head
)
371 + db
->head
->module
* sizeof (ref_t
)
372 + db
->head
->data_size
));
373 ssize_t written
= sendfileall (fd
, db
->wr_fd
,
374 (char *) &dataset
->resp
376 dataset
->head
.recsize
);
377 if (written
!= dataset
->head
.recsize
)
379 # ifndef __ASSUME_SENDFILE
380 if (written
== -1 && errno
== ENOSYS
)
387 # ifndef __ASSUME_SENDFILE
391 if (writeall (fd
, &dataset
->resp
, dataset
->head
.recsize
)
392 != dataset
->head
.recsize
)
396 /* Add the record to the database. But only if it has not been
399 If the record contains more than one IP address (used for
400 load balancing etc) don't cache the entry. This is something
401 the current cache handling cannot handle and it is more than
402 questionable whether it is worthwhile complicating the cache
403 handling just for handling such a special case. */
406 /* If necessary, we also propagate the data to disk. */
410 uintptr_t pval
= (uintptr_t) dataset
& ~pagesize_m1
;
411 msync ((void *) pval
,
412 ((uintptr_t) dataset
& pagesize_m1
)
413 + total
+ req
->key_len
, MS_ASYNC
);
416 /* NB: the following code is really complicated. It has
417 seemlingly duplicated code paths which do the same. The
418 problem is that we always must add the hash table entry
419 with the FIRST flag set first. Otherwise we get dangling
420 pointers in case memory allocation fails. */
421 assert (hst
->h_addr_list
[1] == NULL
);
423 /* Avoid adding names if more than one address is available. See
424 above for more info. */
425 assert (req
->type
== GETHOSTBYNAME
426 || req
->type
== GETHOSTBYNAMEv6
427 || req
->type
== GETHOSTBYADDR
428 || req
->type
== GETHOSTBYADDRv6
);
430 (void) cache_add (req
->type
, key_copy
, req
->key_len
,
431 &dataset
->head
, true, db
, owner
, he
== NULL
);
433 pthread_rwlock_unlock (&db
->lock
);
437 if (__builtin_expect (!all_written
, 0) && debug_level
> 0)
440 dbg_log (_("short write in %s: %s"), __FUNCTION__
,
441 strerror_r (errno
, buf
, sizeof (buf
)));
449 lookup (int type
, void *key
, struct hostent
*resultbufp
, char *buffer
,
450 size_t buflen
, struct hostent
**hst
, int32_t *ttlp
)
452 if (type
== GETHOSTBYNAME
)
453 return __gethostbyname3_r (key
, AF_INET
, resultbufp
, buffer
, buflen
, hst
,
454 &h_errno
, ttlp
, NULL
);
455 if (type
== GETHOSTBYNAMEv6
)
456 return __gethostbyname3_r (key
, AF_INET6
, resultbufp
, buffer
, buflen
, hst
,
457 &h_errno
, ttlp
, NULL
);
458 if (type
== GETHOSTBYADDR
)
459 return __gethostbyaddr2_r (key
, NS_INADDRSZ
, AF_INET
, resultbufp
, buffer
,
460 buflen
, hst
, &h_errno
, ttlp
);
461 return __gethostbyaddr2_r (key
, NS_IN6ADDRSZ
, AF_INET6
, resultbufp
, buffer
,
462 buflen
, hst
, &h_errno
, ttlp
);
467 addhstbyX (struct database_dyn
*db
, int fd
, request_header
*req
,
468 void *key
, uid_t uid
, struct hashentry
*he
, struct datahead
*dh
)
470 /* Search for the entry matching the key. Please note that we don't
471 look again in the table whether the dataset is now available. We
472 simply insert it. It does not matter if it is in there twice. The
473 pruning function only will look at the timestamp. */
475 char *buffer
= (char *) alloca (buflen
);
476 struct hostent resultbuf
;
478 bool use_malloc
= false;
480 int32_t ttl
= INT32_MAX
;
482 if (__builtin_expect (debug_level
> 0, 0))
485 char buf
[INET6_ADDRSTRLEN
+ 1];
486 if (req
->type
== GETHOSTBYNAME
|| req
->type
== GETHOSTBYNAMEv6
)
489 str
= inet_ntop (req
->type
== GETHOSTBYADDR
? AF_INET
: AF_INET6
,
490 key
, buf
, sizeof (buf
));
493 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str
);
495 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str
);
498 while (lookup (req
->type
, key
, &resultbuf
, buffer
, buflen
, &hst
, &ttl
) != 0
499 && h_errno
== NETDB_INTERNAL
500 && (errval
= errno
) == ERANGE
)
504 if (__builtin_expect (buflen
> 32768, 0))
506 char *old_buffer
= buffer
;
508 buffer
= (char *) realloc (use_malloc
? buffer
: NULL
, buflen
);
511 /* We ran out of memory. We cannot do anything but
512 sending a negative response. In reality this should
517 /* We set the error to indicate this is (possibly) a
518 temporary error and that it does not mean the entry
519 is not available at all. */
527 /* Allocate a new buffer on the stack. If possible combine it
528 with the previously allocated buffer. */
529 buffer
= (char *) extend_alloca (buffer
, buflen
, 2 * buflen
);
532 time_t timeout
= cache_addhst (db
, fd
, req
, key
, hst
, uid
, he
, dh
,
533 h_errno
== TRY_AGAIN
? errval
: 0, ttl
);
543 addhstbyname (struct database_dyn
*db
, int fd
, request_header
*req
,
544 void *key
, uid_t uid
)
546 addhstbyX (db
, fd
, req
, key
, uid
, NULL
, NULL
);
551 readdhstbyname (struct database_dyn
*db
, struct hashentry
*he
,
556 .type
= GETHOSTBYNAME
,
560 return addhstbyX (db
, -1, &req
, db
->data
+ he
->key
, he
->owner
, he
, dh
);
565 addhstbyaddr (struct database_dyn
*db
, int fd
, request_header
*req
,
566 void *key
, uid_t uid
)
568 addhstbyX (db
, fd
, req
, key
, uid
, NULL
, NULL
);
573 readdhstbyaddr (struct database_dyn
*db
, struct hashentry
*he
,
578 .type
= GETHOSTBYADDR
,
582 return addhstbyX (db
, -1, &req
, db
->data
+ he
->key
, he
->owner
, he
, dh
);
587 addhstbynamev6 (struct database_dyn
*db
, int fd
, request_header
*req
,
588 void *key
, uid_t uid
)
590 addhstbyX (db
, fd
, req
, key
, uid
, NULL
, NULL
);
595 readdhstbynamev6 (struct database_dyn
*db
, struct hashentry
*he
,
600 .type
= GETHOSTBYNAMEv6
,
604 return addhstbyX (db
, -1, &req
, db
->data
+ he
->key
, he
->owner
, he
, dh
);
609 addhstbyaddrv6 (struct database_dyn
*db
, int fd
, request_header
*req
,
610 void *key
, uid_t uid
)
612 addhstbyX (db
, fd
, req
, key
, uid
, NULL
, NULL
);
617 readdhstbyaddrv6 (struct database_dyn
*db
, struct hashentry
*he
,
622 .type
= GETHOSTBYADDRv6
,
626 return addhstbyX (db
, -1, &req
, db
->data
+ he
->key
, he
->owner
, he
, dh
);