]> git.ipfire.org Git - thirdparty/squid.git/blame - src/asn.cc
merge changes from SQUID_2_3 branch
[thirdparty/squid.git] / src / asn.cc
CommitLineData
6dd85329 1/*
7e3ce7b9 2 * $Id: asn.cc,v 1.58 1999/12/30 17:36:22 wessels Exp $
6dd85329 3 *
4 * DEBUG: section 53 AS Number handling
d9067cd1 5 * AUTHOR: Duane Wessels, Kostas Anagnostakis
6dd85329 6 *
7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 8 * ----------------------------------------------------------
6dd85329 9 *
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
e25c139f 12 * National Laboratory for Applied Network Research and funded by the
13 * National Science Foundation. Squid is Copyrighted (C) 1998 by
14 * Duane Wessels and the University of California San Diego. Please
15 * see the COPYRIGHT file for full details. Squid incorporates
16 * software developed and/or copyrighted by other sources. Please see
17 * the CREDITS file for full details.
6dd85329 18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
6dd85329 33 */
5d6c7aad 34
35#include "squid.h"
36
37#define WHOIS_PORT 43
38
6dd85329 39/* BEGIN of definitions for radix tree entries */
40
afb0ef05 41/* int in memory with length */
0cdcddb9 42typedef u_char m_int[1 + sizeof(unsigned int)];
6dd85329 43#define store_m_int(i, m) \
72ef6df6 44 (i = htonl(i), m[0] = sizeof(m_int), xmemcpy(m+1, &i, sizeof(unsigned int)))
6dd85329 45#define get_m_int(i, m) \
72ef6df6 46 (xmemcpy(&i, m+1, sizeof(unsigned int)), ntohl(i))
6dd85329 47
48/* END of definitions for radix tree entries */
49
6dd85329 50/* Head for ip to asn radix tree */
51struct radix_node_head *AS_tree_head;
5d6c7aad 52
f899fac1 53/*
54 * Structure for as number information. it could be simply
6dd85329 55 * an intlist but it's coded as a structure for future
f899fac1 56 * enhancements (e.g. expires)
57 */
6dd85329 58struct _as_info {
59 intlist *as_number;
69c8d152 60 time_t expires; /* NOTUSED */
6dd85329 61};
53ad48e6 62
63struct _ASState {
64 StoreEntry *entry;
53ad48e6 65 request_t *request;
53ad48e6 66 int as_number;
5db53b8f 67 off_t seen;
68 off_t offset;
53ad48e6 69};
70
71typedef struct _ASState ASState;
6dd85329 72typedef struct _as_info as_info;
73
74/* entry into the radix tree */
75struct _rtentry {
76 struct radix_node e_nodes[2];
77 as_info *e_info;
78 m_int e_addr;
79 m_int e_mask;
80};
81
82typedef struct _rtentry rtentry;
83
f899fac1 84static int asnAddNet(char *, int);
53ad48e6 85static void asnCacheStart(int as);
53ad48e6 86static STCB asHandleReply;
f899fac1 87static int destroyRadixNode(struct radix_node *rn, void *w);
69c8d152 88static int printRadixNode(struct radix_node *rn, void *w);
4bac8de8 89static void asnAclInitialize(acl * acls);
0860ee40 90static void asStateFree(void *data);
53ad48e6 91static void destroyRadixNodeInfo(as_info *);
69c8d152 92static OBJH asnStats;
53ad48e6 93
53ad48e6 94extern struct radix_node *rn_lookup(void *, void *, void *);
6dd85329 95
96
5d6c7aad 97/* PUBLIC */
98
99int
100asnMatchIp(void *data, struct in_addr addr)
101{
6dd85329 102 unsigned long lh;
103 struct radix_node *rn;
104 as_info *e;
105 m_int m_addr;
f899fac1 106 intlist *a = NULL;
107 intlist *b = NULL;
6dd85329 108 lh = ntohl(addr.s_addr);
de7587a2 109 debug(53, 3) ("asnMatchIp: Called for %s.\n", inet_ntoa(addr));
6dd85329 110
0ef05486 111 if (AS_tree_head == NULL)
112 return 0;
7406d2ea 113 if (addr.s_addr == no_addr.s_addr)
0ef05486 114 return 0;
7406d2ea 115 if (addr.s_addr == any_addr.s_addr)
6dd85329 116 return 0;
117 store_m_int(lh, m_addr);
118 rn = rn_match(m_addr, AS_tree_head);
0ef05486 119 if (rn == NULL) {
de7587a2 120 debug(53, 3) ("asnMatchIp: Address not in as db.\n");
6dd85329 121 return 0;
122 }
de7587a2 123 debug(53, 3) ("asnMatchIp: Found in db!\n");
6dd85329 124 e = ((rtentry *) rn)->e_info;
0ef05486 125 assert(e);
6dd85329 126 for (a = (intlist *) data; a; a = a->next)
127 for (b = e->as_number; b; b = b->next)
128 if (a->i == b->i) {
129 debug(53, 5) ("asnMatchIp: Found a match!\n");
130 return 1;
131 }
132 debug(53, 5) ("asnMatchIp: AS not in as db.\n");
5d6c7aad 133 return 0;
134}
135
4bac8de8 136static void
5d6c7aad 137asnAclInitialize(acl * acls)
138{
139 acl *a;
140 intlist *i;
56b63fa1 141 debug(53, 3) ("asnAclInitialize\n");
5d6c7aad 142 for (a = acls; a; a = a->next) {
143 if (a->type != ACL_DST_ASN && a->type != ACL_SRC_ASN)
144 continue;
f899fac1 145 for (i = a->data; i; i = i->next)
53ad48e6 146 asnCacheStart(i->i);
5d6c7aad 147 }
148}
149
f899fac1 150/* initialize the radix tree structure */
151
152void
153asnInit(void)
154{
155 extern int max_keylen;
f1fc2a8d 156 static int inited = 0;
f899fac1 157 max_keylen = 40;
f1fc2a8d 158 if (0 == inited++)
c68e9c6b 159 rn_init();
f899fac1 160 rn_inithead((void **) &AS_tree_head, 8);
4bac8de8 161 asnAclInitialize(Config.aclList);
69c8d152 162 cachemgrRegister("asndb", "AS Number Database", asnStats, 0, 1);
f899fac1 163}
164
165void
166asnFreeMemory(void)
f899fac1 167{
168 rn_walktree(AS_tree_head, destroyRadixNode, AS_tree_head);
169 destroyRadixNode((struct radix_node *) 0, (void *) AS_tree_head);
170}
171
69c8d152 172static void
173asnStats(StoreEntry * sentry)
174{
175 storeAppendPrintf(sentry, "Address \tAS Numbers\n");
176 rn_walktree(AS_tree_head, printRadixNode, sentry);
177}
178
5d6c7aad 179/* PRIVATE */
180
6dd85329 181
53ad48e6 182static void
183asnCacheStart(int as)
184{
185 LOCAL_ARRAY(char, asres, 4096);
f899fac1 186 StoreEntry *e;
0529b344 187 request_t *req;
f899fac1 188 ASState *asState = xcalloc(1, sizeof(ASState));
db1cd23c 189 cbdataAdd(asState, cbdataXfree, 0);
f899fac1 190 debug(53, 3) ("asnCacheStart: AS %d\n", as);
53ad48e6 191 snprintf(asres, 4096, "whois://%s/!gAS%d", Config.as_whois_server, as);
53ad48e6 192 asState->as_number = as;
0529b344 193 req = urlParse(METHOD_GET, asres);
194 assert(NULL != req);
195 asState->request = requestLink(req);
2f9aa365 196 if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
2c76f5d3 197 e = storeCreateEntry(asres, asres, null_request_flags, METHOD_GET);
f899fac1 198 storeClientListAdd(e, asState);
7e3ce7b9 199 fwdStart(-1, e, asState->request);
53ad48e6 200 } else {
f899fac1 201 storeLockObject(e);
202 storeClientListAdd(e, asState);
53ad48e6 203 }
f899fac1 204 asState->entry = e;
5db53b8f 205 asState->seen = 0;
206 asState->offset = 0;
207 storeClientCopy(e,
208 asState->seen,
209 asState->offset,
210 4096,
211 memAllocate(MEM_4K_BUF),
212 asHandleReply,
213 asState);
53ad48e6 214}
215
216static void
217asHandleReply(void *data, char *buf, ssize_t size)
218{
53ad48e6 219 ASState *asState = data;
f899fac1 220 StoreEntry *e = asState->entry;
221 char *s;
222 char *t;
5db53b8f 223 debug(53, 3) ("asHandleReply: Called with size=%d\n", size);
b7fe0ab0 224 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
db1cd23c 225 memFree(buf, MEM_4K_BUF);
0860ee40 226 asStateFree(asState);
53ad48e6 227 return;
228 }
5b2f2d54 229 if (size == 0 && e->mem_obj->inmem_hi > 0) {
db1cd23c 230 memFree(buf, MEM_4K_BUF);
0860ee40 231 asStateFree(asState);
53ad48e6 232 return;
233 } else if (size < 0) {
5db53b8f 234 debug(53, 1) ("asHandleReply: Called with size=%d\n", size);
db1cd23c 235 memFree(buf, MEM_4K_BUF);
0860ee40 236 asStateFree(asState);
53ad48e6 237 return;
238 }
53ad48e6 239 s = buf;
5b2f2d54 240 while (s - buf < size && *s != '\0') {
b6a2f15e 241 while (*s && xisspace(*s))
5db53b8f 242 s++;
53ad48e6 243 for (t = s; *t; t++) {
b6a2f15e 244 if (xisspace(*t))
53ad48e6 245 break;
246 }
247 if (*t == '\0') {
248 /* oof, word should continue on next block */
249 break;
250 }
251 *t = '\0';
5db53b8f 252 debug(53, 3) ("asHandleReply: AS# %s (%d)\n", s, asState->as_number);
f899fac1 253 asnAddNet(s, asState->as_number);
53ad48e6 254 s = t + 1;
53ad48e6 255 }
5db53b8f 256 asState->seen = asState->offset + size;
257 asState->offset += (s - buf);
258 debug(53, 3) ("asState->seen = %d, asState->offset = %d\n",
259 asState->seen, asState->offset);
260 if (e->store_status == STORE_PENDING) {
0860ee40 261 debug(53, 3) ("asHandleReply: store_status == STORE_PENDING: %s\n", storeUrl(e));
262 storeClientCopy(e,
263 asState->seen,
264 asState->offset,
265 SM_PAGE_SIZE,
266 buf,
267 asHandleReply,
268 asState);
269 } else if (asState->seen < e->mem_obj->inmem_hi) {
270 debug(53, 3) ("asHandleReply: asState->seen < e->mem_obj->inmem_hi %s\n", storeUrl(e));
5db53b8f 271 storeClientCopy(e,
272 asState->seen,
273 asState->offset,
274 SM_PAGE_SIZE,
275 buf,
276 asHandleReply,
277 asState);
278 } else {
279 debug(53, 3) ("asHandleReply: Done: %s\n", storeUrl(e));
db1cd23c 280 memFree(buf, MEM_4K_BUF);
0860ee40 281 asStateFree(asState);
5db53b8f 282 }
5d6c7aad 283}
6dd85329 284
0860ee40 285static void
286asStateFree(void *data)
287{
288 ASState *asState = data;
289 debug(53, 3) ("asnStateFree: %s\n", storeUrl(asState->entry));
290 storeUnregister(asState->entry, asState);
291 storeUnlockObject(asState->entry);
292 requestUnlink(asState->request);
293 cbdataFree(asState);
294}
295
6dd85329 296
297/* add a network (addr, mask) to the radix tree, with matching AS
298 * number */
299
300static int
f899fac1 301asnAddNet(char *as_string, int as_number)
6dd85329 302{
303 rtentry *e = xmalloc(sizeof(rtentry));
304 struct radix_node *rn;
305 char dbg1[32], dbg2[32];
306 intlist **Tail = NULL;
307 intlist *q = NULL;
c68e9c6b 308 as_info *asinfo = NULL;
6dd85329 309 struct in_addr in_a, in_m;
310 long mask, addr;
311 char *t;
312 int bitl;
313
78947b18 314 t = strchr(as_string, '/');
6dd85329 315 if (t == NULL) {
f899fac1 316 debug(53, 3) ("asnAddNet: failed, invalid response from whois server.\n");
6dd85329 317 return 0;
318 }
319 *t = '\0';
320 addr = inet_addr(as_string);
321 bitl = atoi(t + 1);
5db53b8f 322 if (bitl < 0)
323 bitl = 0;
324 if (bitl > 32)
325 bitl = 32;
326 mask = bitl ? 0xfffffffful << (32 - bitl) : 0;
6dd85329 327
328 in_a.s_addr = addr;
329 in_m.s_addr = mask;
72ef6df6 330 xstrncpy(dbg1, inet_ntoa(in_a), 32);
331 xstrncpy(dbg2, inet_ntoa(in_m), 32);
6dd85329 332 addr = ntohl(addr);
69c8d152 333 /*mask = ntohl(mask); */
5f6ac48b 334 debug(53, 3) ("asnAddNet: called for %s/%s\n", dbg1, dbg2);
6dd85329 335 memset(e, '\0', sizeof(rtentry));
336 store_m_int(addr, e->e_addr);
337 store_m_int(mask, e->e_mask);
338 rn = rn_lookup(e->e_addr, e->e_mask, AS_tree_head);
5db53b8f 339 if (rn != NULL) {
c68e9c6b 340 asinfo = ((rtentry *) rn)->e_info;
341 if (intlistFind(asinfo->as_number, as_number)) {
5db53b8f 342 debug(53, 3) ("asnAddNet: Ignoring repeated network '%s/%d' for AS %d\n",
343 dbg1, bitl, as_number);
344 } else {
345 debug(53, 3) ("asnAddNet: Warning: Found a network with multiple AS numbers!\n");
c68e9c6b 346 for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
5db53b8f 347 q = xcalloc(1, sizeof(intlist));
348 q->i = as_number;
349 *(Tail) = q;
c68e9c6b 350 e->e_info = asinfo;
5db53b8f 351 }
6dd85329 352 } else {
353 q = xcalloc(1, sizeof(intlist));
354 q->i = as_number;
c68e9c6b 355 asinfo = xmalloc(sizeof(asinfo));
356 asinfo->as_number = q;
6dd85329 357 rn = rn_addroute(e->e_addr, e->e_mask, AS_tree_head, e->e_nodes);
358 rn = rn_match(e->e_addr, AS_tree_head);
f899fac1 359 assert(rn != NULL);
c68e9c6b 360 e->e_info = asinfo;
6dd85329 361 }
362 if (rn == 0) {
363 xfree(e);
f899fac1 364 debug(53, 3) ("asnAddNet: Could not add entry.\n");
6dd85329 365 return 0;
366 }
c68e9c6b 367 e->e_info = asinfo;
53ad48e6 368 return 1;
369}
370
371static int
372destroyRadixNode(struct radix_node *rn, void *w)
373{
374 struct radix_node_head *rnh = (struct radix_node_head *) w;
375
376 if (rn && !(rn->rn_flags & RNF_ROOT)) {
377 rtentry *e = (rtentry *) rn;
378 rn = rn_delete(rn->rn_key, rn->rn_mask, rnh);
379 if (rn == 0)
380 debug(53, 3) ("destroyRadixNode: internal screwup\n");
381 destroyRadixNodeInfo(e->e_info);
382 xfree(rn);
383 }
6dd85329 384 return 1;
385}
53ad48e6 386
53ad48e6 387static void
388destroyRadixNodeInfo(as_info * e_info)
389{
a200bbd2 390 intlist *prev = NULL;
53ad48e6 391 intlist *data = e_info->as_number;
53ad48e6 392 while (data) {
393 prev = data;
394 data = data->next;
395 xfree(prev);
396 }
397 xfree(data);
398}
69c8d152 399
400int
401mask_len(int mask)
402{
403 int len = 32;
404 while ((mask & 1) == 0) {
405 len--;
406 mask >>= 1;
407 }
408 return len;
409}
410
411static int
412printRadixNode(struct radix_node *rn, void *w)
413{
414 StoreEntry *sentry = w;
415 rtentry *e = (rtentry *) rn;
416 intlist *q;
c68e9c6b 417 as_info *asinfo;
69c8d152 418 struct in_addr addr;
419 struct in_addr mask;
420 assert(e);
c68e9c6b 421 assert(e->e_info);
69c8d152 422 (void) get_m_int(addr.s_addr, e->e_addr);
423 (void) get_m_int(mask.s_addr, e->e_mask);
424 storeAppendPrintf(sentry, "%15s/%d\t",
425 inet_ntoa(addr), mask_len(ntohl(mask.s_addr)));
c68e9c6b 426 asinfo = e->e_info;
427 assert(asinfo->as_number);
428 for (q = asinfo->as_number; q; q = q->next)
69c8d152 429 storeAppendPrintf(sentry, " %d", q->i);
430 storeAppendPrintf(sentry, "\n");
431 return 0;
432}