1 /* Cache handling for host lookup.
2 Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library 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 GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
32 #include <arpa/inet.h>
33 #include <arpa/nameser.h>
39 /* This is the standard reply in case the service is disabled. */
40 static const hst_response_header disabled =
42 version: NSCD_VERSION,
52 /* This is the struct describing how to write this record. */
53 const struct iovec hst_iov_disabled =
55 iov_base: (void *) &disabled,
56 iov_len: sizeof (disabled)
60 /* This is the standard reply in case we haven't found the dataset. */
61 static const hst_response_header notfound =
63 version: NSCD_VERSION,
73 /* This is the struct describing how to write this record. */
74 static const struct iovec iov_notfound =
76 iov_base: (void *) ¬found,
77 iov_len: sizeof (notfound)
83 hst_response_header resp;
89 cache_addhst (struct database *db, int fd, request_header *req, void *key,
90 struct hostent *hst, uid_t owner)
94 time_t t = time (NULL);
98 /* We have no data. This means we send the standard reply for this
102 total = sizeof (notfound);
104 written = writev (fd, &iov_notfound, 1);
106 copy = malloc (req->key_len);
108 error (EXIT_FAILURE, errno, _("while allocating key copy"));
109 memcpy (copy, key, req->key_len);
111 /* Compute the timeout time. */
114 /* Now get the lock to safely insert the records. */
115 pthread_rwlock_rdlock (&db->lock);
117 cache_add (req->type, copy, req->key_len, ¬found,
118 sizeof (notfound), (void *) -1, 0, t, db, owner);
120 pthread_rwlock_unlock (&db->lock);
124 /* Determine the I/O structure. */
125 struct hostdata *data;
126 size_t h_name_len = strlen (hst->h_name) + 1;
127 size_t h_aliases_cnt;
128 size_t *h_aliases_len;
129 size_t h_addr_list_cnt;
133 char *key_copy = NULL;
137 /* Determine the number of aliases. */
139 for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
141 /* Determine the length of all aliases. */
142 h_aliases_len = alloca (h_aliases_cnt * sizeof (size_t));
144 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
146 h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
147 total += h_aliases_len[cnt];
150 /* Determine the number of addresses. */
152 for (cnt = 0; hst->h_addr_list[cnt]; ++cnt)
155 /* We allocate all data in one memory block: the iov vector,
156 the response header and the dataset itself. */
157 total += (sizeof (struct hostdata)
159 + h_aliases_cnt * sizeof (size_t)
160 + h_addr_list_cnt * hst->h_length);
162 data = (struct hostdata *) malloc (total + req->key_len);
164 /* There is no reason to go on. */
165 error (EXIT_FAILURE, errno, _("while allocating cache entry"));
167 data->resp.found = 1;
168 data->resp.h_name_len = h_name_len;
169 data->resp.h_aliases_cnt = h_aliases_cnt;
170 data->resp.h_addrtype = hst->h_addrtype;
171 data->resp.h_length = hst->h_length;
172 data->resp.h_addr_list_cnt = h_addr_list_cnt;
173 data->resp.error = NETDB_SUCCESS;
177 cp = mempcpy (cp, hst->h_name, h_name_len);
178 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (size_t));
180 /* The normal addresses first. */
182 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
183 cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
185 /* Then the aliases. */
187 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
188 cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
190 assert (cp == data->strdata + total - sizeof (hst_response_header));
192 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
193 that the answer we get from the NSS does not contain the key
194 itself. This is the case if the resolver is used and the name
195 is extended by the domainnames from /etc/resolv.conf. Therefore
196 we explicitly add the name here. */
197 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
198 key_copy = memcpy (cp, key, req->key_len);
200 /* We write the dataset before inserting it to the database
201 since while inserting this thread might block and so would
202 unnecessarily let the receiver wait. */
203 written = write (fd, data, total);
205 addr_list_type = (hst->h_length == NS_INADDRSZ
206 ? GETHOSTBYADDR : GETHOSTBYADDRv6);
208 /* Compute the timeout time. */
211 /* Now get the lock to safely insert the records. */
212 pthread_rwlock_rdlock (&db->lock);
214 /* First add all the aliases. */
215 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
217 if (addr_list_type == GETHOSTBYADDR)
218 cache_add (GETHOSTBYNAME, aliases, h_aliases_len[cnt], data, total,
219 data, 0, t, db, owner);
221 cache_add (GETHOSTBYNAMEv6, aliases, h_aliases_len[cnt], data, total,
222 data, 0, t, db, owner);
224 aliases += h_aliases_len[cnt];
227 /* Next the normal addresses. */
228 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
230 cache_add (addr_list_type, addresses, hst->h_length, data, total,
231 data, 0, t, db, owner);
232 addresses += hst->h_length;
235 /* If necessary the IPv6 addresses. */
236 if (addr_list_type == GETHOSTBYADDR)
237 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
239 cache_add (GETHOSTBYADDRv6, addresses, IN6ADDRSZ, data, total,
240 data, 0, t, db, owner);
241 addresses += IN6ADDRSZ;
244 /* If necessary add the key for this request. */
245 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
247 if (addr_list_type == GETHOSTBYADDR)
248 cache_add (GETHOSTBYNAME, key_copy, req->key_len, data, total,
249 data, 0, t, db, owner);
250 cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len, data,
251 total, data, 0, t, db, owner);
254 /* And finally the name. We mark this as the last entry. */
255 if (addr_list_type == GETHOSTBYADDR)
256 cache_add (GETHOSTBYNAME, data->strdata, h_name_len, data, total, data,
258 cache_add (GETHOSTBYNAMEv6, data->strdata, h_name_len, data,
259 total, data, 1, t, db, owner);
261 pthread_rwlock_unlock (&db->lock);
264 if (written != total)
267 dbg_log (_("short write in %s: %s"), __FUNCTION__,
268 strerror_r (errno, buf, sizeof (buf)));
274 addhstbyname (struct database *db, int fd, request_header *req,
275 void *key, uid_t uid)
277 /* Search for the entry matching the key. Please note that we don't
278 look again in the table whether the dataset is now available. We
279 simply insert it. It does not matter if it is in there twice. The
280 pruning function only will look at the timestamp. */
282 char *buffer = alloca (buflen);
283 struct hostent resultbuf;
288 dbg_log (_("Haven't found \"%s\" in hosts cache!"), key);
292 oldeuid = geteuid ();
296 while (__gethostbyname2_r (key, AF_INET, &resultbuf, buffer, buflen,
298 && h_errno == NETDB_INTERNAL
303 buffer = alloca (buflen);
309 cache_addhst (db, fd, req, key, hst, uid);
314 addhstbyaddr (struct database *db, int fd, request_header *req,
315 void *key, uid_t uid)
317 /* Search for the entry matching the key. Please note that we don't
318 look again in the table whether the dataset is now available. We
319 simply insert it. It does not matter if it is in there twice. The
320 pruning function only will look at the timestamp. */
322 char *buffer = alloca (buflen);
323 struct hostent resultbuf;
329 char buf[INET_ADDRSTRLEN];
330 dbg_log (_("Haven't found \"%s\" in hosts cache!"),
331 inet_ntop (AF_INET, key, buf, sizeof (buf)));
336 oldeuid = geteuid ();
340 while (__gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, &resultbuf, buffer,
341 buflen, &hst, &h_errno) != 0
342 && h_errno == NETDB_INTERNAL
347 buffer = alloca (buflen);
353 cache_addhst (db, fd, req, key, hst, uid);
358 addhstbynamev6 (struct database *db, int fd, request_header *req,
359 void *key, uid_t uid)
361 /* Search for the entry matching the key. Please note that we don't
362 look again in the table whether the dataset is now available. We
363 simply insert it. It does not matter if it is in there twice. The
364 pruning function only will look at the timestamp. */
366 char *buffer = alloca (buflen);
367 struct hostent resultbuf;
373 char buf[INET6_ADDRSTRLEN];
375 dbg_log (_("Haven't found \"%s\" in hosts cache!"),
376 inet_ntop (AF_INET6, key, buf, sizeof (buf)));
381 oldeuid = geteuid ();
385 while (__gethostbyname2_r (key, AF_INET6, &resultbuf, buffer, buflen,
387 && h_errno == NETDB_INTERNAL
392 buffer = alloca (buflen);
398 cache_addhst (db, fd, req, key, hst, uid);
403 addhstbyaddrv6 (struct database *db, int fd, request_header *req,
404 void *key, uid_t uid)
406 /* Search for the entry matching the key. Please note that we don't
407 look again in the table whether the dataset is now available. We
408 simply insert it. It does not matter if it is in there twice. The
409 pruning function only will look at the timestamp. */
411 char *buffer = alloca (buflen);
412 struct hostent resultbuf;
418 char buf[INET6_ADDRSTRLEN];
419 dbg_log (_("Haven't found \"%s\" in hosts cache!"),
420 inet_ntop (AF_INET6, key, buf, sizeof (buf)));
425 oldeuid = geteuid ();
429 while (__gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, &resultbuf,
430 buffer, buflen, &hst, &h_errno) != 0
431 && h_errno == NETDB_INTERNAL
436 buffer = alloca (buflen);
442 cache_addhst (db, fd, req, key, hst, uid);