]> git.ipfire.org Git - thirdparty/squid.git/blob - src/asn.cc
Updated copyright
[thirdparty/squid.git] / src / asn.cc
1
2 /*
3 * $Id: asn.cc,v 1.68 2001/01/12 00:37:14 wessels Exp $
4 *
5 * DEBUG: section 53 AS Number handling
6 * AUTHOR: Duane Wessels, Kostas Anagnostakis
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
38 #define WHOIS_PORT 43
39
40 /* BEGIN of definitions for radix tree entries */
41
42 /* int in memory with length */
43 typedef u_char m_int[1 + sizeof(unsigned int)];
44 #define store_m_int(i, m) \
45 (i = htonl(i), m[0] = sizeof(m_int), xmemcpy(m+1, &i, sizeof(unsigned int)))
46 #define get_m_int(i, m) \
47 (xmemcpy(&i, m+1, sizeof(unsigned int)), ntohl(i))
48
49 /* END of definitions for radix tree entries */
50
51 /* Head for ip to asn radix tree */
52 struct radix_node_head *AS_tree_head;
53
54 /*
55 * Structure for as number information. it could be simply
56 * an intlist but it's coded as a structure for future
57 * enhancements (e.g. expires)
58 */
59 struct _as_info {
60 intlist *as_number;
61 time_t expires; /* NOTUSED */
62 };
63
64 struct _ASState {
65 StoreEntry *entry;
66 store_client *sc;
67 request_t *request;
68 int as_number;
69 off_t seen;
70 off_t offset;
71 };
72
73 typedef struct _ASState ASState;
74 typedef struct _as_info as_info;
75
76 /* entry into the radix tree */
77 struct _rtentry {
78 struct radix_node e_nodes[2];
79 as_info *e_info;
80 m_int e_addr;
81 m_int e_mask;
82 };
83
84 typedef struct _rtentry rtentry;
85
86 static int asnAddNet(char *, int);
87 static void asnCacheStart(int as);
88 static STCB asHandleReply;
89 static int destroyRadixNode(struct radix_node *rn, void *w);
90 static int printRadixNode(struct radix_node *rn, void *w);
91 static void asnAclInitialize(acl * acls);
92 static void asStateFree(void *data);
93 static void destroyRadixNodeInfo(as_info *);
94 static OBJH asnStats;
95
96 extern struct radix_node *rn_lookup(void *, void *, void *);
97
98
99 /* PUBLIC */
100
101 int
102 asnMatchIp(void *data, struct in_addr addr)
103 {
104 unsigned long lh;
105 struct radix_node *rn;
106 as_info *e;
107 m_int m_addr;
108 intlist *a = NULL;
109 intlist *b = NULL;
110 lh = ntohl(addr.s_addr);
111 debug(53, 3) ("asnMatchIp: Called for %s.\n", inet_ntoa(addr));
112
113 if (AS_tree_head == NULL)
114 return 0;
115 if (addr.s_addr == no_addr.s_addr)
116 return 0;
117 if (addr.s_addr == any_addr.s_addr)
118 return 0;
119 store_m_int(lh, m_addr);
120 rn = rn_match(m_addr, AS_tree_head);
121 if (rn == NULL) {
122 debug(53, 3) ("asnMatchIp: Address not in as db.\n");
123 return 0;
124 }
125 debug(53, 3) ("asnMatchIp: Found in db!\n");
126 e = ((rtentry *) rn)->e_info;
127 assert(e);
128 for (a = (intlist *) data; a; a = a->next)
129 for (b = e->as_number; b; b = b->next)
130 if (a->i == b->i) {
131 debug(53, 5) ("asnMatchIp: Found a match!\n");
132 return 1;
133 }
134 debug(53, 5) ("asnMatchIp: AS not in as db.\n");
135 return 0;
136 }
137
138 static void
139 asnAclInitialize(acl * acls)
140 {
141 acl *a;
142 intlist *i;
143 debug(53, 3) ("asnAclInitialize\n");
144 for (a = acls; a; a = a->next) {
145 if (a->type != ACL_DST_ASN && a->type != ACL_SRC_ASN)
146 continue;
147 for (i = a->data; i; i = i->next)
148 asnCacheStart(i->i);
149 }
150 }
151
152 /* initialize the radix tree structure */
153
154 CBDATA_TYPE(ASState);
155 void
156 asnInit(void)
157 {
158 extern int max_keylen;
159 static int inited = 0;
160 max_keylen = 40;
161 CBDATA_INIT_TYPE(ASState);
162 if (0 == inited++)
163 rn_init();
164 rn_inithead((void **) &AS_tree_head, 8);
165 asnAclInitialize(Config.aclList);
166 cachemgrRegister("asndb", "AS Number Database", asnStats, 0, 1);
167 }
168
169 void
170 asnFreeMemory(void)
171 {
172 rn_walktree(AS_tree_head, destroyRadixNode, AS_tree_head);
173 destroyRadixNode((struct radix_node *) 0, (void *) AS_tree_head);
174 }
175
176 static void
177 asnStats(StoreEntry * sentry)
178 {
179 storeAppendPrintf(sentry, "Address \tAS Numbers\n");
180 rn_walktree(AS_tree_head, printRadixNode, sentry);
181 }
182
183 /* PRIVATE */
184
185
186 static void
187 asnCacheStart(int as)
188 {
189 LOCAL_ARRAY(char, asres, 4096);
190 StoreEntry *e;
191 request_t *req;
192 ASState *asState;
193 asState = CBDATA_ALLOC(ASState, NULL);
194 debug(53, 3) ("asnCacheStart: AS %d\n", as);
195 snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
196 asState->as_number = as;
197 req = urlParse(METHOD_GET, asres);
198 assert(NULL != req);
199 asState->request = requestLink(req);
200 if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
201 e = storeCreateEntry(asres, asres, null_request_flags, METHOD_GET);
202 asState->sc = storeClientListAdd(e, asState);
203 fwdStart(-1, e, asState->request);
204 } else {
205 storeLockObject(e);
206 asState->sc = storeClientListAdd(e, asState);
207 }
208 asState->entry = e;
209 asState->seen = 0;
210 asState->offset = 0;
211 storeClientCopy(asState->sc,
212 e,
213 asState->seen,
214 asState->offset,
215 4096,
216 memAllocate(MEM_4K_BUF),
217 asHandleReply,
218 asState);
219 }
220
221 static void
222 asHandleReply(void *data, char *buf, ssize_t size)
223 {
224 ASState *asState = data;
225 StoreEntry *e = asState->entry;
226 char *s;
227 char *t;
228 debug(53, 3) ("asHandleReply: Called with size=%d\n", size);
229 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
230 memFree(buf, MEM_4K_BUF);
231 asStateFree(asState);
232 return;
233 }
234 if (size == 0 && e->mem_obj->inmem_hi > 0) {
235 memFree(buf, MEM_4K_BUF);
236 asStateFree(asState);
237 return;
238 } else if (size < 0) {
239 debug(53, 1) ("asHandleReply: Called with size=%d\n", size);
240 memFree(buf, MEM_4K_BUF);
241 asStateFree(asState);
242 return;
243 } else if (HTTP_OK != e->mem_obj->reply->sline.status) {
244 debug(53, 1) ("WARNING: AS %d whois request failed\n",
245 asState->as_number);
246 memFree(buf, MEM_4K_BUF);
247 asStateFree(asState);
248 return;
249 }
250 s = buf;
251 while (s - buf < size && *s != '\0') {
252 while (*s && xisspace(*s))
253 s++;
254 for (t = s; *t; t++) {
255 if (xisspace(*t))
256 break;
257 }
258 if (*t == '\0') {
259 /* oof, word should continue on next block */
260 break;
261 }
262 *t = '\0';
263 debug(53, 3) ("asHandleReply: AS# %s (%d)\n", s, asState->as_number);
264 asnAddNet(s, asState->as_number);
265 s = t + 1;
266 }
267 asState->seen = asState->offset + size;
268 asState->offset += (s - buf);
269 debug(53, 3) ("asState->seen = %d, asState->offset = %d\n",
270 asState->seen, asState->offset);
271 if (e->store_status == STORE_PENDING) {
272 debug(53, 3) ("asHandleReply: store_status == STORE_PENDING: %s\n", storeUrl(e));
273 storeClientCopy(asState->sc,
274 e,
275 asState->seen,
276 asState->offset,
277 4096,
278 buf,
279 asHandleReply,
280 asState);
281 } else if (asState->seen < e->mem_obj->inmem_hi) {
282 debug(53, 3) ("asHandleReply: asState->seen < e->mem_obj->inmem_hi %s\n", storeUrl(e));
283 storeClientCopy(asState->sc,
284 e,
285 asState->seen,
286 asState->offset,
287 4096,
288 buf,
289 asHandleReply,
290 asState);
291 } else {
292 debug(53, 3) ("asHandleReply: Done: %s\n", storeUrl(e));
293 memFree(buf, MEM_4K_BUF);
294 asStateFree(asState);
295 }
296 }
297
298 static void
299 asStateFree(void *data)
300 {
301 ASState *asState = data;
302 debug(53, 3) ("asnStateFree: %s\n", storeUrl(asState->entry));
303 storeUnregister(asState->sc, asState->entry, asState);
304 storeUnlockObject(asState->entry);
305 requestUnlink(asState->request);
306 cbdataFree(asState);
307 }
308
309
310 /* add a network (addr, mask) to the radix tree, with matching AS
311 * number */
312
313 static int
314 asnAddNet(char *as_string, int as_number)
315 {
316 rtentry *e = xmalloc(sizeof(rtentry));
317 struct radix_node *rn;
318 char dbg1[32], dbg2[32];
319 intlist **Tail = NULL;
320 intlist *q = NULL;
321 as_info *asinfo = NULL;
322 struct in_addr in_a, in_m;
323 long mask, addr;
324 char *t;
325 int bitl;
326
327 t = strchr(as_string, '/');
328 if (t == NULL) {
329 debug(53, 3) ("asnAddNet: failed, invalid response from whois server.\n");
330 return 0;
331 }
332 *t = '\0';
333 addr = inet_addr(as_string);
334 bitl = atoi(t + 1);
335 if (bitl < 0)
336 bitl = 0;
337 if (bitl > 32)
338 bitl = 32;
339 mask = bitl ? 0xfffffffful << (32 - bitl) : 0;
340
341 in_a.s_addr = addr;
342 in_m.s_addr = mask;
343 xstrncpy(dbg1, inet_ntoa(in_a), 32);
344 xstrncpy(dbg2, inet_ntoa(in_m), 32);
345 addr = ntohl(addr);
346 /*mask = ntohl(mask); */
347 debug(53, 3) ("asnAddNet: called for %s/%s\n", dbg1, dbg2);
348 memset(e, '\0', sizeof(rtentry));
349 store_m_int(addr, e->e_addr);
350 store_m_int(mask, e->e_mask);
351 rn = rn_lookup(e->e_addr, e->e_mask, AS_tree_head);
352 if (rn != NULL) {
353 asinfo = ((rtentry *) rn)->e_info;
354 if (intlistFind(asinfo->as_number, as_number)) {
355 debug(53, 3) ("asnAddNet: Ignoring repeated network '%s/%d' for AS %d\n",
356 dbg1, bitl, as_number);
357 } else {
358 debug(53, 3) ("asnAddNet: Warning: Found a network with multiple AS numbers!\n");
359 for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
360 q = xcalloc(1, sizeof(intlist));
361 q->i = as_number;
362 *(Tail) = q;
363 e->e_info = asinfo;
364 }
365 } else {
366 q = xcalloc(1, sizeof(intlist));
367 q->i = as_number;
368 asinfo = xmalloc(sizeof(asinfo));
369 asinfo->as_number = q;
370 rn = rn_addroute(e->e_addr, e->e_mask, AS_tree_head, e->e_nodes);
371 rn = rn_match(e->e_addr, AS_tree_head);
372 assert(rn != NULL);
373 e->e_info = asinfo;
374 }
375 if (rn == 0) {
376 xfree(e);
377 debug(53, 3) ("asnAddNet: Could not add entry.\n");
378 return 0;
379 }
380 e->e_info = asinfo;
381 return 1;
382 }
383
384 static int
385 destroyRadixNode(struct radix_node *rn, void *w)
386 {
387 struct radix_node_head *rnh = (struct radix_node_head *) w;
388
389 if (rn && !(rn->rn_flags & RNF_ROOT)) {
390 rtentry *e = (rtentry *) rn;
391 rn = rn_delete(rn->rn_key, rn->rn_mask, rnh);
392 if (rn == 0)
393 debug(53, 3) ("destroyRadixNode: internal screwup\n");
394 destroyRadixNodeInfo(e->e_info);
395 xfree(rn);
396 }
397 return 1;
398 }
399
400 static void
401 destroyRadixNodeInfo(as_info * e_info)
402 {
403 intlist *prev = NULL;
404 intlist *data = e_info->as_number;
405 while (data) {
406 prev = data;
407 data = data->next;
408 xfree(prev);
409 }
410 xfree(data);
411 }
412
413 int
414 mask_len(int mask)
415 {
416 int len = 32;
417 if (mask == 0)
418 return 0;
419 while ((mask & 1) == 0) {
420 len--;
421 mask >>= 1;
422 }
423 return len;
424 }
425
426 static int
427 printRadixNode(struct radix_node *rn, void *w)
428 {
429 StoreEntry *sentry = w;
430 rtentry *e = (rtentry *) rn;
431 intlist *q;
432 as_info *asinfo;
433 struct in_addr addr;
434 struct in_addr mask;
435 assert(e);
436 assert(e->e_info);
437 (void) get_m_int(addr.s_addr, e->e_addr);
438 (void) get_m_int(mask.s_addr, e->e_mask);
439 storeAppendPrintf(sentry, "%15s/%d\t",
440 inet_ntoa(addr), mask_len(ntohl(mask.s_addr)));
441 asinfo = e->e_info;
442 assert(asinfo->as_number);
443 for (q = asinfo->as_number; q; q = q->next)
444 storeAppendPrintf(sentry, " %d", q->i);
445 storeAppendPrintf(sentry, "\n");
446 return 0;
447 }