]>
Commit | Line | Data |
---|---|---|
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 | 42 | typedef 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 */ |
51 | struct 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 | 58 | struct _as_info { |
59 | intlist *as_number; | |
69c8d152 | 60 | time_t expires; /* NOTUSED */ |
6dd85329 | 61 | }; |
53ad48e6 | 62 | |
63 | struct _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 | ||
71 | typedef struct _ASState ASState; | |
6dd85329 | 72 | typedef struct _as_info as_info; |
73 | ||
74 | /* entry into the radix tree */ | |
75 | struct _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 | ||
82 | typedef struct _rtentry rtentry; | |
83 | ||
f899fac1 | 84 | static int asnAddNet(char *, int); |
53ad48e6 | 85 | static void asnCacheStart(int as); |
53ad48e6 | 86 | static STCB asHandleReply; |
f899fac1 | 87 | static int destroyRadixNode(struct radix_node *rn, void *w); |
69c8d152 | 88 | static int printRadixNode(struct radix_node *rn, void *w); |
4bac8de8 | 89 | static void asnAclInitialize(acl * acls); |
0860ee40 | 90 | static void asStateFree(void *data); |
53ad48e6 | 91 | static void destroyRadixNodeInfo(as_info *); |
69c8d152 | 92 | static OBJH asnStats; |
53ad48e6 | 93 | |
53ad48e6 | 94 | extern struct radix_node *rn_lookup(void *, void *, void *); |
6dd85329 | 95 | |
96 | ||
5d6c7aad | 97 | /* PUBLIC */ |
98 | ||
99 | int | |
100 | asnMatchIp(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 | 136 | static void |
5d6c7aad | 137 | asnAclInitialize(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 | ||
152 | void | |
153 | asnInit(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 | ||
165 | void | |
166 | asnFreeMemory(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 | 172 | static void |
173 | asnStats(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 | 182 | static void |
183 | asnCacheStart(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 | ||
216 | static void | |
217 | asHandleReply(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 | 285 | static void |
286 | asStateFree(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 | ||
300 | static int | |
f899fac1 | 301 | asnAddNet(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 | ||
371 | static int | |
372 | destroyRadixNode(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 | 387 | static void |
388 | destroyRadixNodeInfo(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 | |
400 | int | |
401 | mask_len(int mask) | |
402 | { | |
403 | int len = 32; | |
404 | while ((mask & 1) == 0) { | |
405 | len--; | |
406 | mask >>= 1; | |
407 | } | |
408 | return len; | |
409 | } | |
410 | ||
411 | static int | |
412 | printRadixNode(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 | } |