]>
Commit | Line | Data |
---|---|---|
30a4f2a8 | 1 | /* |
c021888f | 2 | * $Id: ipcache.cc,v 1.72 1996/10/15 16:40:09 wessels Exp $ |
30a4f2a8 | 3 | * |
4 | * DEBUG: section 14 IP Cache | |
5 | * AUTHOR: Harvest Derived | |
6 | * | |
7 | * SQUID Internet Object Cache http://www.nlanr.net/Squid/ | |
8 | * -------------------------------------------------------- | |
9 | * | |
10 | * Squid is the result of efforts by numerous individuals from the | |
11 | * Internet community. Development is led by Duane Wessels of the | |
12 | * National Laboratory for Applied Network Research and funded by | |
13 | * the National Science Foundation. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify | |
16 | * it under the terms of the GNU General Public License as published by | |
17 | * the Free Software Foundation; either version 2 of the License, or | |
18 | * (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | * | |
29 | */ | |
019dd986 | 30 | |
31 | /* | |
30a4f2a8 | 32 | * Copyright (c) 1994, 1995. All rights reserved. |
33 | * | |
34 | * The Harvest software was developed by the Internet Research Task | |
35 | * Force Research Group on Resource Discovery (IRTF-RD): | |
36 | * | |
37 | * Mic Bowman of Transarc Corporation. | |
38 | * Peter Danzig of the University of Southern California. | |
39 | * Darren R. Hardy of the University of Colorado at Boulder. | |
40 | * Udi Manber of the University of Arizona. | |
41 | * Michael F. Schwartz of the University of Colorado at Boulder. | |
42 | * Duane Wessels of the University of Colorado at Boulder. | |
43 | * | |
44 | * This copyright notice applies to software in the Harvest | |
45 | * ``src/'' directory only. Users should consult the individual | |
46 | * copyright notices in the ``components/'' subdirectories for | |
47 | * copyright information about other software bundled with the | |
48 | * Harvest source code distribution. | |
49 | * | |
50 | * TERMS OF USE | |
51 | * | |
52 | * The Harvest software may be used and re-distributed without | |
53 | * charge, provided that the software origin and research team are | |
54 | * cited in any use of the system. Most commonly this is | |
55 | * accomplished by including a link to the Harvest Home Page | |
56 | * (http://harvest.cs.colorado.edu/) from the query page of any | |
57 | * Broker you deploy, as well as in the query result pages. These | |
58 | * links are generated automatically by the standard Broker | |
59 | * software distribution. | |
60 | * | |
61 | * The Harvest software is provided ``as is'', without express or | |
62 | * implied warranty, and with no support nor obligation to assist | |
63 | * in its use, correction, modification or enhancement. We assume | |
64 | * no liability with respect to the infringement of copyrights, | |
65 | * trade secrets, or any patents, and are not responsible for | |
66 | * consequential damages. Proper use of the Harvest software is | |
67 | * entirely the responsibility of the user. | |
68 | * | |
69 | * DERIVATIVE WORKS | |
70 | * | |
71 | * Users may make derivative works from the Harvest software, subject | |
72 | * to the following constraints: | |
73 | * | |
74 | * - You must include the above copyright notice and these | |
75 | * accompanying paragraphs in all forms of derivative works, | |
76 | * and any documentation and other materials related to such | |
77 | * distribution and use acknowledge that the software was | |
78 | * developed at the above institutions. | |
79 | * | |
80 | * - You must notify IRTF-RD regarding your distribution of | |
81 | * the derivative work. | |
82 | * | |
83 | * - You must clearly notify users that your are distributing | |
84 | * a modified version and not the original Harvest software. | |
85 | * | |
86 | * - Any derivative product is also subject to these copyright | |
87 | * and use restrictions. | |
88 | * | |
89 | * Note that the Harvest software is NOT in the public domain. We | |
90 | * retain copyright, as specified above. | |
91 | * | |
92 | * HISTORY OF FREE SOFTWARE STATUS | |
93 | * | |
94 | * Originally we required sites to license the software in cases | |
95 | * where they were going to build commercial products/services | |
96 | * around Harvest. In June 1995 we changed this policy. We now | |
97 | * allow people to use the core Harvest software (the code found in | |
98 | * the Harvest ``src/'' directory) for free. We made this change | |
99 | * in the interest of encouraging the widest possible deployment of | |
100 | * the technology. The Harvest software is really a reference | |
101 | * implementation of a set of protocols and formats, some of which | |
102 | * we intend to standardize. We encourage commercial | |
103 | * re-implementations of code complying to this set of standards. | |
019dd986 | 104 | */ |
44a47c6e | 105 | |
106 | #include "squid.h" | |
107 | ||
090089c4 | 108 | #define MAX_LINELEN (4096) |
090089c4 | 109 | |
30a4f2a8 | 110 | #define IP_LOW_WATER 90 |
111 | #define IP_HIGH_WATER 95 | |
090089c4 | 112 | |
30a4f2a8 | 113 | struct _ip_pending { |
090089c4 | 114 | int fd; |
115 | IPH handler; | |
30a4f2a8 | 116 | void *handlerData; |
090089c4 | 117 | struct _ip_pending *next; |
30a4f2a8 | 118 | }; |
090089c4 | 119 | |
f88bb09c | 120 | struct ipcacheQueueData { |
121 | struct ipcacheQueueData *next; | |
122 | ipcache_entry *i; | |
123 | }; | |
30a4f2a8 | 124 | |
125 | static struct { | |
126 | int requests; | |
f88bb09c | 127 | int replies; |
30a4f2a8 | 128 | int hits; |
129 | int misses; | |
130 | int pending_hits; | |
131 | int negative_hits; | |
30a4f2a8 | 132 | int errors; |
133 | int avg_svc_time; | |
134 | int ghbn_calls; /* # calls to blocking gethostbyname() */ | |
30a4f2a8 | 135 | } IpcacheStats; |
090089c4 | 136 | |
67508012 | 137 | static int ipcache_testname _PARAMS((void)); |
138 | static int ipcache_compareLastRef _PARAMS((ipcache_entry **, ipcache_entry **)); | |
139 | static int ipcache_reverseLastRef _PARAMS((ipcache_entry **, ipcache_entry **)); | |
140 | static int ipcache_dnsHandleRead _PARAMS((int, dnsserver_t *)); | |
141 | static ipcache_entry *ipcache_parsebuffer _PARAMS((char *buf, dnsserver_t *)); | |
142 | static void ipcache_release _PARAMS((ipcache_entry *)); | |
143 | static ipcache_entry *ipcache_GetFirst _PARAMS((void)); | |
144 | static ipcache_entry *ipcache_GetNext _PARAMS((void)); | |
145 | static ipcache_entry *ipcache_create _PARAMS((void)); | |
146 | static void ipcache_add_to_hash _PARAMS((ipcache_entry *)); | |
147 | static void ipcache_call_pending _PARAMS((ipcache_entry *)); | |
148 | static void ipcache_add _PARAMS((char *, ipcache_entry *, struct hostent *, int)); | |
149 | static int ipcacheHasPending _PARAMS((ipcache_entry *)); | |
150 | static ipcache_entry *ipcache_get _PARAMS((char *)); | |
e5f6c5c2 | 151 | static void dummy_handler _PARAMS((int, ipcache_addrs *, void *)); |
67508012 | 152 | static int ipcacheExpiredEntry _PARAMS((ipcache_entry *)); |
153 | static void ipcacheAddPending _PARAMS((ipcache_entry *, int fd, IPH, void *)); | |
154 | static void ipcacheEnqueue _PARAMS((ipcache_entry *)); | |
155 | static void *ipcacheDequeue _PARAMS((void)); | |
156 | static void ipcache_dnsDispatch _PARAMS((dnsserver_t *, ipcache_entry *)); | |
e5f6c5c2 | 157 | static ipcache_addrs *ipcacheCheckNumeric _PARAMS((char *name)); |
67508012 | 158 | static void ipcacheStatPrint _PARAMS((ipcache_entry *, StoreEntry *)); |
159 | static void ipcacheUnlockEntry _PARAMS((ipcache_entry *)); | |
160 | static void ipcacheLockEntry _PARAMS((ipcache_entry *)); | |
30a4f2a8 | 161 | |
e5f6c5c2 | 162 | static ipcache_addrs static_addrs; |
30a4f2a8 | 163 | static HashID ip_table = 0; |
f88bb09c | 164 | static struct ipcacheQueueData *ipcacheQueueHead = NULL; |
165 | static struct ipcacheQueueData **ipcacheQueueTailP = &ipcacheQueueHead; | |
090089c4 | 166 | |
30a4f2a8 | 167 | static char ipcache_status_char[] = |
090089c4 | 168 | { |
30a4f2a8 | 169 | 'C', |
170 | 'N', | |
171 | 'P', | |
172 | 'D' | |
173 | }; | |
090089c4 | 174 | |
24382924 | 175 | static long ipcache_low = 180; |
176 | static long ipcache_high = 200; | |
f88bb09c | 177 | |
c021888f | 178 | #if LIBRESOLV_DNS_TTL_HACK |
179 | extern int _dns_ttl_; | |
180 | #endif | |
181 | ||
b8d8561b | 182 | static void |
183 | ipcacheEnqueue(ipcache_entry * i) | |
f88bb09c | 184 | { |
185 | struct ipcacheQueueData *new = xcalloc(1, sizeof(struct ipcacheQueueData)); | |
186 | new->i = i; | |
187 | *ipcacheQueueTailP = new; | |
188 | ipcacheQueueTailP = &new->next; | |
189 | } | |
190 | ||
b8d8561b | 191 | static void * |
0673c0ba | 192 | ipcacheDequeue(void) |
f88bb09c | 193 | { |
194 | struct ipcacheQueueData *old = NULL; | |
195 | ipcache_entry *i = NULL; | |
196 | if (ipcacheQueueHead) { | |
197 | i = ipcacheQueueHead->i; | |
198 | old = ipcacheQueueHead; | |
199 | ipcacheQueueHead = ipcacheQueueHead->next; | |
200 | if (ipcacheQueueHead == NULL) | |
201 | ipcacheQueueTailP = &ipcacheQueueHead; | |
202 | safe_free(old); | |
203 | } | |
204 | return i; | |
205 | } | |
206 | ||
b8d8561b | 207 | static int |
0673c0ba | 208 | ipcache_testname(void) |
090089c4 | 209 | { |
b09ad9fd | 210 | wordlist *w = NULL; |
6eb42cae | 211 | debug(14, 1, "Performing DNS Tests...\n"); |
b6f794d6 | 212 | if ((w = Config.dns_testname_list) == NULL) |
b09ad9fd | 213 | return 1; |
214 | for (; w; w = w->next) { | |
30a4f2a8 | 215 | IpcacheStats.ghbn_calls++; |
b09ad9fd | 216 | if (gethostbyname(w->key) != NULL) |
217 | return 1; | |
090089c4 | 218 | } |
b09ad9fd | 219 | return 0; |
090089c4 | 220 | } |
221 | ||
090089c4 | 222 | /* removes the given ipcache entry */ |
b8d8561b | 223 | static void |
224 | ipcache_release(ipcache_entry * i) | |
090089c4 | 225 | { |
30a4f2a8 | 226 | hash_link *table_entry = NULL; |
090089c4 | 227 | |
30a4f2a8 | 228 | if ((table_entry = hash_lookup(ip_table, i->name)) == NULL) { |
229 | debug(14, 0, "ipcache_release: Could not find key '%s'\n", i->name); | |
230 | return; | |
231 | } | |
f7a5493b | 232 | if (i != (ipcache_entry *) table_entry) |
233 | fatal_dump("ipcache_release: i != table_entry!"); | |
30a4f2a8 | 234 | if (i->status == IP_PENDING) { |
235 | debug(14, 1, "ipcache_release: Someone called on a PENDING entry\n"); | |
236 | return; | |
237 | } | |
238 | if (i->status == IP_DISPATCHED) { | |
239 | debug(14, 1, "ipcache_release: Someone called on a DISPATCHED entry\n"); | |
240 | return; | |
090089c4 | 241 | } |
30a4f2a8 | 242 | if (hash_remove_link(ip_table, table_entry)) { |
243 | debug(14, 0, "ipcache_release: hash_remove_link() failed for '%s'\n", | |
f7a5493b | 244 | i->name); |
30a4f2a8 | 245 | return; |
246 | } | |
f7a5493b | 247 | if (i->status == IP_CACHED) { |
e5f6c5c2 | 248 | safe_free(i->addrs.in_addrs); |
30a4f2a8 | 249 | debug(14, 5, "ipcache_release: Released IP cached record for '%s'.\n", |
f7a5493b | 250 | i->name); |
30a4f2a8 | 251 | } |
f7a5493b | 252 | safe_free(i->name); |
253 | safe_free(i->error_message); | |
254 | memset(i, '\0', sizeof(ipcache_entry)); | |
255 | safe_free(i); | |
30a4f2a8 | 256 | --meta_data.ipcache_count; |
257 | return; | |
090089c4 | 258 | } |
259 | ||
260 | /* return match for given name */ | |
b8d8561b | 261 | static ipcache_entry * |
262 | ipcache_get(char *name) | |
090089c4 | 263 | { |
264 | hash_link *e; | |
30a4f2a8 | 265 | static ipcache_entry *i; |
090089c4 | 266 | |
30a4f2a8 | 267 | i = NULL; |
090089c4 | 268 | if (ip_table) { |
269 | if ((e = hash_lookup(ip_table, name)) != NULL) | |
30a4f2a8 | 270 | i = (ipcache_entry *) e; |
090089c4 | 271 | } |
30a4f2a8 | 272 | return i; |
090089c4 | 273 | } |
274 | ||
090089c4 | 275 | /* get the first ip entry in the storage */ |
b8d8561b | 276 | static ipcache_entry * |
0673c0ba | 277 | ipcache_GetFirst(void) |
090089c4 | 278 | { |
30a4f2a8 | 279 | return (ipcache_entry *) hash_first(ip_table); |
090089c4 | 280 | } |
281 | ||
090089c4 | 282 | /* get the next ip entry in the storage for a given search pointer */ |
b8d8561b | 283 | static ipcache_entry * |
0673c0ba | 284 | ipcache_GetNext(void) |
090089c4 | 285 | { |
30a4f2a8 | 286 | return (ipcache_entry *) hash_next(ip_table); |
090089c4 | 287 | } |
288 | ||
b8d8561b | 289 | static int |
290 | ipcache_compareLastRef(ipcache_entry ** e1, ipcache_entry ** e2) | |
090089c4 | 291 | { |
292 | if (!e1 || !e2) | |
293 | fatal_dump(NULL); | |
090089c4 | 294 | if ((*e1)->lastref > (*e2)->lastref) |
295 | return (1); | |
090089c4 | 296 | if ((*e1)->lastref < (*e2)->lastref) |
297 | return (-1); | |
090089c4 | 298 | return (0); |
299 | } | |
300 | ||
b8d8561b | 301 | static int |
302 | ipcache_reverseLastRef(ipcache_entry ** e1, ipcache_entry ** e2) | |
af00901c | 303 | { |
304 | if ((*e1)->lastref < (*e2)->lastref) | |
305 | return (1); | |
306 | if ((*e1)->lastref > (*e2)->lastref) | |
307 | return (-1); | |
308 | return (0); | |
309 | } | |
310 | ||
b8d8561b | 311 | static int |
312 | ipcacheExpiredEntry(ipcache_entry * i) | |
30a4f2a8 | 313 | { |
30a4f2a8 | 314 | if (i->status == IP_PENDING) |
315 | return 0; | |
316 | if (i->status == IP_DISPATCHED) | |
317 | return 0; | |
620da955 | 318 | if (i->locks != 0) |
319 | return 0; | |
af00901c | 320 | if (i->expires > squid_curtime) |
30a4f2a8 | 321 | return 0; |
322 | return 1; | |
323 | } | |
090089c4 | 324 | |
325 | /* finds the LRU and deletes */ | |
b8d8561b | 326 | int |
0673c0ba | 327 | ipcache_purgelru(void) |
090089c4 | 328 | { |
30a4f2a8 | 329 | ipcache_entry *i = NULL; |
090089c4 | 330 | int local_ip_notpending_count = 0; |
331 | int removed = 0; | |
30a4f2a8 | 332 | int k; |
333 | ipcache_entry **LRU_list = NULL; | |
090089c4 | 334 | int LRU_list_count = 0; |
090089c4 | 335 | |
af00901c | 336 | LRU_list = xcalloc(meta_data.ipcache_count, sizeof(ipcache_entry *)); |
090089c4 | 337 | |
30a4f2a8 | 338 | for (i = ipcache_GetFirst(); i; i = ipcache_GetNext()) { |
339 | if (ipcacheExpiredEntry(i)) { | |
340 | ipcache_release(i); | |
341 | removed++; | |
342 | continue; | |
343 | } | |
af00901c | 344 | if (LRU_list_count == meta_data.ipcache_count) |
345 | break; | |
30a4f2a8 | 346 | if (i->status == IP_PENDING) |
347 | continue; | |
348 | if (i->status == IP_DISPATCHED) | |
349 | continue; | |
233794cd | 350 | if (i->locks != 0) |
351 | continue; | |
30a4f2a8 | 352 | local_ip_notpending_count++; |
353 | LRU_list[LRU_list_count++] = i; | |
090089c4 | 354 | } |
355 | ||
019dd986 | 356 | debug(14, 3, "ipcache_purgelru: ipcache_count: %5d\n", meta_data.ipcache_count); |
e5e3c3dd | 357 | debug(14, 3, " LRU candidates : %5d\n", LRU_list_count); |
30a4f2a8 | 358 | debug(14, 3, " high W mark : %5d\n", ipcache_high); |
359 | debug(14, 3, " low W mark : %5d\n", ipcache_low); | |
360 | debug(14, 3, " not pending : %5d\n", local_ip_notpending_count); | |
090089c4 | 361 | |
362 | /* sort LRU candidate list */ | |
30a4f2a8 | 363 | qsort((char *) LRU_list, |
364 | LRU_list_count, | |
6e40f263 | 365 | sizeof(ipcache_entry *), |
366 | (QS) ipcache_compareLastRef); | |
af00901c | 367 | for (k = 0; k < LRU_list_count; k++) { |
368 | if (meta_data.ipcache_count < ipcache_low) | |
369 | break; | |
370 | if (LRU_list[k] == NULL) | |
371 | break; | |
30a4f2a8 | 372 | ipcache_release(LRU_list[k]); |
090089c4 | 373 | removed++; |
374 | } | |
375 | ||
30a4f2a8 | 376 | debug(14, 3, " removed : %5d\n", removed); |
090089c4 | 377 | safe_free(LRU_list); |
378 | return (removed > 0) ? 0 : -1; | |
379 | } | |
380 | ||
381 | ||
382 | /* create blank ipcache_entry */ | |
b8d8561b | 383 | static ipcache_entry * |
0673c0ba | 384 | ipcache_create(void) |
090089c4 | 385 | { |
090089c4 | 386 | static ipcache_entry *new; |
090089c4 | 387 | |
388 | if (meta_data.ipcache_count > ipcache_high) { | |
30a4f2a8 | 389 | if (ipcache_purgelru() < 0) |
390 | debug(14, 0, "HELP!! IP Cache is overflowing!\n"); | |
090089c4 | 391 | } |
392 | meta_data.ipcache_count++; | |
30a4f2a8 | 393 | new = xcalloc(1, sizeof(ipcache_entry)); |
090089c4 | 394 | /* set default to 4, in case parser fail to get token $h_length from |
395 | * dnsserver. */ | |
af00901c | 396 | new->expires = squid_curtime + Config.negativeDnsTtl; |
090089c4 | 397 | return new; |
398 | ||
399 | } | |
400 | ||
b8d8561b | 401 | static void |
402 | ipcache_add_to_hash(ipcache_entry * i) | |
090089c4 | 403 | { |
30a4f2a8 | 404 | if (hash_join(ip_table, (hash_link *) i)) { |
019dd986 | 405 | debug(14, 1, "ipcache_add_to_hash: Cannot add %s (%p) to hash table %d.\n", |
30a4f2a8 | 406 | i->name, i, ip_table); |
090089c4 | 407 | } |
30a4f2a8 | 408 | debug(14, 5, "ipcache_add_to_hash: name <%s>\n", i->name); |
090089c4 | 409 | } |
410 | ||
411 | ||
b8d8561b | 412 | static void |
413 | ipcache_add(char *name, ipcache_entry * i, struct hostent *hp, int cached) | |
090089c4 | 414 | { |
30a4f2a8 | 415 | int addr_count; |
30a4f2a8 | 416 | int k; |
090089c4 | 417 | |
30a4f2a8 | 418 | if (ipcache_get(name)) |
419 | fatal_dump("ipcache_add: somebody adding a duplicate!"); | |
019dd986 | 420 | debug(14, 10, "ipcache_add: Adding name '%s' (%s).\n", name, |
090089c4 | 421 | cached ? "cached" : "not cached"); |
30a4f2a8 | 422 | i->name = xstrdup(name); |
090089c4 | 423 | if (cached) { |
090089c4 | 424 | /* count for IPs */ |
425 | addr_count = 0; | |
aad137ea | 426 | while ((addr_count < 255) && *(hp->h_addr_list + addr_count)) |
090089c4 | 427 | ++addr_count; |
e5f6c5c2 | 428 | i->addrs.count = (unsigned char) addr_count; |
429 | i->addrs.in_addrs = xcalloc(addr_count, sizeof(struct in_addr)); | |
430 | for (k = 0; k < addr_count; k++) | |
431 | memcpy(&i->addrs.in_addrs[k].s_addr, | |
432 | *(hp->h_addr_list + k), | |
433 | hp->h_length); | |
30a4f2a8 | 434 | i->status = IP_CACHED; |
af00901c | 435 | i->expires = squid_curtime + Config.positiveDnsTtl; |
090089c4 | 436 | } else { |
30a4f2a8 | 437 | i->status = IP_NEGATIVE_CACHED; |
af00901c | 438 | i->expires = squid_curtime + Config.negativeDnsTtl; |
090089c4 | 439 | } |
30a4f2a8 | 440 | ipcache_add_to_hash(i); |
090089c4 | 441 | } |
442 | ||
090089c4 | 443 | /* walks down the pending list, calling handlers */ |
b8d8561b | 444 | static void |
445 | ipcache_call_pending(ipcache_entry * i) | |
090089c4 | 446 | { |
30a4f2a8 | 447 | struct _ip_pending *p = NULL; |
090089c4 | 448 | int nhandler = 0; |
449 | ||
30a4f2a8 | 450 | i->lastref = squid_curtime; |
090089c4 | 451 | |
620da955 | 452 | ipcacheLockEntry(i); |
30a4f2a8 | 453 | while (i->pending_head != NULL) { |
454 | p = i->pending_head; | |
455 | i->pending_head = p->next; | |
456 | if (p->handler) { | |
090089c4 | 457 | nhandler++; |
30a4f2a8 | 458 | dns_error_message = i->error_message; |
459 | p->handler(p->fd, | |
e5f6c5c2 | 460 | i->status == IP_CACHED ? &i->addrs : NULL, |
30a4f2a8 | 461 | p->handlerData); |
090089c4 | 462 | } |
30a4f2a8 | 463 | memset(p, '\0', sizeof(struct _ip_pending)); |
090089c4 | 464 | safe_free(p); |
465 | } | |
30a4f2a8 | 466 | i->pending_head = NULL; /* nuke list */ |
019dd986 | 467 | debug(14, 10, "ipcache_call_pending: Called %d handlers.\n", nhandler); |
620da955 | 468 | ipcacheUnlockEntry(i); |
090089c4 | 469 | } |
470 | ||
b8d8561b | 471 | static ipcache_entry * |
472 | ipcache_parsebuffer(char *inbuf, dnsserver_t * dnsData) | |
090089c4 | 473 | { |
d5a266cb | 474 | char *buf = xstrdup(inbuf); |
475 | char *token; | |
476 | static ipcache_entry i; | |
477 | int k; | |
30a4f2a8 | 478 | int ipcount; |
479 | int aliascount; | |
d5a266cb | 480 | debug(14, 5, "ipcache_parsebuffer: parsing:\n%s", inbuf); |
35e853ba | 481 | memset(&i, '\0', sizeof(ipcache_entry)); |
482 | i.expires = squid_curtime + Config.positiveDnsTtl; | |
483 | i.status = IP_DISPATCHED; | |
d5a266cb | 484 | for (token = strtok(buf, w_space); token; token = strtok(NULL, w_space)) { |
485 | if (!strcmp(token, "$end")) { | |
090089c4 | 486 | break; |
d5a266cb | 487 | } else if (!strcmp(token, "$alive")) { |
30a4f2a8 | 488 | dnsData->answer = squid_curtime; |
d5a266cb | 489 | } else if (!strcmp(token, "$fail")) { |
490 | if ((token = strtok(NULL, w_space)) == NULL) | |
491 | fatal_dump("Invalid $fail"); | |
35e853ba | 492 | i.expires = squid_curtime + Config.negativeDnsTtl; |
493 | i.status = IP_NEGATIVE_CACHED; | |
d5a266cb | 494 | } else if (!strcmp(token, "$message")) { |
495 | if ((token = strtok(NULL, "\n")) == NULL) | |
496 | fatal_dump("Invalid $message"); | |
497 | i.error_message = xstrdup(token); | |
498 | } else if (!strcmp(token, "$name")) { | |
499 | if ((token = strtok(NULL, w_space)) == NULL) | |
500 | fatal_dump("Invalid $name"); | |
35e853ba | 501 | i.status = IP_CACHED; |
d5a266cb | 502 | } else if (!strcmp(token, "$h_name")) { |
503 | if ((token = strtok(NULL, w_space)) == NULL) | |
504 | fatal_dump("Invalid $h_name"); | |
e5f6c5c2 | 505 | /* ignore $h_name */ |
d5a266cb | 506 | } else if (!strcmp(token, "$h_len")) { |
507 | if ((token = strtok(NULL, w_space)) == NULL) | |
508 | fatal_dump("Invalid $h_len"); | |
e5f6c5c2 | 509 | /* ignore $h_length */ |
d5a266cb | 510 | } else if (!strcmp(token, "$ipcount")) { |
511 | if ((token = strtok(NULL, w_space)) == NULL) | |
512 | fatal_dump("Invalid $ipcount"); | |
513 | ipcount = atoi(token); | |
e5f6c5c2 | 514 | i.addrs.count = (unsigned char) ipcount; |
d5a266cb | 515 | if (ipcount == 0) { |
e5f6c5c2 | 516 | i.addrs.in_addrs = NULL; |
090089c4 | 517 | } else { |
e5f6c5c2 | 518 | i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr)); |
d5a266cb | 519 | } |
520 | for (k = 0; k < ipcount; k++) { | |
521 | if ((token = strtok(NULL, w_space)) == NULL) | |
522 | fatal_dump("Invalid IP address"); | |
e5f6c5c2 | 523 | i.addrs.in_addrs[k].s_addr = inet_addr(token); |
090089c4 | 524 | } |
d5a266cb | 525 | } else if (!strcmp(token, "$aliascount")) { |
526 | if ((token = strtok(NULL, w_space)) == NULL) | |
527 | fatal_dump("Invalid $aliascount"); | |
528 | aliascount = atoi(token); | |
d5a266cb | 529 | for (k = 0; k < aliascount; k++) { |
530 | if ((token = strtok(NULL, w_space)) == NULL) | |
531 | fatal_dump("Invalid alias"); | |
090089c4 | 532 | } |
d5a266cb | 533 | } else if (!strcmp(token, "$ttl")) { |
534 | if ((token = strtok(NULL, w_space)) == NULL) | |
535 | fatal_dump("Invalid $ttl"); | |
536 | i.expires = squid_curtime + atoi(token); | |
090089c4 | 537 | } else { |
d5a266cb | 538 | fatal_dump("Invalid dnsserver output"); |
090089c4 | 539 | } |
540 | } | |
d5a266cb | 541 | xfree(buf); |
542 | return &i; | |
090089c4 | 543 | } |
544 | ||
b8d8561b | 545 | static int |
546 | ipcache_dnsHandleRead(int fd, dnsserver_t * dnsData) | |
090089c4 | 547 | { |
30a4f2a8 | 548 | int len; |
549 | int svc_time; | |
550 | int n; | |
551 | ipcache_entry *i = NULL; | |
d5a266cb | 552 | ipcache_entry *x = NULL; |
30a4f2a8 | 553 | |
554 | len = read(fd, | |
555 | dnsData->ip_inbuf + dnsData->offset, | |
556 | dnsData->size - dnsData->offset); | |
557 | debug(14, 5, "ipcache_dnsHandleRead: Result from DNS ID %d (%d bytes)\n", | |
558 | dnsData->id, len); | |
559 | if (len <= 0) { | |
560 | debug(14, dnsData->flags & DNS_FLAG_CLOSING ? 5 : 1, | |
561 | "FD %d: Connection from DNSSERVER #%d is closed, disabling\n", | |
562 | fd, dnsData->id); | |
563 | dnsData->flags = 0; | |
b177367b | 564 | commSetSelect(fd, |
30a4f2a8 | 565 | COMM_SELECT_WRITE, |
566 | NULL, | |
b177367b | 567 | NULL, 0); |
30a4f2a8 | 568 | comm_close(fd); |
090089c4 | 569 | return 0; |
570 | } | |
f88bb09c | 571 | n = ++IpcacheStats.replies; |
07635534 | 572 | DnsStats.replies++; |
30a4f2a8 | 573 | dnsData->offset += len; |
574 | dnsData->ip_inbuf[dnsData->offset] = '\0'; | |
35e853ba | 575 | i = dnsData->data; |
576 | if (i->status != IP_DISPATCHED) | |
577 | fatal_dump("ipcache_dnsHandleRead: bad status"); | |
30a4f2a8 | 578 | if (strstr(dnsData->ip_inbuf, "$end\n")) { |
090089c4 | 579 | /* end of record found */ |
30a4f2a8 | 580 | svc_time = tvSubMsec(dnsData->dispatch_time, current_time); |
581 | if (n > IPCACHE_AV_FACTOR) | |
582 | n = IPCACHE_AV_FACTOR; | |
583 | IpcacheStats.avg_svc_time | |
584 | = (IpcacheStats.avg_svc_time * (n - 1) + svc_time) / n; | |
d5a266cb | 585 | if ((x = ipcache_parsebuffer(dnsData->ip_inbuf, dnsData)) == NULL) { |
586 | debug(14, 0, "ipcache_dnsHandleRead: ipcache_parsebuffer failed?!\n"); | |
587 | } else { | |
588 | dnsData->offset = 0; | |
589 | dnsData->ip_inbuf[0] = '\0'; | |
590 | i = dnsData->data; | |
e5f6c5c2 | 591 | i->addrs = x->addrs; |
d5a266cb | 592 | i->error_message = x->error_message; |
35e853ba | 593 | i->status = x->status; |
ba35f853 | 594 | i->expires = x->expires; |
d5a266cb | 595 | ipcache_call_pending(i); |
090089c4 | 596 | } |
597 | } | |
30a4f2a8 | 598 | if (dnsData->offset == 0) { |
f88bb09c | 599 | dnsData->data = NULL; |
30a4f2a8 | 600 | dnsData->flags &= ~DNS_FLAG_BUSY; |
601 | } | |
090089c4 | 602 | /* reschedule */ |
b177367b | 603 | commSetSelect(dnsData->inpipe, |
30a4f2a8 | 604 | COMM_SELECT_READ, |
605 | (PF) ipcache_dnsHandleRead, | |
b177367b | 606 | dnsData, 0); |
f88bb09c | 607 | while ((dnsData = dnsGetFirstAvailable()) && (i = ipcacheDequeue())) |
608 | ipcache_dnsDispatch(dnsData, i); | |
090089c4 | 609 | return 0; |
610 | } | |
611 | ||
b8d8561b | 612 | static void |
613 | ipcacheAddPending(ipcache_entry * i, int fd, IPH handler, void *handlerData) | |
30a4f2a8 | 614 | { |
615 | struct _ip_pending *pending = xcalloc(1, sizeof(struct _ip_pending)); | |
616 | struct _ip_pending **I = NULL; | |
af00901c | 617 | i->lastref = squid_curtime; |
30a4f2a8 | 618 | pending->fd = fd; |
619 | pending->handler = handler; | |
620 | pending->handlerData = handlerData; | |
30a4f2a8 | 621 | for (I = &(i->pending_head); *I; I = &((*I)->next)); |
622 | *I = pending; | |
623 | } | |
624 | ||
b8d8561b | 625 | void |
626 | ipcache_nbgethostbyname(char *name, int fd, IPH handler, void *handlerData) | |
090089c4 | 627 | { |
30a4f2a8 | 628 | ipcache_entry *i = NULL; |
629 | dnsserver_t *dnsData = NULL; | |
e5f6c5c2 | 630 | ipcache_addrs *addrs; |
30a4f2a8 | 631 | |
632 | if (!handler) | |
633 | fatal_dump("ipcache_nbgethostbyname: NULL handler"); | |
090089c4 | 634 | |
019dd986 | 635 | debug(14, 4, "ipcache_nbgethostbyname: FD %d: Name '%s'.\n", fd, name); |
30a4f2a8 | 636 | IpcacheStats.requests++; |
090089c4 | 637 | |
638 | if (name == NULL || name[0] == '\0') { | |
019dd986 | 639 | debug(14, 4, "ipcache_nbgethostbyname: Invalid name!\n"); |
620da955 | 640 | handler(fd, NULL, handlerData); |
af00901c | 641 | return; |
642 | } | |
e5f6c5c2 | 643 | if ((addrs = ipcacheCheckNumeric(name))) { |
644 | handler(fd, addrs, handlerData); | |
af00901c | 645 | return; |
090089c4 | 646 | } |
30a4f2a8 | 647 | if ((i = ipcache_get(name))) { |
648 | if (ipcacheExpiredEntry(i)) { | |
649 | ipcache_release(i); | |
650 | i = NULL; | |
090089c4 | 651 | } |
090089c4 | 652 | } |
30a4f2a8 | 653 | if (i == NULL) { |
654 | /* MISS: No entry, create the new one */ | |
655 | debug(14, 5, "ipcache_nbgethostbyname: MISS for '%s'\n", name); | |
656 | IpcacheStats.misses++; | |
657 | i = ipcache_create(); | |
658 | i->name = xstrdup(name); | |
659 | i->status = IP_PENDING; | |
660 | ipcacheAddPending(i, fd, handler, handlerData); | |
661 | ipcache_add_to_hash(i); | |
662 | } else if (i->status == IP_CACHED || i->status == IP_NEGATIVE_CACHED) { | |
663 | /* HIT */ | |
664 | debug(14, 4, "ipcache_nbgethostbyname: HIT for '%s'\n", name); | |
665 | if (i->status == IP_NEGATIVE_CACHED) | |
666 | IpcacheStats.negative_hits++; | |
667 | else | |
668 | IpcacheStats.hits++; | |
669 | ipcacheAddPending(i, fd, handler, handlerData); | |
670 | ipcache_call_pending(i); | |
af00901c | 671 | return; |
30a4f2a8 | 672 | } else if (i->status == IP_PENDING || i->status == IP_DISPATCHED) { |
673 | debug(14, 4, "ipcache_nbgethostbyname: PENDING for '%s'\n", name); | |
674 | IpcacheStats.pending_hits++; | |
675 | ipcacheAddPending(i, fd, handler, handlerData); | |
af00901c | 676 | return; |
30a4f2a8 | 677 | } else { |
678 | fatal_dump("ipcache_nbgethostbyname: BAD ipcache_entry status"); | |
090089c4 | 679 | } |
680 | ||
30a4f2a8 | 681 | /* for HIT, PENDING, DISPATCHED we've returned. For MISS we continue */ |
090089c4 | 682 | |
30a4f2a8 | 683 | if ((dnsData = dnsGetFirstAvailable())) |
f88bb09c | 684 | ipcache_dnsDispatch(dnsData, i); |
30a4f2a8 | 685 | else |
f88bb09c | 686 | ipcacheEnqueue(i); |
30a4f2a8 | 687 | } |
688 | ||
b8d8561b | 689 | static void |
690 | ipcache_dnsDispatch(dnsserver_t * dns, ipcache_entry * i) | |
30a4f2a8 | 691 | { |
692 | char *buf = NULL; | |
693 | if (!ipcacheHasPending(i)) { | |
f88bb09c | 694 | debug(14, 0, "ipcache_dnsDispatch: skipping '%s' because no handler.\n", |
30a4f2a8 | 695 | i->name); |
696 | i->status = IP_NEGATIVE_CACHED; | |
697 | ipcache_release(i); | |
698 | return; | |
090089c4 | 699 | } |
30a4f2a8 | 700 | buf = xcalloc(1, 256); |
701 | sprintf(buf, "%1.254s\n", i->name); | |
702 | dns->flags |= DNS_FLAG_BUSY; | |
f88bb09c | 703 | dns->data = i; |
620da955 | 704 | i->status = IP_DISPATCHED; |
30a4f2a8 | 705 | comm_write(dns->outpipe, |
706 | buf, | |
707 | strlen(buf), | |
708 | 0, /* timeout */ | |
709 | NULL, /* Handler */ | |
9864ee44 | 710 | NULL, /* Handler-data */ |
711 | xfree); | |
b177367b | 712 | commSetSelect(dns->outpipe, |
f88bb09c | 713 | COMM_SELECT_READ, |
714 | (PF) ipcache_dnsHandleRead, | |
b177367b | 715 | dns, 0); |
f88bb09c | 716 | debug(14, 5, "ipcache_dnsDispatch: Request sent to DNS server #%d.\n", |
30a4f2a8 | 717 | dns->id); |
718 | dns->dispatch_time = current_time; | |
f88bb09c | 719 | DnsStats.requests++; |
720 | DnsStats.hist[dns->id - 1]++; | |
090089c4 | 721 | } |
722 | ||
723 | ||
0ffd22bc | 724 | /* initialize the ipcache */ |
b8d8561b | 725 | void |
0673c0ba | 726 | ipcache_init(void) |
0ffd22bc | 727 | { |
b09ad9fd | 728 | debug(14, 3, "Initializing IP Cache...\n"); |
0ffd22bc | 729 | |
30a4f2a8 | 730 | memset(&IpcacheStats, '\0', sizeof(IpcacheStats)); |
0ffd22bc | 731 | |
732 | /* test naming lookup */ | |
30a4f2a8 | 733 | if (!opt_dns_tests) { |
b09ad9fd | 734 | debug(14, 4, "ipcache_init: Skipping DNS name lookup tests.\n"); |
735 | } else if (!ipcache_testname()) { | |
736 | fatal("ipcache_init: DNS name lookup tests failed/"); | |
0ffd22bc | 737 | } else { |
738 | debug(14, 1, "Successful DNS name lookup tests...\n"); | |
739 | } | |
740 | ||
aad137ea | 741 | ip_table = hash_create(urlcmp, 229, hash_string); /* small hash table */ |
e5f6c5c2 | 742 | memset(&static_addrs, '\0', sizeof(ipcache_addrs)); |
743 | static_addrs.in_addrs = xcalloc(1, sizeof(struct in_addr)); | |
0ffd22bc | 744 | |
b15e6857 | 745 | ipcache_high = (long) (((float) Config.ipcache.size * |
746 | (float) Config.ipcache.high) / (float) 100); | |
747 | ipcache_low = (long) (((float) Config.ipcache.size * | |
748 | (float) Config.ipcache.low) / (float) 100); | |
090089c4 | 749 | } |
750 | ||
751 | /* clean up the pending entries in dnsserver */ | |
752 | /* return 1 if we found the host, 0 otherwise */ | |
b8d8561b | 753 | int |
754 | ipcache_unregister(char *name, int fd) | |
090089c4 | 755 | { |
30a4f2a8 | 756 | ipcache_entry *i = NULL; |
757 | struct _ip_pending *p = NULL; | |
758 | int n = 0; | |
090089c4 | 759 | |
30a4f2a8 | 760 | debug(14, 3, "ipcache_unregister: FD %d, name '%s'\n", fd, name); |
761 | if ((i = ipcache_get(name)) == NULL) | |
090089c4 | 762 | return 0; |
30a4f2a8 | 763 | if (i->status == IP_PENDING || i->status == IP_DISPATCHED) { |
764 | for (p = i->pending_head; p; p = p->next) { | |
765 | if (p->fd == fd && p->handler != NULL) { | |
766 | p->handler = NULL; | |
767 | p->fd = -1; | |
768 | n++; | |
769 | } | |
090089c4 | 770 | } |
090089c4 | 771 | } |
30a4f2a8 | 772 | debug(14, 3, "ipcache_unregister: unregistered %d handlers\n", n); |
773 | return n; | |
090089c4 | 774 | } |
775 | ||
e5f6c5c2 | 776 | ipcache_addrs * |
b8d8561b | 777 | ipcache_gethostbyname(char *name, int flags) |
090089c4 | 778 | { |
30a4f2a8 | 779 | ipcache_entry *i = NULL; |
e5f6c5c2 | 780 | ipcache_addrs *addrs; |
781 | struct hostent *hp; | |
30a4f2a8 | 782 | |
783 | if (!name) | |
784 | fatal_dump("ipcache_gethostbyname: NULL name"); | |
785 | IpcacheStats.requests++; | |
786 | if ((i = ipcache_get(name))) { | |
af00901c | 787 | if (ipcacheExpiredEntry(i)) { |
788 | ipcache_release(i); | |
789 | i = NULL; | |
790 | } | |
791 | } | |
792 | if (i) { | |
30a4f2a8 | 793 | if (i->status == IP_PENDING || i->status == IP_DISPATCHED) { |
794 | IpcacheStats.pending_hits++; | |
795 | return NULL; | |
796 | } else if (i->status == IP_NEGATIVE_CACHED) { | |
797 | IpcacheStats.negative_hits++; | |
798 | dns_error_message = i->error_message; | |
799 | return NULL; | |
090089c4 | 800 | } else { |
30a4f2a8 | 801 | IpcacheStats.hits++; |
802 | i->lastref = squid_curtime; | |
e5f6c5c2 | 803 | return &i->addrs; |
090089c4 | 804 | } |
30a4f2a8 | 805 | } |
806 | IpcacheStats.misses++; | |
e5f6c5c2 | 807 | if ((addrs = ipcacheCheckNumeric(name))) |
808 | return addrs; | |
30a4f2a8 | 809 | if (flags & IP_BLOCKING_LOOKUP) { |
810 | IpcacheStats.ghbn_calls++; | |
811 | hp = gethostbyname(name); | |
812 | if (hp && hp->h_name && (hp->h_name[0] != '\0') && ip_table) { | |
090089c4 | 813 | /* good address, cached */ |
30a4f2a8 | 814 | ipcache_add(name, ipcache_create(), hp, 1); |
815 | i = ipcache_get(name); | |
af00901c | 816 | i->lastref = squid_curtime; |
817 | i->expires = squid_curtime + Config.positiveDnsTtl; | |
c021888f | 818 | #if LIBRESOLV_DNS_TTL_HACK |
819 | if (_dns_ttl_ > -1) | |
820 | i->expires = squid_curtime + _dns_ttl_; | |
821 | #endif /* LIBRESOLV_DNS_TTL_HACK */ | |
e5f6c5c2 | 822 | return &i->addrs; |
090089c4 | 823 | } |
30a4f2a8 | 824 | /* bad address, negative cached */ |
af00901c | 825 | if (ip_table) { |
30a4f2a8 | 826 | ipcache_add(name, ipcache_create(), hp, 0); |
af00901c | 827 | i = ipcache_get(name); |
828 | i->lastref = squid_curtime; | |
829 | i->expires = squid_curtime + Config.negativeDnsTtl; | |
830 | return NULL; | |
831 | } | |
090089c4 | 832 | } |
30a4f2a8 | 833 | if (flags & IP_LOOKUP_IF_MISS) |
834 | ipcache_nbgethostbyname(name, -1, dummy_handler, NULL); | |
835 | return NULL; | |
090089c4 | 836 | } |
837 | ||
b8d8561b | 838 | static void |
839 | ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry) | |
af00901c | 840 | { |
841 | int k; | |
233794cd | 842 | storeAppendPrintf(sentry, " {%-32.32s %c%c %6d %6d %d", |
af00901c | 843 | i->name, |
844 | ipcache_status_char[i->status], | |
233794cd | 845 | i->locks ? 'L' : ' ', |
af00901c | 846 | (int) (squid_curtime - i->lastref), |
847 | (int) (i->expires - squid_curtime), | |
e5f6c5c2 | 848 | (int) i->addrs.count); |
849 | for (k = 0; k < (int) i->addrs.count; k++) | |
850 | storeAppendPrintf(sentry, " %15s", inet_ntoa(i->addrs.in_addrs[k])); | |
af00901c | 851 | storeAppendPrintf(sentry, close_bracket); |
852 | } | |
090089c4 | 853 | |
090089c4 | 854 | /* process objects list */ |
b8d8561b | 855 | void |
856 | stat_ipcache_get(StoreEntry * sentry) | |
090089c4 | 857 | { |
30a4f2a8 | 858 | int k; |
af00901c | 859 | int N; |
860 | ipcache_entry *i = NULL; | |
861 | ipcache_entry **list = NULL; | |
30a4f2a8 | 862 | if (!ip_table) |
863 | return; | |
30a4f2a8 | 864 | storeAppendPrintf(sentry, "{IP Cache Statistics:\n"); |
865 | storeAppendPrintf(sentry, "{IPcache Entries: %d}\n", | |
866 | meta_data.ipcache_count); | |
867 | storeAppendPrintf(sentry, "{IPcache Requests: %d}\n", | |
868 | IpcacheStats.requests); | |
869 | storeAppendPrintf(sentry, "{IPcache Hits: %d}\n", | |
870 | IpcacheStats.hits); | |
871 | storeAppendPrintf(sentry, "{IPcache Pending Hits: %d}\n", | |
872 | IpcacheStats.pending_hits); | |
873 | storeAppendPrintf(sentry, "{IPcache Negative Hits: %d}\n", | |
874 | IpcacheStats.negative_hits); | |
875 | storeAppendPrintf(sentry, "{IPcache Misses: %d}\n", | |
876 | IpcacheStats.misses); | |
877 | storeAppendPrintf(sentry, "{Blocking calls to gethostbyname(): %d}\n", | |
878 | IpcacheStats.ghbn_calls); | |
30a4f2a8 | 879 | storeAppendPrintf(sentry, "{dnsserver avg service time: %d msec}\n", |
880 | IpcacheStats.avg_svc_time); | |
30a4f2a8 | 881 | storeAppendPrintf(sentry, "}\n\n"); |
882 | storeAppendPrintf(sentry, "{IP Cache Contents:\n\n"); | |
af00901c | 883 | storeAppendPrintf(sentry, " {%-29.29s %5s %6s %6s %1s}\n", |
884 | "Hostname", | |
885 | "Flags", | |
886 | "lstref", | |
887 | "TTL", | |
888 | "N"); | |
889 | list = xcalloc(meta_data.ipcache_count, sizeof(ipcache_entry *)); | |
890 | N = 0; | |
30a4f2a8 | 891 | for (i = ipcache_GetFirst(); i; i = ipcache_GetNext()) { |
af00901c | 892 | *(list + N) = i; |
67508012 | 893 | if (++N > meta_data.ipcache_count) { |
894 | debug_trap("stat_ipcache_get: meta_data.ipcache_count mismatch"); | |
895 | break; | |
896 | } | |
090089c4 | 897 | } |
af00901c | 898 | qsort((char *) list, |
899 | N, | |
900 | sizeof(ipcache_entry *), | |
901 | (QS) ipcache_reverseLastRef); | |
902 | for (k = 0; k < N; k++) | |
903 | ipcacheStatPrint(*(list + k), sentry); | |
30a4f2a8 | 904 | storeAppendPrintf(sentry, close_bracket); |
67508012 | 905 | xfree(list); |
090089c4 | 906 | } |
4d64d74a | 907 | |
caebbe00 | 908 | static void |
e5f6c5c2 | 909 | dummy_handler(int u1, ipcache_addrs * addrs, void *u3) |
30a4f2a8 | 910 | { |
caebbe00 | 911 | return; |
30a4f2a8 | 912 | } |
913 | ||
b8d8561b | 914 | static int |
915 | ipcacheHasPending(ipcache_entry * i) | |
30a4f2a8 | 916 | { |
917 | struct _ip_pending *p = NULL; | |
918 | if (i->status != IP_PENDING) | |
919 | return 0; | |
920 | for (p = i->pending_head; p; p = p->next) | |
921 | if (p->handler) | |
922 | return 1; | |
923 | return 0; | |
924 | } | |
877ed73e | 925 | |
b8d8561b | 926 | void |
927 | ipcacheReleaseInvalid(char *name) | |
877ed73e | 928 | { |
929 | ipcache_entry *i; | |
930 | if ((i = ipcache_get(name)) == NULL) | |
931 | return; | |
932 | if (i->status != IP_NEGATIVE_CACHED) | |
933 | return; | |
934 | ipcache_release(i); | |
935 | } | |
f900607e | 936 | |
b8d8561b | 937 | void |
938 | ipcacheInvalidate(char *name) | |
f900607e | 939 | { |
940 | ipcache_entry *i; | |
941 | if ((i = ipcache_get(name)) == NULL) | |
942 | return; | |
6c11e193 | 943 | i->expires = squid_curtime; |
944 | /* NOTE, don't call ipcache_release here becuase we might be here due | |
945 | * to a thread started from ipcache_call_pending() which will cause a | |
946 | * FMR */ | |
f900607e | 947 | } |
af00901c | 948 | |
e5f6c5c2 | 949 | static ipcache_addrs * |
b8d8561b | 950 | ipcacheCheckNumeric(char *name) |
af00901c | 951 | { |
952 | unsigned int ip; | |
953 | /* check if it's already a IP address in text form. */ | |
954 | if ((ip = inet_addr(name)) == INADDR_NONE) | |
955 | return NULL; | |
e5f6c5c2 | 956 | static_addrs.count = 1; |
957 | static_addrs.cur = 0; | |
958 | static_addrs.in_addrs[0].s_addr = ip; | |
959 | return &static_addrs; | |
af00901c | 960 | } |
8905d949 | 961 | |
b8d8561b | 962 | int |
0673c0ba | 963 | ipcacheQueueDrain(void) |
8905d949 | 964 | { |
965 | ipcache_entry *i; | |
966 | dnsserver_t *dnsData; | |
967 | if (!ipcacheQueueHead) | |
968 | return 0; | |
969 | while ((dnsData = dnsGetFirstAvailable()) && (i = ipcacheDequeue())) | |
970 | ipcache_dnsDispatch(dnsData, i); | |
971 | return 1; | |
972 | } | |
620da955 | 973 | |
b8d8561b | 974 | static void |
975 | ipcacheLockEntry(ipcache_entry * i) | |
620da955 | 976 | { |
977 | i->locks++; | |
978 | } | |
979 | ||
b8d8561b | 980 | static void |
981 | ipcacheUnlockEntry(ipcache_entry * i) | |
620da955 | 982 | { |
983 | i->locks--; | |
984 | if (ipcacheExpiredEntry(i)) | |
985 | ipcache_release(i); | |
986 | } | |
e5f6c5c2 | 987 | |
988 | void | |
989 | ipcacheCycleAddr(char *name) | |
990 | { | |
991 | ipcache_entry *i; | |
992 | if ((i = ipcache_get(name)) == NULL) | |
993 | return; | |
994 | if (i->status != IP_CACHED) | |
995 | return; | |
996 | if (++i->addrs.cur == i->addrs.count) | |
997 | i->addrs.cur = 0; | |
998 | } | |
999 | ||
1000 | void | |
1001 | ipcacheRemoveBadAddr(char *name, struct in_addr addr) | |
1002 | { | |
1003 | ipcache_entry *i; | |
1004 | ipcache_addrs *ia; | |
1005 | int k; | |
1006 | if ((i = ipcache_get(name)) == NULL) | |
1007 | return; | |
1008 | ia = &i->addrs; | |
1009 | for (k = 0; k < (int) ia->count; k++) { | |
1010 | if (ia->in_addrs[k].s_addr == addr.s_addr) | |
1011 | break; | |
1012 | } | |
1013 | if (k == (int) ia->count) | |
1014 | return; | |
1015 | ia->in_addrs[k] = ia->in_addrs[--ia->count]; | |
1016 | if (ia->count == 0) | |
1017 | i->expires = squid_curtime; | |
1018 | if (ia->cur >= ia->count) | |
1019 | ia->cur = 0; | |
1020 | } | |
56e15c50 | 1021 | |
1022 | void | |
1023 | ipcacheFreeMemory(void) | |
1024 | { | |
1025 | ipcache_entry *i; | |
1026 | ipcache_entry **list; | |
1027 | int k = 0; | |
1028 | int j; | |
1029 | list = xcalloc(meta_data.ipcache_count, sizeof(ipcache_entry *)); | |
1030 | i = (ipcache_entry *) hash_first(ip_table); | |
1031 | while (i && k < meta_data.ipcache_count) { | |
f6610c4e | 1032 | *(list + k) = i; |
1033 | k++; | |
1034 | i = (ipcache_entry *) hash_next(ip_table); | |
56e15c50 | 1035 | } |
1036 | for (j = 0; j < k; j++) { | |
1037 | i = *(list + j); | |
f6610c4e | 1038 | safe_free(i->addrs.in_addrs); |
1039 | safe_free(i->name); | |
1040 | safe_free(i->error_message); | |
1041 | safe_free(i); | |
56e15c50 | 1042 | } |
1043 | xfree(list); | |
1044 | hashFreeMemory(ip_table); | |
1045 | } |