~ubuntu-branches/ubuntu/karmic/dante/karmic

« back to all changes in this revision

Viewing changes to sockd/hostcache.c

  • Committer: Bazaar Package Importer
  • Author(s): Thijs Kinkhorst
  • Date: 2006-10-19 12:09:39 UTC
  • mfrom: (3.1.1 dapper)
  • Revision ID: james.westby@ubuntu.com-20061019120939-t818x24e2tn8be5k
Tags: 1.1.18-2.1
* Non-maintainer upload for RC bug.
* Make sure changelogs are installed into all packages (Closes: #393568).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003
3
 
 *      Inferno Nettverk A/S, Norway.  All rights reserved.
4
 
 *
5
 
 * Redistribution and use in source and binary forms, with or without
6
 
 * modification, are permitted provided that the following conditions
7
 
 * are met:
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.
18
 
 *
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.
29
 
 *
30
 
 * Inferno Nettverk A/S requests users of this software to return to
31
 
 *
32
 
 *  Software Distribution Coordinator  or  sdc@inet.no
33
 
 *  Inferno Nettverk A/S
34
 
 *  Oslo Research Park
35
 
 *  Gaustadall�en 21
36
 
 *  NO-0349 Oslo
37
 
 *  Norway
38
 
 *
39
 
 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40
 
 * the rights to redistribute these changes.
41
 
 *
42
 
 */
43
 
 
44
 
#include "common.h"
45
 
 
46
 
static const char rcsid[] =
47
 
"$Id: hostcache.c,v 1.24 2003/07/01 13:21:29 michaels Exp $";
48
 
 
49
 
__BEGIN_DECLS
50
 
 
51
 
#if SOCKS_SERVER
52
 
 
53
 
#undef gethostbyaddr
54
 
#undef gethostbyname
55
 
 
56
 
#if SOCKSLIBRARY_DYNAMIC
57
 
 
58
 
#define gethostbyaddr(addr, len, type)  sys_gethostbyaddr(addr, len, type)
59
 
#define gethostbyname(name)                             sys_gethostbyname(name)
60
 
 
61
 
#endif /* SOCKSLIBRARY_DYNAMIC */
62
 
 
63
 
static struct hostent *
64
 
hostentupdate __P((struct hostent *old, const struct hostent *new));
65
 
/*
66
 
 * Updates "old" with the contents of "new", freeing any
67
 
 * resources currently used by "old".
68
 
 * Returns:
69
 
 *              On success: "old", updated.
70
 
 *              On failure: NULL.
71
 
*/
72
 
 
73
 
static int
74
 
hosthash __P((const char *name, size_t size));
75
 
/*
76
 
 * Calculates a hashvalue for "name" and returns it's value.
77
 
 * Size of hashtable is given by "size".
78
 
*/
79
 
 
80
 
static int
81
 
addrhash __P((in_addr_t addr, size_t size));
82
 
/*
83
 
 * Calculates a hashvalue for "addr" and returns it's value.
84
 
 * Size of hashtable is given by "size".
85
 
*/
86
 
 
87
 
#endif /* SOCKS_SERVER */
88
 
 
89
 
static char **
90
 
listrealloc __P((char ***old, const char ***new, int length));
91
 
/*
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
96
 
 * of every string.
97
 
 * Returns:
98
 
 *              On success: "**old", with the contents of "new".
99
 
 *              On failure: NULL.
100
 
*/
101
 
 
102
 
__END_DECLS
103
 
 
104
 
struct hostent *
105
 
hostentdup(hostent)
106
 
        const struct hostent *hostent;
107
 
{
108
 
        static struct hostent dupedinit;
109
 
        struct hostent *duped;
110
 
 
111
 
        if ((duped = (struct hostent *)malloc(sizeof(*duped))) == NULL)
112
 
                return NULL;
113
 
 
114
 
        *duped = dupedinit;
115
 
 
116
 
        if ((duped->h_name = strdup(hostent->h_name)) == NULL) {
117
 
                hostentfree(duped);
118
 
                return NULL;
119
 
        }
120
 
 
121
 
        if (listrealloc(&duped->h_aliases, (const char ***)&hostent->h_aliases, -1)
122
 
        == NULL) {
123
 
                hostentfree(duped);
124
 
                return NULL;
125
 
        }
126
 
 
127
 
        duped->h_addrtype = hostent->h_addrtype;
128
 
        duped->h_length = hostent->h_length;
129
 
 
130
 
        if (listrealloc(&duped->h_addr_list, (const char ***)&hostent->h_addr_list,
131
 
        hostent->h_length) == NULL) {
132
 
                hostentfree(duped);
133
 
                return NULL;
134
 
        }
135
 
 
136
 
        return duped;
137
 
}
138
 
 
139
 
void
140
 
hostentfree(hostent)
141
 
        struct hostent *hostent;
142
 
{
143
 
        char **p;
144
 
 
145
 
        if (hostent == NULL)
146
 
                return;
147
 
 
148
 
        free(hostent->h_name);
149
 
        hostent->h_name = NULL;
150
 
 
151
 
        if (hostent->h_aliases != NULL)
152
 
                for (p = hostent->h_aliases; *p != NULL; ++p)
153
 
                        free(*p);
154
 
        free(hostent->h_aliases);
155
 
        hostent->h_aliases = NULL;
156
 
 
157
 
        if (hostent->h_addr_list != NULL)
158
 
                for (p = hostent->h_addr_list; *p != NULL; ++p)
159
 
                        free(*p);
160
 
        free(hostent->h_addr_list);
161
 
        hostent->h_addr_list = NULL;
162
 
 
163
 
        free(hostent);
164
 
}
165
 
 
166
 
static char **
167
 
listrealloc(old, new, length)
168
 
        char ***old;
169
 
        const char ***new;
170
 
        int length;
171
 
{
172
 
        int i, oldi, newi;
173
 
 
174
 
        /* entries we can reallocate, starting at 0. */
175
 
        oldi = 0;
176
 
        if (*old != NULL)
177
 
                while ((*old)[oldi] != NULL)
178
 
                        ++oldi;
179
 
 
180
 
        newi = 0;
181
 
        while ((*new)[newi] != NULL)
182
 
                ++newi;
183
 
 
184
 
        for (i = newi; i < oldi; ++i)
185
 
                free((*old)[i]);
186
 
 
187
 
        if ((*old = (char **)realloc(*old, sizeof(**new) * (newi + 1))) == NULL)
188
 
                return NULL;
189
 
 
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)
193
 
                        return NULL;
194
 
 
195
 
                if (length < 0)
196
 
                        strcpy((*old)[newi], (*new)[newi]);
197
 
                else
198
 
                        memcpy((*old)[newi], (*new)[newi], (size_t)length);
199
 
        }
200
 
        (*old)[newi] = NULL;
201
 
 
202
 
        return *old;
203
 
}
204
 
 
205
 
#if SOCKS_SERVER
206
 
 
207
 
struct hostent *
208
 
cgethostbyname(name)
209
 
        const char *name;
210
 
{
211
 
        const char *function = "cgethostbyname()";
212
 
        static struct {
213
 
                unsigned                                allocated:1;
214
 
                char                                    host[MAXHOSTNAMELEN];
215
 
                time_t                          written;
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));
221
 
        size_t i;
222
 
        struct hostent *hostent;
223
 
 
224
 
#if SOCKD_CACHESTAT
225
 
        if (++count % SOCKD_CACHESTAT == 0)
226
 
                slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
227
 
#endif /* SOCKD_CACHESTAT */
228
 
 
229
 
        for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
230
 
                if (!table[i].allocated) {
231
 
                        if (freehost == NULL)
232
 
                                freehost = &table[i];
233
 
                        continue;
234
 
                }
235
 
 
236
 
                if (strcasecmp(table[i].host, name) == 0) {
237
 
                        if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
238
 
                                freehost = &table[i];
239
 
                                break;
240
 
                        }
241
 
                        ++hit;
242
 
                        return &table[i].hostent;
243
 
                }
244
 
        }
245
 
        ++miss;
246
 
 
247
 
        if ((hostent = gethostbyname(name)) == NULL)
248
 
                return NULL;
249
 
 
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];
254
 
                                break;
255
 
                        }
256
 
 
257
 
                        if (freehost->written < table[i].written) {
258
 
                                freehost = &table[i]; /* oldest. */
259
 
                                break;
260
 
                        }
261
 
                }
262
 
 
263
 
        if (hostentupdate(&freehost->hostent, hostent) == NULL) {
264
 
                freehost->allocated = 0;
265
 
                slog(LOG_WARNING, "%s: %s", NOMEM, function);
266
 
                return NULL;
267
 
        }
268
 
 
269
 
        SASSERTX(strlen(name) < sizeof(freehost->host));
270
 
        strcpy(freehost->host, name);
271
 
        time(&freehost->written);
272
 
        freehost->allocated = 1;
273
 
 
274
 
        return &freehost->hostent;
275
 
}
276
 
 
277
 
struct hostent *
278
 
cgethostbyaddr(addr, len, type)
279
 
        const char *addr;
280
 
        int len;
281
 
        int type;
282
 
{
283
 
        const char *function = "cgethostbyaddr()";
284
 
        static struct {
285
 
                unsigned                        allocated:1;
286
 
                in_addr_t                       addr;
287
 
                time_t                          written;
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 */
293
 
        const int hashi
294
 
        = addrhash(((const struct in_addr *)addr)->s_addr, ELEMENTS(table));
295
 
        size_t i;
296
 
        struct hostent *hostent;
297
 
 
298
 
#if SOCKD_CACHESTAT
299
 
        if (++count % SOCKD_CACHESTAT == 0)
300
 
                slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
301
 
#endif /* SOCKD_CACHESTAT */
302
 
 
303
 
        for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
304
 
                if (!table[i].allocated) {
305
 
                        if (freehost == NULL)
306
 
                                freehost = &table[i];
307
 
                        continue;
308
 
                }
309
 
 
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];
314
 
                                break;
315
 
                        }
316
 
                        ++hit;
317
 
                        return &table[i].hostent;
318
 
                }
319
 
        }
320
 
        ++miss;
321
 
 
322
 
        if ((hostent = gethostbyaddr(addr, len, type)) == NULL)
323
 
                return NULL;
324
 
 
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];
329
 
                                break;
330
 
                        }
331
 
 
332
 
                        if (freehost->written < table[i].written) {
333
 
                                freehost = &table[i]; /* oldest. */
334
 
                                break;
335
 
                        }
336
 
                }
337
 
 
338
 
        if (hostentupdate(&freehost->hostent, hostent) == NULL) {
339
 
                freehost->allocated = 0;
340
 
                slog(LOG_WARNING, "%s: %s", NOMEM, function);
341
 
                return NULL;
342
 
        }
343
 
 
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;
348
 
 
349
 
        return &freehost->hostent;
350
 
}
351
 
 
352
 
static int
353
 
hosthash(name, size)
354
 
        const char *name;
355
 
        size_t size;
356
 
{
357
 
        char *end;
358
 
        unsigned int value;
359
 
 
360
 
        /* end at second dot. */
361
 
        if ((end = strchr(name, '.')) != NULL)
362
 
                end = strchr(end, '.');
363
 
        if (end == NULL)
364
 
                end = strchr(name, NUL);
365
 
 
366
 
        SASSERTX(name <= end);
367
 
        value = 0;
368
 
        while (name != end)
369
 
                value = (value << 5) + *name++; /* MAW - DS&A: Horner's rule. */
370
 
 
371
 
        return value % size;
372
 
}
373
 
 
374
 
static int
375
 
addrhash(addr, size)
376
 
        in_addr_t addr;
377
 
        size_t size;
378
 
{
379
 
 
380
 
        return addr % size;
381
 
}
382
 
 
383
 
static struct hostent *
384
 
hostentupdate(old, new)
385
 
        struct hostent *old;
386
 
        const struct hostent *new;
387
 
{
388
 
 
389
 
        if ((old->h_name = (char *)realloc(old->h_name, strlen(new->h_name) + 1))
390
 
        == NULL)
391
 
                return NULL;
392
 
        strcpy(old->h_name, new->h_name);
393
 
 
394
 
        if (listrealloc(&old->h_aliases, (const char ***)&new->h_aliases, -1)
395
 
        == NULL)
396
 
                return NULL;
397
 
 
398
 
        old->h_addrtype = new->h_addrtype;
399
 
        old->h_length           = new->h_length;
400
 
 
401
 
        if (listrealloc(&old->h_addr_list, (const char ***)&new->h_addr_list,
402
 
        new->h_length) == NULL)
403
 
                return NULL;
404
 
 
405
 
        return old;
406
 
}
407
 
 
408
 
#endif /* SOCKS_SERVER */