]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Asn.cc
c152f29bf3d2f4974476745b432c77aec14bf1d4
2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 53 AS Number handling */
14 #include "acl/Checklist.h"
15 #include "acl/DestinationAsn.h"
16 #include "acl/DestinationIp.h"
17 #include "acl/SourceAsn.h"
18 #include "acl/Strategised.h"
20 #include "HttpReply.h"
21 #include "HttpRequest.h"
23 #include "MasterXaction.h"
24 #include "mgr/Registration.h"
26 #include "RequestFlags.h"
27 #include "SquidConfig.h"
29 #include "StoreClient.h"
32 #define AS_REQBUF_SZ 4096
34 /* BEGIN of definitions for radix tree entries */
36 /* 32/128 bits address in memory with length */
43 m_ADDR() : len(sizeof(Ip::Address
)) {};
46 /* END of definitions for radix tree entries */
48 /* Head for ip to asn radix tree */
50 struct squid_radix_node_head
*AS_tree_head
;
52 /* explicit instantiation required for some systems */
54 /// \cond AUTODOCS_IGNORE
55 template cbdata_type CbDataList
<int>::CBDATA_CbDataList
;
59 * Structure for as number information. it could be simply
60 * a list but it's coded as a structure for future
61 * enhancements (e.g. expires)
64 CbDataList
<int> *as_number
;
65 time_t expires
; /* NOTUSED */
70 CBDATA_CLASS(ASState
);
78 HttpRequest::Pointer request
;
82 char reqbuf
[AS_REQBUF_SZ
];
86 CBDATA_CLASS_INIT(ASState
);
97 memset(reqbuf
, 0, AS_REQBUF_SZ
);
102 debugs(53, 3, entry
->url());
103 storeUnregister(sc
, entry
, this);
104 entry
->unlock("~ASState");
107 /** entry into the radix tree */
109 struct squid_radix_node e_nodes
[2];
115 static int asnAddNet(char *, int);
117 static void asnCacheStart(int as
);
119 static STCB asHandleReply
;
121 #if defined(__cplusplus)
125 static int destroyRadixNode(struct squid_radix_node
*rn
, void *w
);
126 static int printRadixNode(struct squid_radix_node
*rn
, void *sentry
);
128 #if defined(__cplusplus)
132 void asnAclInitialize(ACL
* acls
);
134 static void destroyRadixNodeInfo(as_info
*);
136 static OBJH asnStats
;
141 asnMatchIp(CbDataList
<int> *data
, Ip::Address
&addr
)
143 struct squid_radix_node
*rn
;
146 CbDataList
<int> *a
= NULL
;
147 CbDataList
<int> *b
= NULL
;
149 debugs(53, 3, "asnMatchIp: Called for " << addr
);
151 if (AS_tree_head
== NULL
)
157 if (addr
.isAnyAddr())
162 rn
= squid_rn_match(&m_addr
, AS_tree_head
);
165 debugs(53, 3, "asnMatchIp: Address not in as db.");
169 debugs(53, 3, "asnMatchIp: Found in db!");
170 e
= ((rtentry_t
*) rn
)->e_info
;
173 for (a
= data
; a
; a
= a
->next
)
174 for (b
= e
->as_number
; b
; b
= b
->next
)
175 if (a
->element
== b
->element
) {
176 debugs(53, 5, "asnMatchIp: Found a match!");
180 debugs(53, 5, "asnMatchIp: AS not in as db.");
185 ACLASN::prepareForUse()
187 for (CbDataList
<int> *i
= data
; i
; i
= i
->
189 asnCacheStart(i
->element
);
193 asnRegisterWithCacheManager(void)
195 Mgr::RegisterAction("asndb", "AS Number Database", asnStats
, 0, 1);
198 /* initialize the radix tree structure */
200 SQUIDCEXTERN
int squid_max_keylen
; /* yuck.. this is in lib/radix.c */
205 static bool inited
= false;
206 squid_max_keylen
= 40;
213 squid_rn_inithead(&AS_tree_head
, 8);
215 asnRegisterWithCacheManager();
221 squid_rn_walktree(AS_tree_head
, destroyRadixNode
, AS_tree_head
);
223 destroyRadixNode((struct squid_radix_node
*) 0, (void *) AS_tree_head
);
227 asnStats(StoreEntry
* sentry
)
229 storeAppendPrintf(sentry
, "Address \tAS Numbers\n");
230 squid_rn_walktree(AS_tree_head
, printRadixNode
, sentry
);
236 asnCacheStart(int as
)
238 LOCAL_ARRAY(char, asres
, 4096);
240 ASState
*asState
= new ASState
;
241 debugs(53, 3, "AS " << as
);
242 snprintf(asres
, 4096, "whois://%s/!gAS%d", Config
.as_whois_server
, as
);
243 asState
->as_number
= as
;
244 const MasterXaction::Pointer mx
= new MasterXaction(XactionInitiator::initAsn
);
245 asState
->request
= HttpRequest::FromUrl(asres
, mx
);
246 assert(asState
->request
!= NULL
);
248 if ((e
= storeGetPublic(asres
, Http::METHOD_GET
)) == NULL
) {
249 e
= storeCreateEntry(asres
, asres
, RequestFlags(), Http::METHOD_GET
);
250 asState
->sc
= storeClientListAdd(e
, asState
);
251 FwdState::fwdStart(Comm::ConnectionPointer(), e
, asState
->request
.getRaw());
254 asState
->sc
= storeClientListAdd(e
, asState
);
258 StoreIOBuffer
readBuffer (AS_REQBUF_SZ
, asState
->offset
, asState
->reqbuf
);
259 storeClientCopy(asState
->sc
, e
, readBuffer
, asHandleReply
, asState
);
263 asHandleReply(void *data
, StoreIOBuffer result
)
265 ASState
*asState
= (ASState
*)data
;
266 StoreEntry
*e
= asState
->entry
;
269 char *buf
= asState
->reqbuf
;
272 debugs(53, 3, "asHandleReply: Called with size=" << (unsigned int)result
.length
);
273 debugs(53, 3, "asHandleReply: buffer='" << buf
<< "'");
275 /* First figure out whether we should abort the request */
277 if (EBIT_TEST(e
->flags
, ENTRY_ABORTED
)) {
282 if (result
.length
== 0 && asState
->dataRead
) {
283 debugs(53, 3, "asHandleReply: Done: " << e
->url());
286 } else if (result
.flags
.error
) {
287 debugs(53, DBG_IMPORTANT
, "asHandleReply: Called with Error set and size=" << (unsigned int) result
.length
);
290 } else if (e
->getReply()->sline
.status() != Http::scOkay
) {
291 debugs(53, DBG_IMPORTANT
, "WARNING: AS " << asState
->as_number
<< " whois request failed");
297 * Next, attempt to parse our request
298 * Remembering that the actual buffer size is retsize + reqofs!
302 while ((size_t)(s
- buf
) < result
.length
+ asState
->reqofs
&& *s
!= '\0') {
303 while (*s
&& xisspace(*s
))
306 for (t
= s
; *t
; ++t
) {
312 /* oof, word should continue on next block */
317 debugs(53, 3, "asHandleReply: AS# " << s
<< " (" << asState
->as_number
<< ")");
318 asnAddNet(s
, asState
->as_number
);
320 asState
->dataRead
= true;
324 * Next, grab the end of the 'valid data' in the buffer, and figure
325 * out how much data is left in our buffer, which we need to keep
326 * around for the next request
328 leftoversz
= (asState
->reqofs
+ result
.length
) - (s
- buf
);
330 assert(leftoversz
>= 0);
333 * Next, copy the left over data, from s to s + leftoversz to the
334 * beginning of the buffer
336 memmove(buf
, s
, leftoversz
);
339 * Next, update our offset and reqofs, and kick off a copy if required
341 asState
->offset
+= result
.length
;
343 asState
->reqofs
= leftoversz
;
345 debugs(53, 3, "asState->offset = " << asState
->offset
);
347 if (e
->store_status
== STORE_PENDING
) {
348 debugs(53, 3, "asHandleReply: store_status == STORE_PENDING: " << e
->url() );
349 StoreIOBuffer
tempBuffer (AS_REQBUF_SZ
- asState
->reqofs
,
351 asState
->reqbuf
+ asState
->reqofs
);
352 storeClientCopy(asState
->sc
,
358 StoreIOBuffer tempBuffer
;
359 debugs(53, 3, "asHandleReply: store complete, but data received " << e
->url() );
360 tempBuffer
.offset
= asState
->offset
;
361 tempBuffer
.length
= AS_REQBUF_SZ
- asState
->reqofs
;
362 tempBuffer
.data
= asState
->reqbuf
+ asState
->reqofs
;
363 storeClientCopy(asState
->sc
,
372 * add a network (addr, mask) to the radix tree, with matching AS number
375 asnAddNet(char *as_string
, int as_number
)
377 struct squid_radix_node
*rn
;
378 CbDataList
<int> **Tail
= NULL
;
379 CbDataList
<int> *q
= NULL
;
380 as_info
*asinfo
= NULL
;
387 t
= strchr(as_string
, '/');
390 debugs(53, 3, "asnAddNet: failed, invalid response from whois server.");
401 // INET6 TODO : find a better way of identifying the base IPA family for mask than this.
402 t
= strchr(as_string
, '.');
404 // generate Netbits Format Mask
406 mask
.applyMask(bitl
, (t
!=NULL
?AF_INET
:AF_INET6
) );
408 debugs(53, 3, "asnAddNet: called for " << addr
<< "/" << mask
);
410 rtentry_t
*e
= (rtentry_t
*)xcalloc(1, sizeof(rtentry_t
));
412 e
->e_addr
.addr
= addr
;
414 e
->e_mask
.addr
= mask
;
416 rn
= squid_rn_lookup(&e
->e_addr
, &e
->e_mask
, AS_tree_head
);
419 asinfo
= ((rtentry_t
*) rn
)->e_info
;
421 if (asinfo
->as_number
->find(as_number
)) {
422 debugs(53, 3, "asnAddNet: Ignoring repeated network '" << addr
<< "/" << bitl
<< "' for AS " << as_number
);
424 debugs(53, 3, "asnAddNet: Warning: Found a network with multiple AS numbers!");
426 for (Tail
= &asinfo
->as_number
; *Tail
; Tail
= &(*Tail
)->next
);
427 q
= new CbDataList
<int> (as_number
);
434 q
= new CbDataList
<int> (as_number
);
435 asinfo
= (as_info
*)xmalloc(sizeof(as_info
));
436 asinfo
->as_number
= q
;
437 squid_rn_addroute(&e
->e_addr
, &e
->e_mask
, AS_tree_head
, e
->e_nodes
);
438 rn
= squid_rn_match(&e
->e_addr
, AS_tree_head
);
443 if (rn
== 0) { /* assert might expand to nothing */
447 debugs(53, 3, "asnAddNet: Could not add entry.");
456 destroyRadixNode(struct squid_radix_node
*rn
, void *w
)
459 struct squid_radix_node_head
*rnh
= (struct squid_radix_node_head
*) w
;
461 if (rn
&& !(rn
->rn_flags
& RNF_ROOT
)) {
462 rtentry_t
*e
= (rtentry_t
*) rn
;
463 rn
= squid_rn_delete(rn
->rn_key
, rn
->rn_mask
, rnh
);
466 debugs(53, 3, "destroyRadixNode: internal screwup");
468 destroyRadixNodeInfo(e
->e_info
);
477 destroyRadixNodeInfo(as_info
* e_info
)
479 CbDataList
<int> *prev
= NULL
;
480 CbDataList
<int> *data
= e_info
->as_number
;
490 printRadixNode(struct squid_radix_node
*rn
, void *_sentry
)
492 StoreEntry
*sentry
= (StoreEntry
*)_sentry
;
493 rtentry_t
*e
= (rtentry_t
*) rn
;
496 char buf
[MAX_IPSTRLEN
];
502 addr
= e
->e_addr
.addr
;
503 mask
= e
->e_mask
.addr
;
504 storeAppendPrintf(sentry
, "%s/%d\t",
505 addr
.toStr(buf
, MAX_IPSTRLEN
),
508 assert(asinfo
->as_number
);
510 for (q
= asinfo
->as_number
; q
; q
= q
->next
)
511 storeAppendPrintf(sentry
, " %d", q
->element
);
513 storeAppendPrintf(sentry
, "\n");
526 ACLASN::match(Ip::Address toMatch
)
528 return asnMatchIp(data
, toMatch
);
536 CbDataList
<int> *ldata
= data
;
538 while (ldata
!= NULL
) {
540 s
.Printf("%d", ldata
->element
);
549 ACLASN::empty () const
557 CbDataList
<int> **curlist
= &data
;
558 CbDataList
<int> **Tail
;
559 CbDataList
<int> *q
= NULL
;
562 for (Tail
= curlist
; *Tail
; Tail
= &((*Tail
)->next
));
563 while ((t
= ConfigParser::strtokFile())) {
564 q
= new CbDataList
<int> (atoi(t
));
570 ACLData
<Ip::Address
> *
571 ACLASN::clone() const
574 fatal ("cloning of ACLASN not implemented");
576 return new ACLASN(*this);
579 /* explicit template instantiation required for some systems */
581 template class ACLStrategised
<Ip::Address
>;
584 ACLSourceASNStrategy::match (ACLData
<Ip::Address
> * &data
, ACLFilledChecklist
*checklist
)
586 return data
->match(checklist
->src_addr
);
590 ACLDestinationASNStrategy::match (ACLData
<MatchType
> * &data
, ACLFilledChecklist
*checklist
)
592 const ipcache_addrs
*ia
= ipcache_gethostbyname(checklist
->request
->url
.host(), IP_LOOKUP_IF_MISS
);
595 for (int k
= 0; k
< (int) ia
->count
; ++k
) {
596 if (data
->match(ia
->in_addrs
[k
]))
602 } else if (!checklist
->request
->flags
.destinationIpLookedUp
) {
603 /* No entry in cache, lookup not attempted */
604 debugs(28, 3, "can't yet compare '" << AclMatchedName
<< "' ACL for " << checklist
->request
->url
.host());
605 if (checklist
->goAsync(DestinationIPLookup::Instance()))
607 // else fall through to noaddr match, hiding the lookup failure (XXX)
611 return data
->match(noaddr
);