Asn.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 53 AS Number handling */
10
11#include "squid.h"
12#include "acl/Acl.h"
13#include "acl/Asn.h"
14#include "acl/DestinationAsn.h"
15#include "acl/DestinationIp.h"
16#include "acl/FilledChecklist.h"
17#include "acl/SourceAsn.h"
18#include "base/CharacterSet.h"
19#include "FwdState.h"
20#include "HttpReply.h"
21#include "HttpRequest.h"
22#include "ipcache.h"
23#include "MasterXaction.h"
24#include "mgr/Registration.h"
25#include "parser/Tokenizer.h"
26#include "radix.h"
27#include "RequestFlags.h"
28#include "sbuf/SBuf.h"
29#include "SquidConfig.h"
30#include "Store.h"
31#include "StoreClient.h"
32
33/* BEGIN of definitions for radix tree entries */
34
35/* 32/128 bits address in memory with length */
36class m_ADDR
37{
38public:
39 uint8_t len;
41
42 m_ADDR() : len(sizeof(Ip::Address)) {};
43};
44
45/* END of definitions for radix tree entries */
46
47/* Head for ip to asn radix tree */
48
50
51/* explicit instantiation required for some systems */
52
56
62struct as_info {
64 time_t expires; /* NOTUSED */
65};
66
68{
70
71public:
72 ASState() = default;
73
75 if (entry) {
76 debugs(53, 3, entry->url());
77 storeUnregister(sc, entry, this);
78 entry->unlock("~ASState");
79 }
80 }
81
82public:
83 StoreEntry *entry = nullptr;
84 store_client *sc = nullptr;
86 int as_number = 0;
87
90};
91
93
95struct rtentry_t {
96 struct squid_radix_node e_nodes[2];
100};
101
102static int asnAddNet(const SBuf &, int);
103
104static void asnCacheStart(int as);
105
107
108#if defined(__cplusplus)
109extern "C" {
110#endif
111
112static int destroyRadixNode(struct squid_radix_node *rn, void *w);
113static int printRadixNode(struct squid_radix_node *rn, void *sentry);
114
115#if defined(__cplusplus)
116}
117#endif
118
120
121static void destroyRadixNodeInfo(as_info *);
122
124
125/* PUBLIC */
126
127int
129{
130 struct squid_radix_node *rn;
131 as_info *e;
132 m_ADDR m_addr;
133 CbDataList<int> *a = nullptr;
134 CbDataList<int> *b = nullptr;
135
136 debugs(53, 3, "asnMatchIp: Called for " << addr );
137
138 if (AS_tree_head == nullptr)
139 return 0;
140
141 if (addr.isNoAddr())
142 return 0;
143
144 if (addr.isAnyAddr())
145 return 0;
146
147 m_addr.addr = addr;
148
149 rn = squid_rn_match(&m_addr, AS_tree_head);
150
151 if (rn == nullptr) {
152 debugs(53, 3, "asnMatchIp: Address not in as db.");
153 return 0;
154 }
155
156 debugs(53, 3, "asnMatchIp: Found in db!");
157 e = ((rtentry_t *) rn)->e_info;
158 assert(e);
159
160 for (a = data; a; a = a->next)
161 for (b = e->as_number; b; b = b->next)
162 if (a->element == b->element) {
163 debugs(53, 5, "asnMatchIp: Found a match!");
164 return 1;
165 }
166
167 debugs(53, 5, "asnMatchIp: AS not in as db.");
168 return 0;
169}
170
171void
173{
174 for (CbDataList<int> *i = data; i; i = i->
175 next)
176 asnCacheStart(i->element);
177}
178
179static void
181{
182 Mgr::RegisterAction("asndb", "AS Number Database", asnStats, 0, 1);
183}
184
185/* initialize the radix tree structure */
186
187SQUIDCEXTERN int squid_max_keylen; /* yuck.. this is in lib/radix.c */
188
189void
191{
192 static bool inited = false;
193 squid_max_keylen = 40;
194
195 if (!inited) {
196 inited = true;
198 }
199
201
203}
204
205void
207{
209
210 destroyRadixNode((struct squid_radix_node *) nullptr, (void *) AS_tree_head);
211}
212
213static void
215{
216 storeAppendPrintf(sentry, "Address \tAS Numbers\n");
218}
219
220/* PRIVATE */
221
222static void
224{
226 whoisUrl.host(Config.as_whois_server);
227 whoisUrl.defaultPort();
228
229 SBuf asPath("/!gAS");
230 asPath.appendf("%d", as);
231 whoisUrl.path(asPath);
232
233 debugs(53, 3, "AS " << as);
234 ASState *asState = new ASState;
235 asState->as_number = as;
236 const auto mx = MasterXaction::MakePortless<XactionInitiator::initAsn>();
237 asState->request = new HttpRequest(mx);
238 asState->request->url = whoisUrl;
239 asState->request->method = Http::METHOD_GET;
240
241 // XXX: performance regression, c_str() reallocates
242 const auto asres = xstrdup(whoisUrl.absolute().c_str());
243
244 // XXX: Missing a hittingRequiresCollapsing() && startCollapsingOn() check.
245 auto e = storeGetPublic(asres, Http::METHOD_GET);
246 if (!e) {
247 e = storeCreateEntry(asres, asres, RequestFlags(), Http::METHOD_GET);
248 asState->sc = storeClientListAdd(e, asState);
250 } else {
251 e->lock("Asn");
252 asState->sc = storeClientListAdd(e, asState);
253 }
254 xfree(asres);
255
256 asState->entry = e;
257 storeClientCopy(asState->sc, e, asState->parsingBuffer.makeInitialSpace(), asHandleReply, asState);
258}
259
260static void
261asHandleReply(void *data, StoreIOBuffer result)
262{
263 ASState *asState = (ASState *)data;
264 StoreEntry *e = asState->entry;
265
266 debugs(53, 3, result << " for " << asState->as_number << " with " << *e);
267
268 /* First figure out whether we should abort the request */
269
270 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
271 delete asState;
272 return;
273 }
274
275 if (result.flags.error) {
276 debugs(53, DBG_IMPORTANT, "ERROR: asHandleReply: Called with Error set and size=" << (unsigned int) result.length);
277 delete asState;
278 return;
279 } else if (e->mem().baseReply().sline.status() != Http::scOkay) {
280 debugs(53, DBG_IMPORTANT, "WARNING: AS " << asState->as_number << " whois request failed");
281 delete asState;
282 return;
283 }
284
285 asState->parsingBuffer.appended(result.data, result.length);
287 SBuf address;
288 // Word delimiters in WHOIS ASN replies. RFC 3912 mentions SP, CR, and LF.
289 // Others are added to mimic an earlier isspace()-based implementation.
290 static const auto WhoisSpaces = CharacterSet("ASCII_spaces", " \f\r\n\t\v");
291 while (tok.token(address, WhoisSpaces)) {
292 (void)asnAddNet(address, asState->as_number);
293 }
294 asState->parsingBuffer.consume(tok.parsedSize());
295 const auto leftoverBytes = asState->parsingBuffer.contentSize();
296
297 if (asState->sc->atEof()) {
298 if (leftoverBytes)
299 debugs(53, 2, "WHOIS: Discarding the last " << leftoverBytes << " received bytes of a truncated AS response");
300 delete asState;
301 return;
302 }
303
304 const auto remainingSpace = asState->parsingBuffer.space().positionAt(result.offset + result.length);
305
306 if (!remainingSpace.length) {
307 Assure(leftoverBytes);
308 debugs(53, DBG_IMPORTANT, "WARNING: Ignoring the tail of a WHOIS AS response" <<
309 " with an unparsable section of " << leftoverBytes <<
310 " bytes ending at offset " << remainingSpace.offset);
311 delete asState;
312 return;
313 }
314
315 const decltype(StoreIOBuffer::offset) stillReasonableOffset = 100000; // an arbitrary limit in bytes
316 if (remainingSpace.offset > stillReasonableOffset) {
317 // stop suspicious accumulation of parsed addresses and/or work
318 debugs(53, DBG_IMPORTANT, "WARNING: Ignoring the tail of a suspiciously large WHOIS AS response" <<
319 " exceeding " << stillReasonableOffset << " bytes");
320 delete asState;
321 return;
322 }
323
324 storeClientCopy(asState->sc, e, remainingSpace, asHandleReply, asState);
325}
326
330static int
331asnAddNet(const SBuf &addressAndMask, const int as_number)
332{
333 struct squid_radix_node *rn;
334 CbDataList<int> **Tail = nullptr;
335 CbDataList<int> *q = nullptr;
336 as_info *asinfo = nullptr;
337
338 static const CharacterSet NonSlashSet = CharacterSet("slash", "/").complement("non-slash");
339 Parser::Tokenizer tok(addressAndMask);
340 SBuf addressToken;
341 if (!(tok.prefix(addressToken, NonSlashSet) && tok.skip('/'))) {
342 debugs(53, 3, "asnAddNet: failed, invalid response from whois server.");
343 return 0;
344 }
345 const Ip::Address addr = addressToken.c_str();
346
347 // INET6 TODO : find a better way of identifying the base IPA family for mask than this.
348 const auto addrFamily = (addressToken.find('.') != SBuf::npos) ? AF_INET : AF_INET6;
349
350 // generate Netbits Format Mask
351 Ip::Address mask;
352 mask.setNoAddr();
353 int64_t bitl = 0;
354 if (tok.int64(bitl, 10, false))
355 mask.applyMask(bitl, addrFamily);
356
357 debugs(53, 3, "asnAddNet: called for " << addr << "/" << mask );
358
359 rtentry_t *e = (rtentry_t *)xcalloc(1, sizeof(rtentry_t));
360
361 e->e_addr.addr = addr;
362
363 e->e_mask.addr = mask;
364
366
367 if (rn != nullptr) {
368 asinfo = ((rtentry_t *) rn)->e_info;
369
370 if (asinfo->as_number->find(as_number)) {
371 debugs(53, 3, "asnAddNet: Ignoring repeated network '" << addr << "/" << bitl << "' for AS " << as_number);
372 } else {
373 debugs(53, 3, "asnAddNet: Warning: Found a network with multiple AS numbers!");
374
375 for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
376 q = new CbDataList<int> (as_number);
377
378 *(Tail) = q;
379
380 e->e_info = asinfo;
381 }
382 } else {
383 q = new CbDataList<int> (as_number);
384 asinfo = (as_info *)xmalloc(sizeof(as_info));
385 asinfo->as_number = q;
388 assert(rn != nullptr);
389 e->e_info = asinfo;
390 }
391
392 if (rn == nullptr) { /* assert might expand to nothing */
393 xfree(asinfo);
394 delete q;
395 xfree(e);
396 debugs(53, 3, "asnAddNet: Could not add entry.");
397 return 0;
398 }
399
400 e->e_info = asinfo;
401 return 1;
402}
403
404static int
406{
407
408 struct squid_radix_node_head *rnh = (struct squid_radix_node_head *) w;
409
410 if (rn && !(rn->rn_flags & RNF_ROOT)) {
411 rtentry_t *e = (rtentry_t *) rn;
412 rn = squid_rn_delete(rn->rn_key, rn->rn_mask, rnh);
413
414 if (rn == nullptr)
415 debugs(53, 3, "destroyRadixNode: internal screwup");
416
418
419 xfree(rn);
420 }
421
422 return 1;
423}
424
425static void
427{
428 CbDataList<int> *prev = nullptr;
429 CbDataList<int> *data = e_info->as_number;
430
431 while (data) {
432 prev = data;
433 data = data->next;
434 delete prev;
435 }
436}
437
438static int
439printRadixNode(struct squid_radix_node *rn, void *_sentry)
440{
441 StoreEntry *sentry = (StoreEntry *)_sentry;
442 rtentry_t *e = (rtentry_t *) rn;
444 as_info *asinfo;
445 char buf[MAX_IPSTRLEN];
446 Ip::Address addr;
447 Ip::Address mask;
448
449 assert(e);
450 assert(e->e_info);
451 addr = e->e_addr.addr;
452 mask = e->e_mask.addr;
453 storeAppendPrintf(sentry, "%s/%d\t",
454 addr.toStr(buf, MAX_IPSTRLEN),
455 mask.cidr() );
456 asinfo = e->e_info;
457 assert(asinfo->as_number);
458
459 for (q = asinfo->as_number; q; q = q->next)
460 storeAppendPrintf(sentry, " %d", q->element);
461
462 storeAppendPrintf(sentry, "\n");
463
464 return 0;
465}
466
468{
469 if (data)
470 delete data;
471}
472
473bool
474
476{
477 return asnMatchIp(data, toMatch);
478}
479
482{
483 SBufList sl;
484
485 CbDataList<int> *ldata = data;
486
487 while (ldata != nullptr) {
488 SBuf s;
489 s.Printf("%d", ldata->element);
490 sl.push_back(s);
491 ldata = ldata->next;
492 }
493
494 return sl;
495}
496
497bool
499{
500 return data == nullptr;
501}
502
503void
505{
506 CbDataList<int> **curlist = &data;
507 CbDataList<int> **Tail;
508 CbDataList<int> *q = nullptr;
509 char *t = nullptr;
510
511 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
512 while ((t = ConfigParser::strtokFile())) {
513 q = new CbDataList<int> (atoi(t));
514 *(Tail) = q;
515 Tail = &q->next;
516 }
517}
518
519int
521{
522 const auto checklist = Filled(ch);
523
524 return data->match(checklist->src_addr);
525}
526
527int
529{
530 const auto checklist = Filled(ch);
531
532 const ipcache_addrs *ia = ipcache_gethostbyname(checklist->request->url.host(), IP_LOOKUP_IF_MISS);
533
534 if (ia) {
535 for (const auto &ip: ia->goodAndBad()) {
536 if (data->match(ip))
537 return 1;
538 }
539
540 return 0;
541
542 } else if (!checklist->request->flags.destinationIpLookedUp) {
543 /* No entry in cache, lookup not attempted */
544 debugs(28, 3, "can't yet compare '" << AclMatchedName << "' ACL for " << checklist->request->url.host());
545 if (checklist->goAsync(DestinationIPLookup::Instance()))
546 return -1;
547 // else fall through to noaddr match, hiding the lookup failure (XXX)
548 }
549 Ip::Address noaddr;
550 noaddr.setNoAddr();
551 return data->match(noaddr);
552}
553
CBDATA_CLASS_INIT(ASState)
static STCB asHandleReply
Definition: Asn.cc:106
static int printRadixNode(struct squid_radix_node *rn, void *sentry)
Definition: Asn.cc:439
static int destroyRadixNode(struct squid_radix_node *rn, void *w)
Definition: Asn.cc:405
int asnMatchIp(CbDataList< int > *data, Ip::Address &addr)
Definition: Asn.cc:128
static OBJH asnStats
Definition: Asn.cc:123
SQUIDCEXTERN int squid_max_keylen
Definition: Asn.cc:187
static int asnAddNet(const SBuf &, int)
Definition: Asn.cc:331
void asnAclInitialize(ACL *acls)
static void asnRegisterWithCacheManager(void)
Definition: Asn.cc:180
static void destroyRadixNodeInfo(as_info *)
Definition: Asn.cc:426
struct squid_radix_node_head * AS_tree_head
Definition: Asn.cc:49
static void asnCacheStart(int as)
Definition: Asn.cc:223
#define Assure(condition)
Definition: Assure.h:35
ACLFilledChecklist * Filled(ACLChecklist *checklist)
convenience and safety wrapper for dynamic_cast<ACLFilledChecklist*>
class SquidConfig Config
Definition: SquidConfig.cc:12
void(void *, StoreIOBuffer) STCB
Definition: StoreClient.h:32
#define assert(EX)
Definition: assert.h:17
int cbdata_type
Definition: cbdata.h:195
CbDataList< int > * data
Definition: Asn.h:40
void prepareForUse() override
Definition: Asn.cc:172
SBufList dump() const override
Definition: Asn.cc:481
~ACLASN() override
Definition: Asn.cc:467
void parse() override
Definition: Asn.cc:504
bool match(Ip::Address) override
Definition: Asn.cc:475
bool empty() const override
Definition: Asn.cc:498
Definition: Acl.h:46
Definition: Asn.cc:68
~ASState()
Definition: Asn.cc:74
HttpRequest::Pointer request
Definition: Asn.cc:85
StoreEntry * entry
Definition: Asn.cc:83
store_client * sc
Definition: Asn.cc:84
int as_number
Definition: Asn.cc:86
CBDATA_CLASS(ASState)
ASState()=default
Store::ParsingBuffer parsingBuffer
for receiving a WHOIS reply body from Store and interpreting it
Definition: Asn.cc:89
int match(ACLChecklist *) override
Matches the actual data in checklist against this ACL.
Definition: Asn.cc:528
int match(ACLChecklist *) override
Matches the actual data in checklist against this ACL.
Definition: Asn.cc:520
Definition: Uri.h:31
void path(const char *p)
Definition: Uri.h:101
void defaultPort()
reset the port to the default port number for the current scheme
Definition: Uri.h:99
SBuf & absolute() const
Definition: Uri.cc:668
void host(const char *src)
Definition: Uri.cc:100
bool find(C const &) const
Definition: CbDataList.h:110
CbDataList * next
Definition: CbDataList.h:31
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:18
CharacterSet complement(const char *complementLabel=nullptr) const
Definition: CharacterSet.cc:74
static char * strtokFile()
Definition: ConfigParser.cc:65
static DestinationIPLookup * Instance()
IpsSelector< IpsIterator > goodAndBad() const
all IPs
Definition: ipcache.h:249
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:412
Http::StatusLine sline
Definition: HttpReply.h:56
HttpRequestMethod method
Definition: HttpRequest.h:114
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:792
bool isNoAddr() const
Definition: Address.cc:284
bool isAnyAddr() const
Definition: Address.cc:170
void setNoAddr()
Definition: Address.cc:292
int applyMask(const Address &mask)
Definition: Address.cc:87
int cidr() const
Definition: Address.cc:44
const HttpReply & baseReply() const
Definition: MemObject.h:60
C * getRaw() const
Definition: RefCount.h:89
Definition: SBuf.h:94
static const size_type npos
Definition: SBuf.h:99
const char * c_str()
Definition: SBuf.cc:516
SBuf & appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:229
SBuf & Printf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:214
size_type find(char c, size_type startPos=0) const
Definition: SBuf.cc:584
char * as_whois_server
Definition: SquidConfig.h:181
uint16_t flags
Definition: Store.h:232
MemObject & mem()
Definition: Store.h:51
unsigned error
Definition: StoreIOBuffer.h:55
int64_t offset
Definition: StoreIOBuffer.h:58
struct StoreIOBuffer::@141 flags
StoreIOBuffer & positionAt(const int64_t newOffset)
convenience method for changing the offset of a being-configured buffer
Definition: StoreIOBuffer.h:47
void consume(size_t)
get rid of previously appended() prefix of a given size
size_t contentSize() const
the total number of append()ed bytes that were not consume()d
StoreIOBuffer space()
StoreIOBuffer content() const
StoreIOBuffer makeInitialSpace()
Definition: ParsingBuffer.h:84
void appended(const char *, size_t)
remember the new bytes received into the previously provided space()
Definition: Asn.cc:37
Ip::Address addr
Definition: Asn.cc:40
uint8_t len
Definition: Asn.cc:39
m_ADDR()
Definition: Asn.cc:42
bool atEof() const
Definition: StoreClient.h:109
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define IP_LOOKUP_IF_MISS
Definition: defines.h:39
#define EBIT_TEST(flag, bit)
Definition: defines.h:69
@ ENTRY_ABORTED
Definition: enums.h:115
void asnFreeMemory(void)
Definition: Asn.cc:206
void asnInit(void)
Definition: Asn.cc:190
const char * AclMatchedName
Definition: Acl.cc:29
const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags)
Definition: ipcache.cc:728
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
void OBJH(StoreEntry *)
Definition: forward.h:44
@ PROTO_WHOIS
Definition: ProtocolType.h:36
@ scOkay
Definition: StatusCode.h:26
@ METHOD_GET
Definition: MethodType.h:25
Definition: Xaction.cc:139
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
#define xfree
#define xstrdup
#define xmalloc
SQUIDCEXTERN struct squid_radix_node * squid_rn_lookup(void *, void *, struct squid_radix_node_head *)
Definition: radix.c:206
SQUIDCEXTERN struct squid_radix_node * squid_rn_delete(void *, void *, struct squid_radix_node_head *)
Definition: radix.c:664
SQUIDCEXTERN struct squid_radix_node * squid_rn_match(void *, struct squid_radix_node_head *)
Definition: radix.c:244
SQUIDCEXTERN int squid_rn_inithead(struct squid_radix_node_head **, int)
Definition: radix.c:853
SQUIDCEXTERN int squid_rn_walktree(struct squid_radix_node_head *, int(*)(struct squid_radix_node *, void *), void *)
Definition: radix.c:817
SQUIDCEXTERN struct squid_radix_node * squid_rn_addroute(void *, void *, struct squid_radix_node_head *, struct squid_radix_node[2])
Definition: radix.c:519
#define RNF_ROOT
Definition: radix.h:60
SQUIDCEXTERN void squid_rn_init(void)
Definition: radix.c:883
std::list< SBuf > SBufList
Definition: forward.h:23
static int sc[16]
Definition: smbdes.c:121
#define SQUIDCEXTERN
Definition: squid.h:21
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:841
StoreEntry * storeCreateEntry(const char *url, const char *logUrl, const RequestFlags &flags, const HttpRequestMethod &method)
Definition: store.cc:745
StoreEntry * storeGetPublic(const char *uri, const HttpRequestMethod &method)
Definition: store.cc:490
int storeUnregister(store_client *sc, StoreEntry *e, void *data)
void storeClientCopy(store_client *sc, StoreEntry *e, StoreIOBuffer copyInto, STCB *callback, void *data)
store_client * storeClientListAdd(StoreEntry *e, void *data)
Definition: Asn.cc:62
CbDataList< int > * as_number
Definition: Asn.cc:63
time_t expires
Definition: Asn.cc:64
Definition: Asn.cc:95
m_ADDR e_addr
Definition: Asn.cc:98
as_info * e_info
Definition: Asn.cc:97
struct squid_radix_node e_nodes[2]
Definition: Asn.cc:96
m_ADDR e_mask
Definition: Asn.cc:99
unsigned char rn_flags
Definition: radix.h:58
Definition: parse.c:160
int token
Definition: parse.c:163
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors