ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/negcache.c
Revision: 5207
Committed: Mon Dec 29 19:38:22 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 6448 byte(s)
Log Message:
- Removed AC_HEADER_STDC configure test

File Contents

# Content
1 /*
2 Copyright (C) 2002-2003 Andy Smith
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to:
16
17 the Free Software Foundation, Inc.
18 59 Temple Place - Suite 330
19 Boston, MA 02111-1307, USA.
20
21 */
22
23 /*
24 * A Negative caching implementation for IPv4 addresses. The idea is that
25 * every time an IP address is seen, it is checked against a patricia trie. If
26 * the IP address was previously seen and within an acceptable period of time,
27 * it is not scanned again. Otherwise, the address is scanned as normal. If
28 * it is proven to be OK (i.e. it doesn't run an open proxy) then it is added
29 * to the trie.
30 *
31 * I'm using a patricia trie as described on p253 of Sedgewick. The reason for
32 * this is that it can find any IP address with only log_2 N bit comparisons
33 * and only requires as many nodes as we have IP addresses to store.
34 *
35 * I would have liked to have made the trie implementation generic but couldn't
36 * see how to do it easily given that the trie structure depends on the data
37 * within it.
38 * --grifferz
39 */
40
41 #include "setup.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #ifdef TIME_WITH_SYS_TIME
47 #include <sys/time.h>
48 #include <time.h>
49 #else
50 # ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
52 # else
53 # include <time.h>
54 # endif
55 #endif
56
57 #include "irc.h"
58 #include "negcache.h"
59 #include "config.h"
60 #include "malloc.h"
61 #include "log.h"
62
63
64 extern unsigned int OPT_DEBUG;
65
66 static struct cnode *nc_search(struct cnode *head, const unsigned long ip);
67 static struct cnode *nc_insert(struct cnode *head, const unsigned long ip);
68 static void nc_rebuild(struct cnode *old_head, struct cnode *new_head,
69 struct cnode *n, time_t now);
70
71 time_t last_nc_expire;
72 unsigned int maxb;
73 extern struct cnode *nc_head;
74
75 /*
76 * Return the bit which appears k bits from the right in x.
77 */
78 #define GETBIT(x,k) ((x >> k) & 1)
79
80
81 /*
82 * Initialise the patricia trie we use for storing our negative cache.
83 */
84 void nc_init(struct cnode **head)
85 {
86 if (*head)
87 {
88 /* Cache already exists */
89 return;
90 }
91
92 *head = MyMalloc(sizeof **head);
93
94 maxb = (sizeof((*head)->ip) * 8);
95 (*head)->ip = 0;
96 (*head)->b = maxb;
97 (*head)->l = (*head)->r = *head;
98 last_nc_expire = time(NULL);
99 }
100
101 /*
102 * Find and return a pointer to the trie node that corresponds to a given IP
103 * address as expressed in network form, or return NULL if the IP isn't
104 * present.
105 */
106 static struct cnode *nc_search(struct cnode *head, const unsigned long ip)
107 {
108 struct cnode *p, *x;
109
110 p = head;
111 x = head->l;
112
113 while (p->b > x->b)
114 {
115 p = x;
116 x = GETBIT(ip, x->b) ? x->r : x->l;
117 }
118
119 if (ip == x->ip)
120 return(x);
121 else
122 return(NULL);
123 }
124
125 /*
126 * Insert a new node into the trie, and return a pointer to it.
127 */
128 static struct cnode *nc_insert(struct cnode *head, const unsigned long ip)
129 {
130 unsigned int i;
131 struct cnode *p, *t, *x;
132
133 i = maxb;
134 p = head;
135 t = head->l;
136
137 while (p->b > t->b)
138 {
139 p = t;
140 t = GETBIT(ip, t->b) ? t->r : t->l;
141 }
142
143 if (ip == t->ip)
144 {
145 /* Node already exists. */
146 return(t);
147 }
148
149 while (GETBIT(t->ip, i) == GETBIT(ip, i))
150 i--;
151
152 p = head;
153 x = head->l;
154
155 while (p->b > x->b && x->b > i)
156 {
157 p = x;
158 x = GETBIT(ip, x->b) ? x->r : x->l;
159 }
160
161 t = MyMalloc(sizeof *t);
162 t->ip = ip;
163 t->b = i;
164 t->l = GETBIT(ip, t->b) ? x : t;
165 t->r = GETBIT(ip, t->b) ? t : x;
166
167 if (GETBIT(ip, p->b))
168 p->r = t;
169 else
170 p->l = t;
171
172 return(t);
173 }
174
175 /*
176 * Check whether an IP address is in our negative cache and was added
177 * recently enough. Return a pointer to its node if so, NULL otherwise.
178 */
179 struct cnode *check_neg_cache(const unsigned long ip)
180 {
181 time_t now;
182 struct cnode *n;
183
184 if (OptionsItem->negcache <= 0)
185 return(NULL);
186
187 n = nc_search(nc_head, ip);
188
189 if (n)
190 {
191 /* Check it is recent enough. */
192 now = time(NULL);
193
194 if (now - n->seen <= OptionsItem->negcache)
195 return(n);
196 }
197
198 return(NULL);
199 }
200
201 /*
202 * Prepare an ASCII string representing an IPv4 address for inserting into
203 * our negative cache.
204 */
205 void negcache_insert(const char *ipstr)
206 {
207 struct bopm_sockaddr ip;
208 struct cnode *n;
209
210 if (inet_pton(AF_INET, ipstr, &(ip.sa4.sin_addr)) <= 0)
211 {
212 log_printf("NEGCACHE -> Invalid IPv4 address '%s'", ipstr);
213 return;
214 }
215
216 n = nc_insert(nc_head, ip.sa4.sin_addr.s_addr);
217
218 if (n)
219 n->seen = time(NULL);
220 }
221
222 /*
223 * Recursively walk the cache and insert the nodes into a new patricia trie,
224 * skipping nodes that are too old.
225 */
226 static void nc_rebuild(struct cnode *old_head, struct cnode *new_head,
227 struct cnode *n, time_t now)
228 {
229 struct cnode *new;
230
231 if (!n)
232 {
233 /* Start at head. */
234 n = old_head->l;
235 }
236
237 if (n == old_head)
238 {
239 /* Trie is empty. */
240 return;
241 }
242
243 if (n->b > n->l->b)
244 {
245 /*
246 * If the trie extends via the left branch, follow it
247 * recursively.
248 */
249 nc_rebuild(old_head, new_head, n->l, now);
250 }
251
252 if (n->b > n->r->b)
253 {
254 /*
255 * If the trie extends via the right branch, follow it
256 * recursively.
257 */
258 nc_rebuild(old_head, new_head, n->r, now);
259 }
260
261 if ((now - n->seen) < OptionsItem->negcache)
262 {
263 /*
264 * We want to keep this node, so insert it into the new
265 * trie.
266 */
267 new = nc_insert(new_head, n->ip);
268 new->seen = n->seen;
269 }
270 else if (OPT_DEBUG >= 2)
271 {
272 log_printf("NEGCACHE -> Deleting negcache node for %lu added at %lu", n->ip,
273 n->seen);
274 }
275
276 /* Safe to free() this node now. */
277 MyFree(n);
278 }
279
280 /*
281 * Wrapper for recursive rebuild function.
282 */
283 void negcache_rebuild(void)
284 {
285 time_t now;
286 struct cnode *new_head;
287
288 now = time(NULL);
289 new_head = NULL;
290
291 nc_init(&new_head);
292 nc_rebuild(nc_head, new_head, NULL, now);
293 MyFree(nc_head);
294 nc_head = new_head;
295 }

Properties

Name Value
svn:eol-style native
svn:keywords Id