~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to src/ipcache.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2006-11-11 10:32:06 UTC
  • Revision ID: james.westby@ubuntu.com-20061111103206-f3p0r9g0vq44rp3r
Tags: upstream-3.0.PRE5
ImportĀ upstreamĀ versionĀ 3.0.PRE5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * $Id: ipcache.cc,v 1.258 2006/08/21 00:50:41 robertc Exp $
 
4
 *
 
5
 * DEBUG: section 14    IP Cache
 
6
 * AUTHOR: Harvest Derived
 
7
 *
 
8
 * SQUID Web Proxy Cache          http://www.squid-cache.org/
 
9
 * ----------------------------------------------------------
 
10
 *
 
11
 *  Squid is the result of efforts by numerous individuals from
 
12
 *  the Internet community; see the CONTRIBUTORS file for full
 
13
 *  details.   Many organizations have provided support for Squid's
 
14
 *  development; see the SPONSORS file for full details.  Squid is
 
15
 *  Copyrighted (C) 2001 by the Regents of the University of
 
16
 *  California; see the COPYRIGHT file for full details.  Squid
 
17
 *  incorporates software developed and/or copyrighted by other
 
18
 *  sources; see the CREDITS file for full details.
 
19
 *
 
20
 *  This program is free software; you can redistribute it and/or modify
 
21
 *  it under the terms of the GNU General Public License as published by
 
22
 *  the Free Software Foundation; either version 2 of the License, or
 
23
 *  (at your option) any later version.
 
24
 *  
 
25
 *  This program is distributed in the hope that it will be useful,
 
26
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
27
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
28
 *  GNU General Public License for more details.
 
29
 *  
 
30
 *  You should have received a copy of the GNU General Public License
 
31
 *  along with this program; if not, write to the Free Software
 
32
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 
33
 *
 
34
 */
 
35
 
 
36
#include "squid.h"
 
37
#include "cbdata.h"
 
38
#include "event.h"
 
39
#include "CacheManager.h"
 
40
#include "SquidTime.h"
 
41
#include "Store.h"
 
42
#include "wordlist.h"
 
43
 
 
44
typedef struct _ipcache_entry ipcache_entry;
 
45
 
 
46
struct _ipcache_entry
 
47
{
 
48
    hash_link hash;             /* must be first */
 
49
    time_t lastref;
 
50
    time_t expires;
 
51
    ipcache_addrs addrs;
 
52
    IPH *handler;
 
53
    void *handlerData;
 
54
    char *error_message;
 
55
 
 
56
    struct timeval request_time;
 
57
    dlink_node lru;
 
58
    unsigned short locks;
 
59
 
 
60
    struct
 
61
    {
 
62
 
 
63
unsigned int negcached:
 
64
        1;
 
65
 
 
66
unsigned int fromhosts:
 
67
        1;
 
68
    }
 
69
 
 
70
    flags;
 
71
};
 
72
 
 
73
static struct
 
74
{
 
75
    int requests;
 
76
    int replies;
 
77
    int hits;
 
78
    int misses;
 
79
    int negative_hits;
 
80
}
 
81
 
 
82
IpcacheStats;
 
83
 
 
84
static dlink_list lru_list;
 
85
 
 
86
static FREE ipcacheFreeEntry;
 
87
#if USE_DNSSERVERS
 
88
static HLPCB ipcacheHandleReply;
 
89
#else
 
90
static IDNSCB ipcacheHandleReply;
 
91
#endif
 
92
static IPH dummy_handler;
 
93
static int ipcacheExpiredEntry(ipcache_entry *);
 
94
static int ipcache_testname(void);
 
95
#if USE_DNSSERVERS
 
96
static int ipcacheParse(ipcache_entry *, const char *buf);
 
97
#else
 
98
static int ipcacheParse(ipcache_entry *, rfc1035_rr *, int, const char *error);
 
99
#endif
 
100
static ipcache_entry *ipcache_get(const char *);
 
101
static void ipcacheLockEntry(ipcache_entry *);
 
102
static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
 
103
static void ipcacheUnlockEntry(ipcache_entry *);
 
104
static void ipcacheRelease(ipcache_entry *);
 
105
 
 
106
static ipcache_addrs static_addrs;
 
107
static hash_table *ip_table = NULL;
 
108
 
 
109
static long ipcache_low = 180;
 
110
static long ipcache_high = 200;
 
111
 
 
112
#if LIBRESOLV_DNS_TTL_HACK
 
113
extern int _dns_ttl_;
 
114
#endif
 
115
 
 
116
static int
 
117
ipcache_testname(void)
 
118
{
 
119
    wordlist *w = NULL;
 
120
    debug(14, 1) ("Performing DNS Tests...\n");
 
121
 
 
122
    if ((w = Config.dns_testname_list) == NULL)
 
123
        return 1;
 
124
 
 
125
    for (; w; w = w->next) {
 
126
        if (gethostbyname(w->key) != NULL)
 
127
            return 1;
 
128
    }
 
129
 
 
130
    return 0;
 
131
}
 
132
 
 
133
/* removes the given ipcache entry */
 
134
static void
 
135
ipcacheRelease(ipcache_entry * i)
 
136
{
 
137
    debug(14, 3) ("ipcacheRelease: Releasing entry for '%s'\n", (const char *) i->hash.key);
 
138
    hash_remove_link(ip_table, (hash_link *) i);
 
139
    dlinkDelete(&i->lru, &lru_list);
 
140
    ipcacheFreeEntry(i);
 
141
}
 
142
 
 
143
static ipcache_entry *
 
144
ipcache_get(const char *name)
 
145
{
 
146
    if (ip_table != NULL)
 
147
        return (ipcache_entry *) hash_lookup(ip_table, name);
 
148
    else
 
149
        return NULL;
 
150
}
 
151
 
 
152
static int
 
153
ipcacheExpiredEntry(ipcache_entry * i)
 
154
{
 
155
    /* all static entries are locked, so this takes care of them too */
 
156
 
 
157
    if (i->locks != 0)
 
158
        return 0;
 
159
 
 
160
    if (i->addrs.count == 0)
 
161
        if (0 == i->flags.negcached)
 
162
            return 1;
 
163
 
 
164
    if (i->expires > squid_curtime)
 
165
        return 0;
 
166
 
 
167
    return 1;
 
168
}
 
169
 
 
170
void
 
171
ipcache_purgelru(void *voidnotused)
 
172
{
 
173
    dlink_node *m;
 
174
    dlink_node *prev = NULL;
 
175
    ipcache_entry *i;
 
176
    int removed = 0;
 
177
    eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
 
178
 
 
179
    for (m = lru_list.tail; m; m = prev) {
 
180
        if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low)
 
181
            break;
 
182
 
 
183
        prev = m->prev;
 
184
 
 
185
        i = (ipcache_entry *)m->data;
 
186
 
 
187
        if (i->locks != 0)
 
188
            continue;
 
189
 
 
190
        ipcacheRelease(i);
 
191
 
 
192
        removed++;
 
193
    }
 
194
 
 
195
    debug(14, 9) ("ipcache_purgelru: removed %d entries\n", removed);
 
196
}
 
197
 
 
198
/* purges entries added from /etc/hosts (or whatever). */
 
199
static void
 
200
purge_entries_fromhosts(void)
 
201
{
 
202
    dlink_node *m = lru_list.head;
 
203
    ipcache_entry *i = NULL, *t;
 
204
 
 
205
    while (m) {
 
206
        if (i != NULL) {        /* need to delay deletion */
 
207
            ipcacheRelease(i);  /* we just override locks */
 
208
            i = NULL;
 
209
        }
 
210
 
 
211
        t = (ipcache_entry*)m->data;
 
212
 
 
213
        if (t->flags.fromhosts)
 
214
            i = t;
 
215
 
 
216
        m = m->next;
 
217
    }
 
218
 
 
219
    if (i != NULL)
 
220
        ipcacheRelease(i);
 
221
}
 
222
 
 
223
/* create blank ipcache_entry */
 
224
static ipcache_entry *
 
225
ipcacheCreateEntry(const char *name)
 
226
{
 
227
    static ipcache_entry *i;
 
228
    i = (ipcache_entry *)memAllocate(MEM_IPCACHE_ENTRY);
 
229
    i->hash.key = xstrdup(name);
 
230
    i->expires = squid_curtime + Config.negativeDnsTtl;
 
231
    return i;
 
232
}
 
233
 
 
234
static void
 
235
ipcacheAddEntry(ipcache_entry * i)
 
236
{
 
237
    hash_link *e = (hash_link *)hash_lookup(ip_table, i->hash.key);
 
238
 
 
239
    if (NULL != e) {
 
240
        /* avoid colission */
 
241
        ipcache_entry *q = (ipcache_entry *) e;
 
242
        ipcacheRelease(q);
 
243
    }
 
244
 
 
245
    hash_join(ip_table, &i->hash);
 
246
    dlinkAdd(i, &i->lru, &lru_list);
 
247
    i->lastref = squid_curtime;
 
248
}
 
249
 
 
250
/* walks down the pending list, calling handlers */
 
251
static void
 
252
ipcacheCallback(ipcache_entry * i)
 
253
{
 
254
    IPH *callback = i->handler;
 
255
    void *cbdata;
 
256
    i->lastref = squid_curtime;
 
257
 
 
258
    if (!i->handler)
 
259
        return;
 
260
 
 
261
    ipcacheLockEntry(i);
 
262
 
 
263
    callback = i->handler;
 
264
 
 
265
    i->handler = NULL;
 
266
 
 
267
    if (cbdataReferenceValidDone(i->handlerData, &cbdata)) {
 
268
        dns_error_message = i->error_message;
 
269
        callback(i->flags.negcached ? NULL : &i->addrs, cbdata);
 
270
    }
 
271
 
 
272
    ipcacheUnlockEntry(i);
 
273
}
 
274
 
 
275
#if USE_DNSSERVERS
 
276
static int
 
277
ipcacheParse(ipcache_entry *i, const char *inbuf)
 
278
{
 
279
    LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
 
280
    char *token;
 
281
    int ipcount = 0;
 
282
    int ttl;
 
283
    char *A[32];
 
284
    const char *name = (const char *)i->hash.key;
 
285
    i->expires = squid_curtime + Config.negativeDnsTtl;
 
286
    i->flags.negcached = 1;
 
287
    safe_free(i->addrs.in_addrs);
 
288
    safe_free(i->addrs.bad_mask);
 
289
    safe_free(i->error_message);
 
290
    i->addrs.count = 0;
 
291
 
 
292
    if (inbuf == NULL) {
 
293
        debug(14, 1) ("ipcacheParse: Got <NULL> reply\n");
 
294
        i->error_message = xstrdup("Internal Error");
 
295
        return -1;
 
296
    }
 
297
 
 
298
    xstrncpy(buf, inbuf, DNS_INBUF_SZ);
 
299
    debug(14, 5) ("ipcacheParse: parsing: {%s}\n", buf);
 
300
    token = strtok(buf, w_space);
 
301
 
 
302
    if (NULL == token) {
 
303
        debug(14, 1) ("ipcacheParse: expecting result, got '%s'\n", inbuf);
 
304
        i->error_message = xstrdup("Internal Error");
 
305
        return -1;
 
306
    }
 
307
 
 
308
    if (0 == strcmp(token, "$fail")) {
 
309
        token = strtok(NULL, "\n");
 
310
        assert(NULL != token);
 
311
        i->error_message = xstrdup(token);
 
312
        return 0;
 
313
    }
 
314
 
 
315
    if (0 != strcmp(token, "$addr")) {
 
316
        debug(14, 1) ("ipcacheParse: expecting '$addr', got '%s' in response to '%s'\n", inbuf, name);
 
317
        i->error_message = xstrdup("Internal Error");
 
318
        return -1;
 
319
    }
 
320
 
 
321
    token = strtok(NULL, w_space);
 
322
 
 
323
    if (NULL == token) {
 
324
        debug(14, 1) ("ipcacheParse: expecting TTL, got '%s' in response to '%s'\n", inbuf, name);
 
325
        i->error_message = xstrdup("Internal Error");
 
326
        return -1;
 
327
    }
 
328
 
 
329
    ttl = atoi(token);
 
330
 
 
331
    while (NULL != (token = strtok(NULL, w_space))) {
 
332
        A[ipcount] = token;
 
333
 
 
334
        if (++ipcount == 32)
 
335
            break;
 
336
    }
 
337
 
 
338
    if (ipcount > 0) {
 
339
        int j, k;
 
340
 
 
341
        i->addrs.in_addrs = (struct IN_ADDR *)xcalloc(ipcount, sizeof(struct IN_ADDR));
 
342
        i->addrs.bad_mask = (unsigned char *)xcalloc(ipcount, sizeof(unsigned char));
 
343
 
 
344
        for (j = 0, k = 0; k < ipcount; k++) {
 
345
            if (safe_inet_addr(A[k], &i->addrs.in_addrs[j]))
 
346
                j++;
 
347
            else
 
348
                debug(14, 1) ("ipcacheParse: Invalid IP address '%s' in response to '%s'\n", A[k], name);
 
349
        }
 
350
 
 
351
        i->addrs.count = (unsigned char) j;
 
352
    }
 
353
 
 
354
    if (i->addrs.count <= 0) {
 
355
        debug(14, 1) ("ipcacheParse: No addresses in response to '%s'\n", name);
 
356
        return -1;
 
357
    }
 
358
 
 
359
    if (ttl == 0 || ttl > Config.positiveDnsTtl)
 
360
        ttl = Config.positiveDnsTtl;
 
361
 
 
362
    if (ttl < Config.negativeDnsTtl)
 
363
        ttl = Config.negativeDnsTtl;
 
364
 
 
365
    i->expires = squid_curtime + ttl;
 
366
 
 
367
    i->flags.negcached = 0;
 
368
 
 
369
    return i->addrs.count;
 
370
}
 
371
 
 
372
#else
 
373
static int
 
374
ipcacheParse(ipcache_entry *i, rfc1035_rr * answers, int nr, const char *error_message)
 
375
{
 
376
    int k;
 
377
    int j;
 
378
    int na = 0;
 
379
    int ttl = 0;
 
380
    const char *name = (const char *)i->hash.key;
 
381
    i->expires = squid_curtime + Config.negativeDnsTtl;
 
382
    i->flags.negcached = 1;
 
383
    safe_free(i->addrs.in_addrs);
 
384
    safe_free(i->addrs.bad_mask);
 
385
    safe_free(i->error_message);
 
386
    i->addrs.count = 0;
 
387
 
 
388
    if (nr < 0) {
 
389
        debug(14, 3) ("ipcacheParse: Lookup failed '%s' for '%s'\n",
 
390
                      error_message, (const char *)i->hash.key);
 
391
        i->error_message = xstrdup(error_message);
 
392
        return -1;
 
393
    }
 
394
 
 
395
    if (nr == 0) {
 
396
        debug(14, 3) ("ipcacheParse: No DNS records in response to '%s'\n", name);
 
397
        i->error_message = xstrdup("No DNS records");
 
398
        return 0;
 
399
    }
 
400
 
 
401
    assert(answers);
 
402
 
 
403
    for (k = 0; k < nr; k++) {
 
404
        if (answers[k].type != RFC1035_TYPE_A)
 
405
            continue;
 
406
 
 
407
        if (answers[k]._class != RFC1035_CLASS_IN)
 
408
            continue;
 
409
 
 
410
        if (answers[k].rdlength != 4) {
 
411
            debug(14, 1)("ipcacheParse: Invalid IP address in response to '%s'\n", name);
 
412
            continue;
 
413
        }
 
414
 
 
415
        na++;
 
416
    }
 
417
 
 
418
    if (na == 0) {
 
419
        debug(14, 1) ("ipcacheParse: No Address records in response to '%s'\n", name);
 
420
        i->error_message = xstrdup("No Address records");
 
421
        return 0;
 
422
    }
 
423
 
 
424
    i->addrs.in_addrs = (struct IN_ADDR *)xcalloc(na, sizeof(struct IN_ADDR));
 
425
    i->addrs.bad_mask = (unsigned char *)xcalloc(na, sizeof(unsigned char));
 
426
 
 
427
    for (j = 0, k = 0; k < nr; k++) {
 
428
        if (answers[k]._class != RFC1035_CLASS_IN)
 
429
            continue;
 
430
 
 
431
        if (answers[k].type == RFC1035_TYPE_A) {
 
432
            if (answers[k].rdlength != 4)
 
433
                continue;
 
434
 
 
435
            xmemcpy(&i->addrs.in_addrs[j++], answers[k].rdata, 4);
 
436
 
 
437
            debug(14, 3) ("ipcacheParse: #%d %s\n",
 
438
                          j - 1,
 
439
                          inet_ntoa(i->addrs.in_addrs[j - 1]));
 
440
        } else if (answers[k].type != RFC1035_TYPE_CNAME)
 
441
            continue;
 
442
 
 
443
        if (ttl == 0 || (int) answers[k].ttl < ttl)
 
444
            ttl = answers[k].ttl;
 
445
 
 
446
    }
 
447
 
 
448
    assert(j == na);
 
449
 
 
450
    if (na < 256)
 
451
        i->addrs.count = (unsigned char) na;
 
452
    else
 
453
        i->addrs.count = 255;
 
454
 
 
455
    if (ttl == 0 || ttl > Config.positiveDnsTtl)
 
456
        ttl = Config.positiveDnsTtl;
 
457
 
 
458
    if (ttl < Config.negativeDnsTtl)
 
459
        ttl = Config.negativeDnsTtl;
 
460
 
 
461
    i->expires = squid_curtime + ttl;
 
462
 
 
463
    i->flags.negcached = 0;
 
464
 
 
465
    return i->addrs.count;
 
466
}
 
467
 
 
468
#endif
 
469
 
 
470
static void
 
471
#if USE_DNSSERVERS
 
472
ipcacheHandleReply(void *data, char *reply)
 
473
#else
 
474
ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_message)
 
475
#endif
 
476
{
 
477
    ipcache_entry *i;
 
478
    static_cast<generic_cbdata *>(data)->unwrap(&i);
 
479
    IpcacheStats.replies++;
 
480
    statHistCount(&statCounter.dns.svc_time,
 
481
                  tvSubMsec(i->request_time, current_time));
 
482
#if USE_DNSSERVERS
 
483
 
 
484
    ipcacheParse(i, reply);
 
485
#else
 
486
 
 
487
    ipcacheParse(i, answers, na, error_message);
 
488
#endif
 
489
 
 
490
    ipcacheAddEntry(i);
 
491
    ipcacheCallback(i);
 
492
}
 
493
 
 
494
void
 
495
ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
 
496
{
 
497
    ipcache_entry *i = NULL;
 
498
    const ipcache_addrs *addrs = NULL;
 
499
    generic_cbdata *c;
 
500
    assert(handler != NULL);
 
501
    debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name);
 
502
    IpcacheStats.requests++;
 
503
 
 
504
    if (name == NULL || name[0] == '\0') {
 
505
        debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n");
 
506
        dns_error_message = "Invalid hostname";
 
507
        handler(NULL, handlerData);
 
508
        return;
 
509
    }
 
510
 
 
511
    if ((addrs = ipcacheCheckNumeric(name))) {
 
512
        dns_error_message = NULL;
 
513
        handler(addrs, handlerData);
 
514
        return;
 
515
    }
 
516
 
 
517
    i = ipcache_get(name);
 
518
 
 
519
    if (NULL == i) {
 
520
        /* miss */
 
521
        (void) 0;
 
522
    } else if (ipcacheExpiredEntry(i)) {
 
523
        /* hit, but expired -- bummer */
 
524
        ipcacheRelease(i);
 
525
        i = NULL;
 
526
    } else {
 
527
        /* hit */
 
528
        debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name);
 
529
 
 
530
        if (i->flags.negcached)
 
531
            IpcacheStats.negative_hits++;
 
532
        else
 
533
            IpcacheStats.hits++;
 
534
 
 
535
        i->handler = handler;
 
536
 
 
537
        i->handlerData = cbdataReference(handlerData);
 
538
 
 
539
        ipcacheCallback(i);
 
540
 
 
541
        return;
 
542
    }
 
543
 
 
544
    debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name);
 
545
    IpcacheStats.misses++;
 
546
    i = ipcacheCreateEntry(name);
 
547
    i->handler = handler;
 
548
    i->handlerData = cbdataReference(handlerData);
 
549
    i->request_time = current_time;
 
550
    c = new generic_cbdata(i);
 
551
#if USE_DNSSERVERS
 
552
 
 
553
    dnsSubmit(hashKeyStr(&i->hash), ipcacheHandleReply, c);
 
554
#else
 
555
 
 
556
    idnsALookup(hashKeyStr(&i->hash), ipcacheHandleReply, c);
 
557
#endif
 
558
}
 
559
 
 
560
/* initialize the ipcache */
 
561
void
 
562
ipcache_init(void)
 
563
{
 
564
    int n;
 
565
    debug(14, 3) ("Initializing IP Cache...\n");
 
566
    memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
 
567
    memset(&lru_list, '\0', sizeof(lru_list));
 
568
    /* test naming lookup */
 
569
 
 
570
    if (!opt_dns_tests) {
 
571
        debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.\n");
 
572
    } else if (!ipcache_testname()) {
 
573
        fatal("ipcache_init: DNS name lookup tests failed.");
 
574
    } else {
 
575
        debug(14, 1) ("Successful DNS name lookup tests...\n");
 
576
    }
 
577
 
 
578
    memset(&static_addrs, '\0', sizeof(ipcache_addrs));
 
579
 
 
580
    static_addrs.in_addrs = (struct IN_ADDR *)xcalloc(1, sizeof(struct IN_ADDR));
 
581
    static_addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
 
582
    ipcache_high = (long) (((float) Config.ipcache.size *
 
583
                            (float) Config.ipcache.high) / (float) 100);
 
584
    ipcache_low = (long) (((float) Config.ipcache.size *
 
585
                           (float) Config.ipcache.low) / (float) 100);
 
586
    n = hashPrime(ipcache_high / 4);
 
587
    ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
 
588
    memDataInit(MEM_IPCACHE_ENTRY, "ipcache_entry", sizeof(ipcache_entry), 0);
 
589
}
 
590
 
 
591
void
 
592
ipcacheRegisterWithCacheManager(CacheManager & manager)
 
593
{
 
594
    manager.registerAction("ipcache",
 
595
                           "IP Cache Stats and Contents",
 
596
                           stat_ipcache_get, 0, 1);
 
597
}
 
598
 
 
599
const ipcache_addrs *
 
600
ipcache_gethostbyname(const char *name, int flags)
 
601
{
 
602
    ipcache_entry *i = NULL;
 
603
    ipcache_addrs *addrs;
 
604
    assert(name);
 
605
    debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%x\n", name, flags);
 
606
    IpcacheStats.requests++;
 
607
    i = ipcache_get(name);
 
608
 
 
609
    if (NULL == i) {
 
610
        (void) 0;
 
611
    } else if (ipcacheExpiredEntry(i)) {
 
612
        ipcacheRelease(i);
 
613
        i = NULL;
 
614
    } else if (i->flags.negcached) {
 
615
        IpcacheStats.negative_hits++;
 
616
        dns_error_message = i->error_message;
 
617
        return NULL;
 
618
    } else {
 
619
        IpcacheStats.hits++;
 
620
        i->lastref = squid_curtime;
 
621
        dns_error_message = i->error_message;
 
622
        return &i->addrs;
 
623
    }
 
624
 
 
625
    dns_error_message = NULL;
 
626
 
 
627
    if ((addrs = ipcacheCheckNumeric(name)))
 
628
        return addrs;
 
629
 
 
630
    IpcacheStats.misses++;
 
631
 
 
632
    if (flags & IP_LOOKUP_IF_MISS)
 
633
        ipcache_nbgethostbyname(name, dummy_handler, NULL);
 
634
 
 
635
    return NULL;
 
636
}
 
637
 
 
638
static void
 
639
ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
 
640
{
 
641
    int k;
 
642
    storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
 
643
                      hashKeyStr(&i->hash),
 
644
                      i->flags.fromhosts ? 'H' : ' ',
 
645
                      i->flags.negcached ? 'N' : ' ',
 
646
                      (int) (squid_curtime - i->lastref),
 
647
                      (int) ((i->flags.fromhosts ? -1 : i->expires - squid_curtime)),
 
648
                      (int) i->addrs.count,
 
649
                      (int) i->addrs.badcount);
 
650
 
 
651
    for (k = 0; k < (int) i->addrs.count; k++) {
 
652
        storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]),
 
653
                          i->addrs.bad_mask[k] ? "BAD" : "OK ");
 
654
    }
 
655
 
 
656
    storeAppendPrintf(sentry, "\n");
 
657
}
 
658
 
 
659
/* process objects list */
 
660
void
 
661
stat_ipcache_get(StoreEntry * sentry)
 
662
{
 
663
    dlink_node *m;
 
664
    assert(ip_table != NULL);
 
665
    storeAppendPrintf(sentry, "IP Cache Statistics:\n");
 
666
    storeAppendPrintf(sentry, "IPcache Entries: %d\n",
 
667
                      memInUse(MEM_IPCACHE_ENTRY));
 
668
    storeAppendPrintf(sentry, "IPcache Requests: %d\n",
 
669
                      IpcacheStats.requests);
 
670
    storeAppendPrintf(sentry, "IPcache Hits: %d\n",
 
671
                      IpcacheStats.hits);
 
672
    storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
 
673
                      IpcacheStats.negative_hits);
 
674
    storeAppendPrintf(sentry, "IPcache Misses: %d\n",
 
675
                      IpcacheStats.misses);
 
676
    storeAppendPrintf(sentry, "\n\n");
 
677
    storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
 
678
    storeAppendPrintf(sentry, " %-29.29s %3s %6s %6s %1s\n",
 
679
                      "Hostname",
 
680
                      "Flg",
 
681
                      "lstref",
 
682
                      "TTL",
 
683
                      "N");
 
684
 
 
685
    for (m = lru_list.head; m; m = m->next)
 
686
        ipcacheStatPrint((ipcache_entry *)m->data, sentry);
 
687
}
 
688
 
 
689
static void
 
690
dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused)
 
691
{
 
692
    return;
 
693
}
 
694
 
 
695
void
 
696
ipcacheInvalidate(const char *name)
 
697
{
 
698
    ipcache_entry *i;
 
699
 
 
700
    if ((i = ipcache_get(name)) == NULL)
 
701
        return;
 
702
 
 
703
    i->expires = squid_curtime;
 
704
 
 
705
    /*
 
706
     * NOTE, don't call ipcacheRelease here becuase we might be here due
 
707
     * to a thread started from a callback.
 
708
     */
 
709
}
 
710
 
 
711
void
 
712
ipcacheInvalidateNegative(const char *name)
 
713
{
 
714
    ipcache_entry *i;
 
715
 
 
716
    if ((i = ipcache_get(name)) == NULL)
 
717
        return;
 
718
 
 
719
    if (i->flags.negcached)
 
720
        i->expires = squid_curtime;
 
721
 
 
722
    /*
 
723
     * NOTE, don't call ipcacheRelease here becuase we might be here due
 
724
     * to a thread started from a callback.
 
725
     */
 
726
}
 
727
 
 
728
ipcache_addrs *
 
729
ipcacheCheckNumeric(const char *name)
 
730
{
 
731
 
 
732
    struct IN_ADDR ip;
 
733
    /* check if it's already a IP address in text form. */
 
734
 
 
735
    if (!safe_inet_addr(name, &ip))
 
736
        return NULL;
 
737
 
 
738
    static_addrs.count = 1;
 
739
 
 
740
    static_addrs.cur = 0;
 
741
 
 
742
    static_addrs.in_addrs[0].s_addr = ip.s_addr;
 
743
 
 
744
    static_addrs.bad_mask[0] = FALSE;
 
745
 
 
746
    static_addrs.badcount = 0;
 
747
 
 
748
    return &static_addrs;
 
749
}
 
750
 
 
751
static void
 
752
ipcacheLockEntry(ipcache_entry * i)
 
753
{
 
754
    if (i->locks++ == 0) {
 
755
        dlinkDelete(&i->lru, &lru_list);
 
756
        dlinkAdd(i, &i->lru, &lru_list);
 
757
    }
 
758
}
 
759
 
 
760
static void
 
761
ipcacheUnlockEntry(ipcache_entry * i)
 
762
{
 
763
    assert(i->locks > 0);
 
764
    i->locks--;
 
765
 
 
766
    if (ipcacheExpiredEntry(i))
 
767
        ipcacheRelease(i);
 
768
}
 
769
 
 
770
void
 
771
ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
 
772
{
 
773
    ipcache_entry *i;
 
774
    unsigned char k;
 
775
    assert(name || ia);
 
776
 
 
777
    if (NULL == ia) {
 
778
        if ((i = ipcache_get(name)) == NULL)
 
779
            return;
 
780
 
 
781
        if (i->flags.negcached)
 
782
            return;
 
783
 
 
784
        ia = &i->addrs;
 
785
    }
 
786
 
 
787
    for (k = 0; k < ia->count; k++) {
 
788
        if (++ia->cur == ia->count)
 
789
            ia->cur = 0;
 
790
 
 
791
        if (!ia->bad_mask[ia->cur])
 
792
            break;
 
793
    }
 
794
 
 
795
    if (k == ia->count) {
 
796
        /* All bad, reset to All good */
 
797
        debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OK\n",
 
798
                      name);
 
799
 
 
800
        for (k = 0; k < ia->count; k++)
 
801
            ia->bad_mask[k] = 0;
 
802
 
 
803
        ia->badcount = 0;
 
804
 
 
805
        ia->cur = 0;
 
806
    }
 
807
 
 
808
    debug(14, 3) ("ipcacheCycleAddr: %s now at %s\n", name,
 
809
                  inet_ntoa(ia->in_addrs[ia->cur]));
 
810
}
 
811
 
 
812
/*
 
813
 * Marks the given address as BAD and calls ipcacheCycleAddr to
 
814
 * advance the current pointer to the next OK address.
 
815
 */
 
816
void
 
817
 
 
818
ipcacheMarkBadAddr(const char *name, struct IN_ADDR addr)
 
819
{
 
820
    ipcache_entry *i;
 
821
    ipcache_addrs *ia;
 
822
    int k;
 
823
 
 
824
    if ((i = ipcache_get(name)) == NULL)
 
825
        return;
 
826
 
 
827
    ia = &i->addrs;
 
828
 
 
829
    for (k = 0; k < (int) ia->count; k++)
 
830
    {
 
831
        if (ia->in_addrs[k].s_addr == addr.s_addr)
 
832
            break;
 
833
    }
 
834
 
 
835
    if (k == (int) ia->count)   /* not found */
 
836
        return;
 
837
 
 
838
    if (!ia->bad_mask[k])
 
839
    {
 
840
        ia->bad_mask[k] = TRUE;
 
841
        ia->badcount++;
 
842
        i->expires = XMIN(squid_curtime + XMAX((time_t)60, Config.negativeDnsTtl), i->expires);
 
843
        debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]\n", name, inet_ntoa(addr));
 
844
    }
 
845
 
 
846
    ipcacheCycleAddr(name, ia);
 
847
}
 
848
 
 
849
void
 
850
 
 
851
ipcacheMarkGoodAddr(const char *name, struct IN_ADDR addr)
 
852
{
 
853
    ipcache_entry *i;
 
854
    ipcache_addrs *ia;
 
855
    int k;
 
856
 
 
857
    if ((i = ipcache_get(name)) == NULL)
 
858
        return;
 
859
 
 
860
    ia = &i->addrs;
 
861
 
 
862
    for (k = 0; k < (int) ia->count; k++)
 
863
    {
 
864
        if (ia->in_addrs[k].s_addr == addr.s_addr)
 
865
            break;
 
866
    }
 
867
 
 
868
    if (k == (int) ia->count)   /* not found */
 
869
        return;
 
870
 
 
871
    if (!ia->bad_mask[k])       /* already OK */
 
872
        return;
 
873
 
 
874
    ia->bad_mask[k] = FALSE;
 
875
 
 
876
    ia->badcount--;
 
877
 
 
878
    debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]\n", name, inet_ntoa(addr));
 
879
}
 
880
 
 
881
static void
 
882
ipcacheFreeEntry(void *data)
 
883
{
 
884
    ipcache_entry *i = (ipcache_entry *)data;
 
885
    safe_free(i->addrs.in_addrs);
 
886
    safe_free(i->addrs.bad_mask);
 
887
    safe_free(i->hash.key);
 
888
    safe_free(i->error_message);
 
889
    memFree(i, MEM_IPCACHE_ENTRY);
 
890
}
 
891
 
 
892
void
 
893
ipcacheFreeMemory(void)
 
894
{
 
895
    hashFreeItems(ip_table, ipcacheFreeEntry);
 
896
    hashFreeMemory(ip_table);
 
897
    ip_table = NULL;
 
898
}
 
899
 
 
900
/* Recalculate IP cache size upon reconfigure */
 
901
void
 
902
ipcache_restart(void)
 
903
{
 
904
    ipcache_high = (long) (((float) Config.ipcache.size *
 
905
                            (float) Config.ipcache.high) / (float) 100);
 
906
    ipcache_low = (long) (((float) Config.ipcache.size *
 
907
                           (float) Config.ipcache.low) / (float) 100);
 
908
    purge_entries_fromhosts();
 
909
}
 
910
 
 
911
/*
 
912
 *  adds a "static" entry from /etc/hosts.  
 
913
 *  returns 0 upon success, 1 if the ip address is invalid
 
914
 */
 
915
int
 
916
ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
 
917
{
 
918
    ipcache_entry *i;
 
919
 
 
920
    struct IN_ADDR ip;
 
921
 
 
922
    if (!safe_inet_addr(ipaddr, &ip)) {
 
923
        if (strchr(ipaddr, ':') && strspn(ipaddr, "0123456789abcdefABCDEF:") == strlen(ipaddr)) {
 
924
            debug(14, 3) ("ipcacheAddEntryFromHosts: Skipping IPv6 address '%s'\n", ipaddr);
 
925
        } else {
 
926
            debug(14, 1) ("ipcacheAddEntryFromHosts: Bad IP address '%s'\n",
 
927
                          ipaddr);
 
928
        }
 
929
 
 
930
        return 1;
 
931
    }
 
932
 
 
933
    if ((i = ipcache_get(name))) {
 
934
        if (1 == i->flags.fromhosts) {
 
935
            ipcacheUnlockEntry(i);
 
936
        } else if (i->locks > 0) {
 
937
            debug(14, 1) ("ipcacheAddEntryFromHosts: can't add static entry"
 
938
                          " for locked name '%s'\n", name);
 
939
            return 1;
 
940
        } else {
 
941
            ipcacheRelease(i);
 
942
        }
 
943
    }
 
944
 
 
945
    i = ipcacheCreateEntry(name);
 
946
    i->addrs.count = 1;
 
947
    i->addrs.cur = 0;
 
948
    i->addrs.badcount = 0;
 
949
 
 
950
    i->addrs.in_addrs = (struct IN_ADDR *)xcalloc(1, sizeof(struct IN_ADDR));
 
951
    i->addrs.bad_mask = (unsigned char *)xcalloc(1, sizeof(unsigned char));
 
952
    i->addrs.in_addrs[0].s_addr = ip.s_addr;
 
953
    i->addrs.bad_mask[0] = FALSE;
 
954
    i->flags.fromhosts = 1;
 
955
    ipcacheAddEntry(i);
 
956
    ipcacheLockEntry(i);
 
957
    return 0;
 
958
}
 
959
 
 
960
#ifdef SQUID_SNMP
 
961
/*
 
962
 * The function to return the ip cache statistics to via SNMP
 
963
 */
 
964
 
 
965
variable_list *
 
966
snmp_netIpFn(variable_list * Var, snint * ErrP)
 
967
{
 
968
    variable_list *Answer = NULL;
 
969
    debug(49, 5) ("snmp_netIpFn: Processing request:\n");
 
970
    snmpDebugOid(5, Var->name, Var->name_length);
 
971
    *ErrP = SNMP_ERR_NOERROR;
 
972
 
 
973
    switch (Var->name[LEN_SQ_NET + 1]) {
 
974
 
 
975
    case IP_ENT:
 
976
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
977
                                      memInUse(MEM_IPCACHE_ENTRY),
 
978
                                      SMI_GAUGE32);
 
979
        break;
 
980
 
 
981
    case IP_REQ:
 
982
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
983
                                      IpcacheStats.requests,
 
984
                                      SMI_COUNTER32);
 
985
        break;
 
986
 
 
987
    case IP_HITS:
 
988
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
989
                                      IpcacheStats.hits,
 
990
                                      SMI_COUNTER32);
 
991
        break;
 
992
 
 
993
    case IP_PENDHIT:
 
994
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
995
                                      0,
 
996
                                      SMI_GAUGE32);
 
997
        break;
 
998
 
 
999
    case IP_NEGHIT:
 
1000
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
1001
                                      IpcacheStats.negative_hits,
 
1002
                                      SMI_COUNTER32);
 
1003
        break;
 
1004
 
 
1005
    case IP_MISS:
 
1006
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
1007
                                      IpcacheStats.misses,
 
1008
                                      SMI_COUNTER32);
 
1009
        break;
 
1010
 
 
1011
    case IP_GHBN:
 
1012
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
1013
                                      0, /* deprecated */
 
1014
                                      SMI_COUNTER32);
 
1015
        break;
 
1016
 
 
1017
    case IP_LOC:
 
1018
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
1019
                                      0, /* deprecated */
 
1020
                                      SMI_COUNTER32);
 
1021
        break;
 
1022
 
 
1023
    default:
 
1024
        *ErrP = SNMP_ERR_NOSUCHNAME;
 
1025
        snmp_var_free(Answer);
 
1026
        return (NULL);
 
1027
    }
 
1028
 
 
1029
    return Answer;
 
1030
}
 
1031
 
 
1032
#endif /*SQUID_SNMP */