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/Checklist.h"
15#include "acl/DestinationAsn.h"
16#include "acl/DestinationIp.h"
17#include "acl/SourceAsn.h"
18#include "acl/Strategised.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 "radix.h"
26#include "RequestFlags.h"
27#include "SquidConfig.h"
28#include "Store.h"
29#include "StoreClient.h"
30
31#ifndef AS_REQBUF_SZ
32#define AS_REQBUF_SZ 4096
33#endif
34
35/* BEGIN of definitions for radix tree entries */
36
37/* 32/128 bits address in memory with length */
38class m_ADDR
39{
40public:
41 uint8_t len;
43
44 m_ADDR() : len(sizeof(Ip::Address)) {};
45};
46
47/* END of definitions for radix tree entries */
48
49/* Head for ip to asn radix tree */
50
52
53/* explicit instantiation required for some systems */
54
58
64struct as_info {
66 time_t expires; /* NOTUSED */
67};
68
70{
72
73public:
75 memset(reqbuf, 0, sizeof(reqbuf));
76 }
78 if (entry) {
79 debugs(53, 3, entry->url());
80 storeUnregister(sc, entry, this);
81 entry->unlock("~ASState");
82 }
83 }
84
85public:
86 StoreEntry *entry = nullptr;
87 store_client *sc = nullptr;
89 int as_number = 0;
90 int64_t offset = 0;
91 int reqofs = 0;
92 char reqbuf[AS_REQBUF_SZ];
93 bool dataRead = false;
94};
95
97
99struct rtentry_t {
100 struct squid_radix_node e_nodes[2];
104};
105
106static int asnAddNet(char *, int);
107
108static void asnCacheStart(int as);
109
111
112#if defined(__cplusplus)
113extern "C" {
114#endif
115
116static int destroyRadixNode(struct squid_radix_node *rn, void *w);
117static int printRadixNode(struct squid_radix_node *rn, void *sentry);
118
119#if defined(__cplusplus)
120}
121#endif
122
124
125static void destroyRadixNodeInfo(as_info *);
126
128
129/* PUBLIC */
130
131int
133{
134 struct squid_radix_node *rn;
135 as_info *e;
136 m_ADDR m_addr;
137 CbDataList<int> *a = nullptr;
138 CbDataList<int> *b = nullptr;
139
140 debugs(53, 3, "asnMatchIp: Called for " << addr );
141
142 if (AS_tree_head == nullptr)
143 return 0;
144
145 if (addr.isNoAddr())
146 return 0;
147
148 if (addr.isAnyAddr())
149 return 0;
150
151 m_addr.addr = addr;
152
153 rn = squid_rn_match(&m_addr, AS_tree_head);
154
155 if (rn == nullptr) {
156 debugs(53, 3, "asnMatchIp: Address not in as db.");
157 return 0;
158 }
159
160 debugs(53, 3, "asnMatchIp: Found in db!");
161 e = ((rtentry_t *) rn)->e_info;
162 assert(e);
163
164 for (a = data; a; a = a->next)
165 for (b = e->as_number; b; b = b->next)
166 if (a->element == b->element) {
167 debugs(53, 5, "asnMatchIp: Found a match!");
168 return 1;
169 }
170
171 debugs(53, 5, "asnMatchIp: AS not in as db.");
172 return 0;
173}
174
175void
177{
178 for (CbDataList<int> *i = data; i; i = i->
179 next)
180 asnCacheStart(i->element);
181}
182
183static void
185{
186 Mgr::RegisterAction("asndb", "AS Number Database", asnStats, 0, 1);
187}
188
189/* initialize the radix tree structure */
190
191SQUIDCEXTERN int squid_max_keylen; /* yuck.. this is in lib/radix.c */
192
193void
195{
196 static bool inited = false;
197 squid_max_keylen = 40;
198
199 if (!inited) {
200 inited = true;
202 }
203
205
207}
208
209void
211{
213
214 destroyRadixNode((struct squid_radix_node *) nullptr, (void *) AS_tree_head);
215}
216
217static void
219{
220 storeAppendPrintf(sentry, "Address \tAS Numbers\n");
222}
223
224/* PRIVATE */
225
226static void
228{
230 whoisUrl.host(Config.as_whois_server);
231 whoisUrl.defaultPort();
232
233 SBuf asPath("/!gAS");
234 asPath.appendf("%d", as);
235 whoisUrl.path(asPath);
236
237 debugs(53, 3, "AS " << as);
238 ASState *asState = new ASState;
239 asState->as_number = as;
240 const auto mx = MasterXaction::MakePortless<XactionInitiator::initAsn>();
241 asState->request = new HttpRequest(mx);
242 asState->request->url = whoisUrl;
243 asState->request->method = Http::METHOD_GET;
244
245 // XXX: performance regression, c_str() reallocates
246 const auto asres = xstrdup(whoisUrl.absolute().c_str());
247
248 // XXX: Missing a hittingRequiresCollapsing() && startCollapsingOn() check.
249 auto e = storeGetPublic(asres, Http::METHOD_GET);
250 if (!e) {
251 e = storeCreateEntry(asres, asres, RequestFlags(), Http::METHOD_GET);
252 asState->sc = storeClientListAdd(e, asState);
254 } else {
255 e->lock("Asn");
256 asState->sc = storeClientListAdd(e, asState);
257 }
258 xfree(asres);
259
260 asState->entry = e;
261 StoreIOBuffer readBuffer (AS_REQBUF_SZ, asState->offset, asState->reqbuf);
262 storeClientCopy(asState->sc, e, readBuffer, asHandleReply, asState);
263}
264
265static void
266asHandleReply(void *data, StoreIOBuffer result)
267{
268 ASState *asState = (ASState *)data;
269 StoreEntry *e = asState->entry;
270 char *s;
271 char *t;
272 char *buf = asState->reqbuf;
273 int leftoversz = -1;
274
275 debugs(53, 3, "asHandleReply: Called with size=" << (unsigned int)result.length);
276 debugs(53, 3, "asHandleReply: buffer='" << buf << "'");
277
278 /* First figure out whether we should abort the request */
279
280 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
281 delete asState;
282 return;
283 }
284
285 if (result.length == 0 && asState->dataRead) {
286 debugs(53, 3, "asHandleReply: Done: " << e->url());
287 delete asState;
288 return;
289 } else if (result.flags.error) {
290 debugs(53, DBG_IMPORTANT, "ERROR: asHandleReply: Called with Error set and size=" << (unsigned int) result.length);
291 delete asState;
292 return;
293 } else if (e->mem().baseReply().sline.status() != Http::scOkay) {
294 debugs(53, DBG_IMPORTANT, "WARNING: AS " << asState->as_number << " whois request failed");
295 delete asState;
296 return;
297 }
298
299 /*
300 * Next, attempt to parse our request
301 * Remembering that the actual buffer size is retsize + reqofs!
302 */
303 s = buf;
304
305 while ((size_t)(s - buf) < result.length + asState->reqofs && *s != '\0') {
306 while (*s && xisspace(*s))
307 ++s;
308
309 for (t = s; *t; ++t) {
310 if (xisspace(*t))
311 break;
312 }
313
314 if (*t == '\0') {
315 /* oof, word should continue on next block */
316 break;
317 }
318
319 *t = '\0';
320 debugs(53, 3, "asHandleReply: AS# " << s << " (" << asState->as_number << ")");
321 asnAddNet(s, asState->as_number);
322 s = t + 1;
323 asState->dataRead = true;
324 }
325
326 /*
327 * Next, grab the end of the 'valid data' in the buffer, and figure
328 * out how much data is left in our buffer, which we need to keep
329 * around for the next request
330 */
331 leftoversz = (asState->reqofs + result.length) - (s - buf);
332
333 assert(leftoversz >= 0);
334
335 /*
336 * Next, copy the left over data, from s to s + leftoversz to the
337 * beginning of the buffer
338 */
339 memmove(buf, s, leftoversz);
340
341 /*
342 * Next, update our offset and reqofs, and kick off a copy if required
343 */
344 asState->offset += result.length;
345
346 asState->reqofs = leftoversz;
347
348 debugs(53, 3, "asState->offset = " << asState->offset);
349
350 if (e->store_status == STORE_PENDING) {
351 debugs(53, 3, "asHandleReply: store_status == STORE_PENDING: " << e->url() );
352 StoreIOBuffer tempBuffer (AS_REQBUF_SZ - asState->reqofs,
353 asState->offset,
354 asState->reqbuf + asState->reqofs);
355 storeClientCopy(asState->sc,
356 e,
357 tempBuffer,
359 asState);
360 } else {
361 StoreIOBuffer tempBuffer;
362 debugs(53, 3, "asHandleReply: store complete, but data received " << e->url() );
363 tempBuffer.offset = asState->offset;
364 tempBuffer.length = AS_REQBUF_SZ - asState->reqofs;
365 tempBuffer.data = asState->reqbuf + asState->reqofs;
366 storeClientCopy(asState->sc,
367 e,
368 tempBuffer,
370 asState);
371 }
372}
373
377static int
378asnAddNet(char *as_string, int as_number)
379{
380 struct squid_radix_node *rn;
381 CbDataList<int> **Tail = nullptr;
382 CbDataList<int> *q = nullptr;
383 as_info *asinfo = nullptr;
384
385 Ip::Address mask;
386 Ip::Address addr;
387 char *t;
388 int bitl;
389
390 t = strchr(as_string, '/');
391
392 if (t == nullptr) {
393 debugs(53, 3, "asnAddNet: failed, invalid response from whois server.");
394 return 0;
395 }
396
397 *t = '\0';
398 addr = as_string;
399 bitl = atoi(t + 1);
400
401 if (bitl < 0)
402 bitl = 0;
403
404 // INET6 TODO : find a better way of identifying the base IPA family for mask than this.
405 t = strchr(as_string, '.');
406
407 // generate Netbits Format Mask
408 mask.setNoAddr();
409 mask.applyMask(bitl, (t!=nullptr?AF_INET:AF_INET6) );
410
411 debugs(53, 3, "asnAddNet: called for " << addr << "/" << mask );
412
413 rtentry_t *e = (rtentry_t *)xcalloc(1, sizeof(rtentry_t));
414
415 e->e_addr.addr = addr;
416
417 e->e_mask.addr = mask;
418
420
421 if (rn != nullptr) {
422 asinfo = ((rtentry_t *) rn)->e_info;
423
424 if (asinfo->as_number->find(as_number)) {
425 debugs(53, 3, "asnAddNet: Ignoring repeated network '" << addr << "/" << bitl << "' for AS " << as_number);
426 } else {
427 debugs(53, 3, "asnAddNet: Warning: Found a network with multiple AS numbers!");
428
429 for (Tail = &asinfo->as_number; *Tail; Tail = &(*Tail)->next);
430 q = new CbDataList<int> (as_number);
431
432 *(Tail) = q;
433
434 e->e_info = asinfo;
435 }
436 } else {
437 q = new CbDataList<int> (as_number);
438 asinfo = (as_info *)xmalloc(sizeof(as_info));
439 asinfo->as_number = q;
442 assert(rn != nullptr);
443 e->e_info = asinfo;
444 }
445
446 if (rn == nullptr) { /* assert might expand to nothing */
447 xfree(asinfo);
448 delete q;
449 xfree(e);
450 debugs(53, 3, "asnAddNet: Could not add entry.");
451 return 0;
452 }
453
454 e->e_info = asinfo;
455 return 1;
456}
457
458static int
460{
461
462 struct squid_radix_node_head *rnh = (struct squid_radix_node_head *) w;
463
464 if (rn && !(rn->rn_flags & RNF_ROOT)) {
465 rtentry_t *e = (rtentry_t *) rn;
466 rn = squid_rn_delete(rn->rn_key, rn->rn_mask, rnh);
467
468 if (rn == nullptr)
469 debugs(53, 3, "destroyRadixNode: internal screwup");
470
472
473 xfree(rn);
474 }
475
476 return 1;
477}
478
479static void
481{
482 CbDataList<int> *prev = nullptr;
483 CbDataList<int> *data = e_info->as_number;
484
485 while (data) {
486 prev = data;
487 data = data->next;
488 delete prev;
489 }
490}
491
492static int
493printRadixNode(struct squid_radix_node *rn, void *_sentry)
494{
495 StoreEntry *sentry = (StoreEntry *)_sentry;
496 rtentry_t *e = (rtentry_t *) rn;
498 as_info *asinfo;
499 char buf[MAX_IPSTRLEN];
500 Ip::Address addr;
501 Ip::Address mask;
502
503 assert(e);
504 assert(e->e_info);
505 addr = e->e_addr.addr;
506 mask = e->e_mask.addr;
507 storeAppendPrintf(sentry, "%s/%d\t",
508 addr.toStr(buf, MAX_IPSTRLEN),
509 mask.cidr() );
510 asinfo = e->e_info;
511 assert(asinfo->as_number);
512
513 for (q = asinfo->as_number; q; q = q->next)
514 storeAppendPrintf(sentry, " %d", q->element);
515
516 storeAppendPrintf(sentry, "\n");
517
518 return 0;
519}
520
522{
523 if (data)
524 delete data;
525}
526
527bool
528
530{
531 return asnMatchIp(data, toMatch);
532}
533
536{
537 SBufList sl;
538
539 CbDataList<int> *ldata = data;
540
541 while (ldata != nullptr) {
542 SBuf s;
543 s.Printf("%d", ldata->element);
544 sl.push_back(s);
545 ldata = ldata->next;
546 }
547
548 return sl;
549}
550
551bool
553{
554 return data == nullptr;
555}
556
557void
559{
560 CbDataList<int> **curlist = &data;
561 CbDataList<int> **Tail;
562 CbDataList<int> *q = nullptr;
563 char *t = nullptr;
564
565 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
566 while ((t = ConfigParser::strtokFile())) {
567 q = new CbDataList<int> (atoi(t));
568 *(Tail) = q;
569 Tail = &q->next;
570 }
571}
572
573/* explicit template instantiation required for some systems */
574
575template class ACLStrategised<Ip::Address>;
576
577int
579{
580 return data->match(checklist->src_addr);
581}
582
583int
585{
587
588 if (ia) {
589 for (const auto &ip: ia->goodAndBad()) {
590 if (data->match(ip))
591 return 1;
592 }
593
594 return 0;
595
596 } else if (!checklist->request->flags.destinationIpLookedUp) {
597 /* No entry in cache, lookup not attempted */
598 debugs(28, 3, "can't yet compare '" << AclMatchedName << "' ACL for " << checklist->request->url.host());
599 if (checklist->goAsync(DestinationIPLookup::Instance()))
600 return -1;
601 // else fall through to noaddr match, hiding the lookup failure (XXX)
602 }
603 Ip::Address noaddr;
604 noaddr.setNoAddr();
605 return data->match(noaddr);
606}
607
static int asnAddNet(char *, int)
Definition: Asn.cc:378
CBDATA_CLASS_INIT(ASState)
static STCB asHandleReply
Definition: Asn.cc:110
static int printRadixNode(struct squid_radix_node *rn, void *sentry)
Definition: Asn.cc:493
static int destroyRadixNode(struct squid_radix_node *rn, void *w)
Definition: Asn.cc:459
int asnMatchIp(CbDataList< int > *data, Ip::Address &addr)
Definition: Asn.cc:132
static OBJH asnStats
Definition: Asn.cc:127
SQUIDCEXTERN int squid_max_keylen
Definition: Asn.cc:191
#define AS_REQBUF_SZ
Definition: Asn.cc:32
void asnAclInitialize(ACL *acls)
static void asnRegisterWithCacheManager(void)
Definition: Asn.cc:184
static void destroyRadixNodeInfo(as_info *)
Definition: Asn.cc:480
struct squid_radix_node_head * AS_tree_head
Definition: Asn.cc:51
static void asnCacheStart(int as)
Definition: Asn.cc:227
class SquidConfig Config
Definition: SquidConfig.cc:12
void STCB(void *, StoreIOBuffer)
Definition: StoreClient.h:19
#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:176
SBufList dump() const override
Definition: Asn.cc:535
~ACLASN() override
Definition: Asn.cc:521
void parse() override
Definition: Asn.cc:558
bool match(Ip::Address) override
Definition: Asn.cc:529
bool empty() const override
Definition: Asn.cc:552
bool goAsync(AsyncState *)
Definition: Checklist.cc:114
virtual bool match(M)=0
int match(ACLData< MatchType > *&, ACLFilledChecklist *) override
Definition: Asn.cc:584
HttpRequest * request
Ip::Address src_addr
int match(ACLData< MatchType > *&, ACLFilledChecklist *) override
Definition: Asn.cc:578
Definition: Acl.h:46
Definition: Asn.cc:70
~ASState()
Definition: Asn.cc:77
HttpRequest::Pointer request
Definition: Asn.cc:88
int reqofs
Definition: Asn.cc:91
StoreEntry * entry
Definition: Asn.cc:86
char reqbuf[AS_REQBUF_SZ]
Definition: Asn.cc:92
store_client * sc
Definition: Asn.cc:87
int as_number
Definition: Asn.cc:89
CBDATA_CLASS(ASState)
bool dataRead
Definition: Asn.cc:93
ASState()
Definition: Asn.cc:74
int64_t offset
Definition: Asn.cc:90
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:592
void host(const char *src)
Definition: Uri.cc:99
bool find(C const &) const
Definition: CbDataList.h:110
CbDataList * next
Definition: CbDataList.h:31
static char * strtokFile()
Definition: ConfigParser.cc:65
static DestinationIPLookup * Instance()
IpsSelector< IpsIterator > goodAndBad() const
all IPs
Definition: ipcache.h:248
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:418
Http::StatusLine sline
Definition: HttpReply.h:56
HttpRequestMethod method
Definition: HttpRequest.h:114
RequestFlags flags
Definition: HttpRequest.h:141
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:59
C * getRaw() const
Definition: RefCount.h:80
bool destinationIpLookedUp
Definition: RequestFlags.h:108
Definition: SBuf.h:94
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
char * as_whois_server
Definition: SquidConfig.h:179
uint16_t flags
Definition: Store.h:232
MemObject & mem()
Definition: Store.h:51
const char * url() const
Definition: store.cc:1534
store_status_t store_status
Definition: Store.h:244
unsigned error
Definition: StoreIOBuffer.h:52
int64_t offset
Definition: StoreIOBuffer.h:55
struct StoreIOBuffer::@142 flags
Definition: Asn.cc:39
Ip::Address addr
Definition: Asn.cc:42
uint8_t len
Definition: Asn.cc:41
m_ADDR()
Definition: Asn.cc:44
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:193
#define IP_LOOKUP_IF_MISS
Definition: defines.h:39
#define EBIT_TEST(flag, bit)
Definition: defines.h:69
@ ENTRY_ABORTED
Definition: enums.h:115
@ STORE_PENDING
Definition: enums.h:51
void asnFreeMemory(void)
Definition: Asn.cc:210
void asnInit(void)
Definition: Asn.cc:194
const char * AclMatchedName
Definition: Acl.cc:29
const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags)
Definition: ipcache.cc:719
#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:37
@ 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:207
SQUIDCEXTERN struct squid_radix_node * squid_rn_delete(void *, void *, struct squid_radix_node_head *)
Definition: radix.c:665
SQUIDCEXTERN struct squid_radix_node * squid_rn_match(void *, struct squid_radix_node_head *)
Definition: radix.c:245
SQUIDCEXTERN int squid_rn_inithead(struct squid_radix_node_head **, int)
Definition: radix.c:854
SQUIDCEXTERN int squid_rn_walktree(struct squid_radix_node_head *, int(*)(struct squid_radix_node *, void *), void *)
Definition: radix.c:818
SQUIDCEXTERN struct squid_radix_node * squid_rn_addroute(void *, void *, struct squid_radix_node_head *, struct squid_radix_node[2])
Definition: radix.c:520
#define RNF_ROOT
Definition: radix.h:60
SQUIDCEXTERN void squid_rn_init(void)
Definition: radix.c:884
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:829
StoreEntry * storeCreateEntry(const char *url, const char *logUrl, const RequestFlags &flags, const HttpRequestMethod &method)
Definition: store.cc:733
StoreEntry * storeGetPublic(const char *uri, const HttpRequestMethod &method)
Definition: store.cc:478
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:64
CbDataList< int > * as_number
Definition: Asn.cc:65
time_t expires
Definition: Asn.cc:66
Definition: Asn.cc:99
m_ADDR e_addr
Definition: Asn.cc:102
as_info * e_info
Definition: Asn.cc:101
struct squid_radix_node e_nodes[2]
Definition: Asn.cc:100
m_ADDR e_mask
Definition: Asn.cc:103
unsigned char rn_flags
Definition: radix.h:58
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
#define xisspace(x)
Definition: xis.h:17

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors