2
* Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003
3
* Inferno Nettverk A/S, Norway. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. The above copyright notice, this list of conditions and the following
9
* disclaimer must appear in all copies of the software, derivative works
10
* or modified versions, and any portions thereof, aswell as in all
11
* supporting documentation.
12
* 2. All advertising materials mentioning features or use of this software
13
* must display the following acknowledgement:
14
* This product includes software developed by
15
* Inferno Nettverk A/S, Norway.
16
* 3. The name of the author may not be used to endorse or promote products
17
* derived from this software without specific prior written permission.
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
* Inferno Nettverk A/S requests users of this software to return to
32
* Software Distribution Coordinator or sdc@inet.no
33
* Inferno Nettverk A/S
39
* any improvements or extensions that they make and grant Inferno Nettverk A/S
40
* the rights to redistribute these changes.
46
static const char rcsid[] =
47
"$Id: hostcache.c,v 1.24 2003/07/01 13:21:29 michaels Exp $";
56
#if SOCKSLIBRARY_DYNAMIC
58
#define gethostbyaddr(addr, len, type) sys_gethostbyaddr(addr, len, type)
59
#define gethostbyname(name) sys_gethostbyname(name)
61
#endif /* SOCKSLIBRARY_DYNAMIC */
63
static struct hostent *
64
hostentupdate __P((struct hostent *old, const struct hostent *new));
66
* Updates "old" with the contents of "new", freeing any
67
* resources currently used by "old".
69
* On success: "old", updated.
74
hosthash __P((const char *name, size_t size));
76
* Calculates a hashvalue for "name" and returns it's value.
77
* Size of hashtable is given by "size".
81
addrhash __P((in_addr_t addr, size_t size));
83
* Calculates a hashvalue for "addr" and returns it's value.
84
* Size of hashtable is given by "size".
87
#endif /* SOCKS_SERVER */
90
listrealloc __P((char ***old, const char ***new, int length));
92
* Reallocates "old" and copies in the contents of "new".
93
* The last element of both "old" and "new" must be NULL.
94
* If "length" is less than 0, each element is assumed to
95
* be NUL terminated, otherwise "length" gives the total length
98
* On success: "**old", with the contents of "new".
106
const struct hostent *hostent;
108
static struct hostent dupedinit;
109
struct hostent *duped;
111
if ((duped = (struct hostent *)malloc(sizeof(*duped))) == NULL)
116
if ((duped->h_name = strdup(hostent->h_name)) == NULL) {
121
if (listrealloc(&duped->h_aliases, (const char ***)&hostent->h_aliases, -1)
127
duped->h_addrtype = hostent->h_addrtype;
128
duped->h_length = hostent->h_length;
130
if (listrealloc(&duped->h_addr_list, (const char ***)&hostent->h_addr_list,
131
hostent->h_length) == NULL) {
141
struct hostent *hostent;
148
free(hostent->h_name);
149
hostent->h_name = NULL;
151
if (hostent->h_aliases != NULL)
152
for (p = hostent->h_aliases; *p != NULL; ++p)
154
free(hostent->h_aliases);
155
hostent->h_aliases = NULL;
157
if (hostent->h_addr_list != NULL)
158
for (p = hostent->h_addr_list; *p != NULL; ++p)
160
free(hostent->h_addr_list);
161
hostent->h_addr_list = NULL;
167
listrealloc(old, new, length)
174
/* entries we can reallocate, starting at 0. */
177
while ((*old)[oldi] != NULL)
181
while ((*new)[newi] != NULL)
184
for (i = newi; i < oldi; ++i)
187
if ((*old = (char **)realloc(*old, sizeof(**new) * (newi + 1))) == NULL)
190
for (newi = 0; (*new)[newi] != NULL; ++newi, --oldi) {
191
if (((*old)[newi] = (char *)realloc(oldi > 0 ? (*old)[newi] : NULL,
192
length < 0 ? (strlen((*new)[newi]) + 1) : length)) == NULL)
196
strcpy((*old)[newi], (*new)[newi]);
198
memcpy((*old)[newi], (*new)[newi], (size_t)length);
211
const char *function = "cgethostbyname()";
213
unsigned allocated:1;
214
char host[MAXHOSTNAMELEN];
216
struct hostent hostent;
217
} table[SOCKD_HOSTCACHE], *freehost;
218
static unsigned int hit, miss, count;
219
const time_t timenow = time(NULL);
220
const int hashi = hosthash(name, ELEMENTS(table));
222
struct hostent *hostent;
225
if (++count % SOCKD_CACHESTAT == 0)
226
slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
227
#endif /* SOCKD_CACHESTAT */
229
for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
230
if (!table[i].allocated) {
231
if (freehost == NULL)
232
freehost = &table[i];
236
if (strcasecmp(table[i].host, name) == 0) {
237
if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
238
freehost = &table[i];
242
return &table[i].hostent;
247
if ((hostent = gethostbyname(name)) == NULL)
250
if (freehost == NULL)
251
for (i = hashi, freehost = &table[i]; i < ELEMENTS(table); ++i) {
252
if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
253
freehost = &table[i];
257
if (freehost->written < table[i].written) {
258
freehost = &table[i]; /* oldest. */
263
if (hostentupdate(&freehost->hostent, hostent) == NULL) {
264
freehost->allocated = 0;
265
slog(LOG_WARNING, "%s: %s", NOMEM, function);
269
SASSERTX(strlen(name) < sizeof(freehost->host));
270
strcpy(freehost->host, name);
271
time(&freehost->written);
272
freehost->allocated = 1;
274
return &freehost->hostent;
278
cgethostbyaddr(addr, len, type)
283
const char *function = "cgethostbyaddr()";
285
unsigned allocated:1;
288
struct hostent hostent;
289
} table[SOCKD_ADDRESSCACHE], *freehost;
290
static unsigned long int hit, miss, count;
291
const time_t timenow = time(NULL);
292
/* LINTED pointer casts may be troublesome */
294
= addrhash(((const struct in_addr *)addr)->s_addr, ELEMENTS(table));
296
struct hostent *hostent;
299
if (++count % SOCKD_CACHESTAT == 0)
300
slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
301
#endif /* SOCKD_CACHESTAT */
303
for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
304
if (!table[i].allocated) {
305
if (freehost == NULL)
306
freehost = &table[i];
310
/* LINTED pointer casts may be troublesome */
311
if (table[i].addr == ((const struct in_addr *)addr)->s_addr) {
312
if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
313
freehost = &table[i];
317
return &table[i].hostent;
322
if ((hostent = gethostbyaddr(addr, len, type)) == NULL)
325
if (freehost == NULL)
326
for (i = hashi, freehost = &table[i]; i < ELEMENTS(table); ++i) {
327
if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
328
freehost = &table[i];
332
if (freehost->written < table[i].written) {
333
freehost = &table[i]; /* oldest. */
338
if (hostentupdate(&freehost->hostent, hostent) == NULL) {
339
freehost->allocated = 0;
340
slog(LOG_WARNING, "%s: %s", NOMEM, function);
344
/* LINTED pointer casts may be troublesome */
345
freehost->addr = ((const struct in_addr *)addr)->s_addr;
346
time(&freehost->written);
347
freehost->allocated = 1;
349
return &freehost->hostent;
360
/* end at second dot. */
361
if ((end = strchr(name, '.')) != NULL)
362
end = strchr(end, '.');
364
end = strchr(name, NUL);
366
SASSERTX(name <= end);
369
value = (value << 5) + *name++; /* MAW - DS&A: Horner's rule. */
383
static struct hostent *
384
hostentupdate(old, new)
386
const struct hostent *new;
389
if ((old->h_name = (char *)realloc(old->h_name, strlen(new->h_name) + 1))
392
strcpy(old->h_name, new->h_name);
394
if (listrealloc(&old->h_aliases, (const char ***)&new->h_aliases, -1)
398
old->h_addrtype = new->h_addrtype;
399
old->h_length = new->h_length;
401
if (listrealloc(&old->h_addr_list, (const char ***)&new->h_addr_list,
402
new->h_length) == NULL)
408
#endif /* SOCKS_SERVER */