]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2021 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 28 Access Control */ | |
10 | ||
11 | #include "squid.h" | |
12 | #include "acl/Checklist.h" | |
13 | #include "acl/Ip.h" | |
14 | #include "cache_cf.h" | |
15 | #include "ConfigParser.h" | |
16 | #include "Debug.h" | |
17 | #include "ip/tools.h" | |
18 | #include "MemBuf.h" | |
19 | #include "wordlist.h" | |
20 | ||
21 | void * | |
22 | ACLIP::operator new (size_t) | |
23 | { | |
24 | fatal ("ACLIP::operator new: unused"); | |
25 | return (void *)1; | |
26 | } | |
27 | ||
28 | void | |
29 | ACLIP::operator delete (void *) | |
30 | { | |
31 | fatal ("ACLIP::operator delete: unused"); | |
32 | } | |
33 | ||
34 | /** | |
35 | * print/format an acl_ip_data structure for debugging output. | |
36 | * | |
37 | \param buf string buffer to write to | |
38 | \param len size of the buffer available | |
39 | */ | |
40 | void | |
41 | acl_ip_data::toStr(char *buf, int len) const | |
42 | { | |
43 | char *b1 = buf; | |
44 | char *b2 = NULL; | |
45 | char *b3 = NULL; | |
46 | int rlen = 0; | |
47 | ||
48 | addr1.toStr(b1, len - rlen ); | |
49 | rlen = strlen(buf); | |
50 | b2 = buf + rlen; | |
51 | ||
52 | if (!addr2.isAnyAddr()) { | |
53 | b2[0] = '-'; | |
54 | ++rlen; | |
55 | addr2.toStr(&(b2[1]), len - rlen ); | |
56 | rlen = strlen(buf); | |
57 | } else | |
58 | b2[0] = '\0'; | |
59 | ||
60 | b3 = buf + rlen; | |
61 | ||
62 | if (!mask.isNoAddr()) { | |
63 | b3[0] = '/'; | |
64 | ++rlen; | |
65 | int cidr = mask.cidr() - (addr1.isIPv4()?96:0); | |
66 | snprintf(&(b3[1]), (len-rlen), "%u", (unsigned int)(cidr<0?0:cidr) ); | |
67 | } else | |
68 | b3[0] = '\0'; | |
69 | } | |
70 | ||
71 | SBuf | |
72 | acl_ip_data::toSBuf() const | |
73 | { | |
74 | const int bufsz = MAX_IPSTRLEN*2+6; | |
75 | static char tmpbuf[ bufsz ]; | |
76 | toStr(tmpbuf,bufsz); | |
77 | return SBuf(tmpbuf); | |
78 | } | |
79 | ||
80 | /* | |
81 | * aclIpAddrNetworkCompare - The guts of the comparison for IP ACLs | |
82 | * matching checks. The first argument (p) is a "host" address, | |
83 | * i.e. the IP address of a cache client. The second argument (q) | |
84 | * is an entry in some address-based access control element. This | |
85 | * function is called via ACLIP::match() and the splay library. | |
86 | */ | |
87 | int | |
88 | aclIpAddrNetworkCompare(acl_ip_data * const &p, acl_ip_data * const &q) | |
89 | { | |
90 | Ip::Address A = p->addr1; | |
91 | ||
92 | /* apply netmask */ | |
93 | A.applyMask(q->mask); | |
94 | ||
95 | debugs(28,9, "aclIpAddrNetworkCompare: compare: " << p->addr1 << "/" << q->mask << " (" << A << ") vs " << | |
96 | q->addr1 << "-" << q->addr2 << "/" << q->mask); | |
97 | ||
98 | if (q->addr2.isAnyAddr()) { /* single address check */ | |
99 | ||
100 | return A.matchIPAddr( q->addr1 ); | |
101 | ||
102 | } else { /* range address check */ | |
103 | ||
104 | if ( (A >= q->addr1) && (A <= q->addr2) ) | |
105 | return 0; /* valid. inside range. */ | |
106 | else | |
107 | return A.matchIPAddr( q->addr1 ); /* outside of range, 'less than' */ | |
108 | } | |
109 | } | |
110 | ||
111 | /* | |
112 | * acl_ip_data::NetworkCompare - Compare two acl_ip_data entries. Strictly | |
113 | * used by the splay insertion routine. It emits a warning if it | |
114 | * detects a "collision" or overlap that would confuse the splay | |
115 | * sorting algorithm. Much like aclDomainCompare. | |
116 | * The first argument (p) is a "host" address, i.e. the IP address of a cache client. | |
117 | * The second argument (b) is a "network" address that might have a subnet and/or range. | |
118 | * We mask the host address bits with the network subnet mask. | |
119 | */ | |
120 | int | |
121 | acl_ip_data::NetworkCompare(acl_ip_data * const & a, acl_ip_data * const &b) | |
122 | { | |
123 | int ret; | |
124 | bool bina = true; | |
125 | ret = aclIpAddrNetworkCompare(b, a); | |
126 | ||
127 | if (ret != 0) { | |
128 | bina = false; | |
129 | ret = aclIpAddrNetworkCompare(a, b); | |
130 | } | |
131 | ||
132 | if (ret == 0) { | |
133 | char buf_n1[3*(MAX_IPSTRLEN+1)]; | |
134 | char buf_n2[3*(MAX_IPSTRLEN+1)]; | |
135 | if (bina) { | |
136 | b->toStr(buf_n1, 3*(MAX_IPSTRLEN+1)); | |
137 | a->toStr(buf_n2, 3*(MAX_IPSTRLEN+1)); | |
138 | } else { | |
139 | a->toStr(buf_n1, 3*(MAX_IPSTRLEN+1)); | |
140 | b->toStr(buf_n2, 3*(MAX_IPSTRLEN+1)); | |
141 | } | |
142 | debugs(28, DBG_CRITICAL, "WARNING: (" << (bina?'B':'A') << ") '" << buf_n1 << "' is a subnetwork of (" << (bina?'A':'B') << ") '" << buf_n2 << "'"); | |
143 | debugs(28, DBG_CRITICAL, "WARNING: because of this '" << (bina?buf_n2:buf_n1) << "' is ignored to keep splay tree searching predictable"); | |
144 | debugs(28, DBG_CRITICAL, "WARNING: You should probably remove '" << buf_n1 << "' from the ACL named '" << AclMatchedName << "'"); | |
145 | } | |
146 | ||
147 | return ret; | |
148 | } | |
149 | ||
150 | /** | |
151 | * Decode an ascii representation (asc) of a IP netmask address or CIDR, | |
152 | * and place resulting information in mask. | |
153 | * This function should NOT be called if 'asc' is a hostname! | |
154 | */ | |
155 | bool | |
156 | acl_ip_data::DecodeMask(const char *asc, Ip::Address &mask, int ctype) | |
157 | { | |
158 | char junk; | |
159 | int a1 = 0; | |
160 | ||
161 | /* default is a mask that doesn't change any IP */ | |
162 | mask.setNoAddr(); | |
163 | ||
164 | if (!asc || !*asc) { | |
165 | return true; | |
166 | } | |
167 | ||
168 | /* An int mask 128, 32 */ | |
169 | if ((sscanf(asc, "%d%c", &a1, &junk)==1) && | |
170 | (a1 <= 128) && (a1 >= 0) | |
171 | ) { | |
172 | return mask.applyMask(a1, ctype); | |
173 | } | |
174 | ||
175 | /* dotted notation */ | |
176 | /* assignment returns true if asc contained an IP address as text */ | |
177 | if ((mask = asc)) { | |
178 | /* HACK: IPv4 netmasks don't cleanly map to IPv6 masks. */ | |
179 | debugs(28, DBG_CRITICAL, "WARNING: Netmasks are deprecated. Please use CIDR masks instead."); | |
180 | if (mask.isIPv4()) { | |
181 | /* locate what CIDR mask was _probably_ meant to be in its native protocol format. */ | |
182 | /* this will completely crap out with a security fail-open if the admin is playing mask tricks */ | |
183 | /* however, that's their fault, and we do warn. see bug 2601 for the effects if we don't do this. */ | |
184 | unsigned int m = mask.cidr(); | |
185 | debugs(28, DBG_CRITICAL, "WARNING: IPv4 netmasks are particularly nasty when used to compare IPv6 to IPv4 ranges."); | |
186 | debugs(28, DBG_CRITICAL, "WARNING: For now we will assume you meant to write /" << m); | |
187 | /* reset the mask completely, and crop to the CIDR boundary back properly. */ | |
188 | mask.setNoAddr(); | |
189 | return mask.applyMask(m,AF_INET); | |
190 | } | |
191 | return true; | |
192 | } | |
193 | ||
194 | return false; | |
195 | } | |
196 | ||
197 | /* Handle either type of address, IPv6 will be discarded with a warning if disabled */ | |
198 | #define SCAN_ACL1_6 "%[0123456789ABCDEFabcdef:]-%[0123456789ABCDEFabcdef:]/%[0123456789]" | |
199 | #define SCAN_ACL2_6 "%[0123456789ABCDEFabcdef:]-%[0123456789ABCDEFabcdef:]%c" | |
200 | #define SCAN_ACL3_6 "%[0123456789ABCDEFabcdef:]/%[0123456789]" | |
201 | #define SCAN_ACL4_6 "%[0123456789ABCDEFabcdef:]/%c" | |
202 | /* We DO need to know which is which though, for proper CIDR masking. */ | |
203 | #define SCAN_ACL1_4 "%[0123456789.]-%[0123456789.]/%[0123456789.]" | |
204 | #define SCAN_ACL2_4 "%[0123456789.]-%[0123456789.]%c" | |
205 | #define SCAN_ACL3_4 "%[0123456789.]/%[0123456789.]" | |
206 | #define SCAN_ACL4_4 "%[0123456789.]/%c" | |
207 | ||
208 | acl_ip_data * | |
209 | acl_ip_data::FactoryParse(const char *t) | |
210 | { | |
211 | LOCAL_ARRAY(char, addr1, 256); | |
212 | LOCAL_ARRAY(char, addr2, 256); | |
213 | LOCAL_ARRAY(char, mask, 256); | |
214 | acl_ip_data *r = NULL; | |
215 | acl_ip_data **Q = NULL; | |
216 | Ip::Address temp; | |
217 | char c; | |
218 | unsigned int changed; | |
219 | acl_ip_data *q = new acl_ip_data; | |
220 | int iptype = AF_UNSPEC; | |
221 | ||
222 | debugs(28, 5, "aclIpParseIpData: " << t); | |
223 | ||
224 | /* Special ACL RHS "all" matches entire Internet */ | |
225 | if (strcmp(t, "all") == 0) { | |
226 | debugs(28, 9, "aclIpParseIpData: magic 'all' found."); | |
227 | q->addr1.setAnyAddr(); | |
228 | q->addr2.setEmpty(); | |
229 | q->mask.setAnyAddr(); | |
230 | return q; | |
231 | } | |
232 | ||
233 | /* Detect some old broken strings equivalent to 'all'. | |
234 | * treat them nicely. But be loud until its fixed. */ | |
235 | if (strcmp(t, "0/0") == 0 || strcmp(t, "0.0.0.0/0") == 0 || strcmp(t, "0.0.0.0/0.0.0.0") == 0 || | |
236 | strcmp(t, "0.0.0.0-255.255.255.255") == 0 || strcmp(t, "0.0.0.0-0.0.0.0/0") == 0) { | |
237 | ||
238 | debugs(28,DBG_CRITICAL, "ERROR: '" << t << "' needs to be replaced by the term 'all'."); | |
239 | debugs(28,DBG_CRITICAL, "SECURITY NOTICE: Overriding config setting. Using 'all' instead."); | |
240 | q->addr1.setAnyAddr(); | |
241 | q->addr2.setEmpty(); | |
242 | q->mask.setAnyAddr(); | |
243 | return q; | |
244 | } | |
245 | ||
246 | /* Special ACL RHS "ipv4" matches IPv4 Internet | |
247 | * A nod to IANA; we include the entire class space in case | |
248 | * they manage to find a way to recover and use it */ | |
249 | if (strcmp(t, "ipv4") == 0) { | |
250 | q->mask.setNoAddr(); | |
251 | q->mask.applyMask(0, AF_INET); | |
252 | return q; | |
253 | } | |
254 | ||
255 | /* Special ACL RHS "ipv6" matches IPv6-Unicast Internet */ | |
256 | if (strcmp(t, "ipv6") == 0) { | |
257 | debugs(28, 9, "aclIpParseIpData: magic 'ipv6' found."); | |
258 | r = q; // save head of the list for result. | |
259 | ||
260 | /* 0000::/4 is a mix of localhost and obsolete IPv4-mapping space. Not valid outside this host. */ | |
261 | ||
262 | /* Future global unicast space: 1000::/4 */ | |
263 | q->addr1 = "1000::"; | |
264 | q->mask.setNoAddr(); | |
265 | q->mask.applyMask(4, AF_INET6); | |
266 | ||
267 | /* Current global unicast space: 2000::/4 = (2000::/4 - 3000::/4) */ | |
268 | q->next = new acl_ip_data; | |
269 | q = q->next; | |
270 | q->addr1 = "2000::"; | |
271 | q->mask.setNoAddr(); | |
272 | q->mask.applyMask(3, AF_INET6); | |
273 | ||
274 | /* Future global unicast space: 4000::/2 = (4000::/4 - 7000::/4) */ | |
275 | q->next = new acl_ip_data; | |
276 | q = q->next; | |
277 | q->addr1 = "4000::"; | |
278 | q->mask.setNoAddr(); | |
279 | q->mask.applyMask(2, AF_INET6); | |
280 | ||
281 | /* Future global unicast space: 8000::/2 = (8000::/4 - B000::/4) */ | |
282 | q->next = new acl_ip_data; | |
283 | q = q->next; | |
284 | q->addr1 = "8000::"; | |
285 | q->mask.setNoAddr(); | |
286 | q->mask.applyMask(2, AF_INET6); | |
287 | ||
288 | /* Future global unicast space: C000::/3 = (C000::/4 - D000::/4) */ | |
289 | q->next = new acl_ip_data; | |
290 | q = q->next; | |
291 | q->addr1 = "C000::"; | |
292 | q->mask.setNoAddr(); | |
293 | q->mask.applyMask(3, AF_INET6); | |
294 | ||
295 | /* Future global unicast space: E000::/4 */ | |
296 | q->next = new acl_ip_data; | |
297 | q = q->next; | |
298 | q->addr1 = "E000::"; | |
299 | q->mask.setNoAddr(); | |
300 | q->mask.applyMask(4, AF_INET6); | |
301 | ||
302 | /* F000::/4 is mostly reserved non-unicast. With some exceptions ... */ | |
303 | ||
304 | /* RFC 4193 Unique-Local unicast space: FC00::/7 */ | |
305 | q->next = new acl_ip_data; | |
306 | q = q->next; | |
307 | q->addr1 = "FC00::"; | |
308 | q->mask.setNoAddr(); | |
309 | q->mask.applyMask(7, AF_INET6); | |
310 | ||
311 | /* Link-Local unicast space: FE80::/10 */ | |
312 | q->next = new acl_ip_data; | |
313 | q = q->next; | |
314 | q->addr1 = "FE80::"; | |
315 | q->mask.setNoAddr(); | |
316 | q->mask.applyMask(10, AF_INET6); | |
317 | ||
318 | return r; | |
319 | } | |
320 | ||
321 | // IPv4 | |
322 | if (sscanf(t, SCAN_ACL1_4, addr1, addr2, mask) == 3) { | |
323 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN1-v4: " << SCAN_ACL1_4); | |
324 | iptype=AF_INET; | |
325 | } else if (sscanf(t, SCAN_ACL2_4, addr1, addr2, &c) >= 2) { | |
326 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN2-v4: " << SCAN_ACL2_4); | |
327 | mask[0] = '\0'; | |
328 | iptype=AF_INET; | |
329 | } else if (sscanf(t, SCAN_ACL3_4, addr1, mask) == 2) { | |
330 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN3-v4: " << SCAN_ACL3_4); | |
331 | addr2[0] = '\0'; | |
332 | iptype=AF_INET; | |
333 | } else if (sscanf(t, SCAN_ACL4_4, addr1,&c) == 2) { | |
334 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN4-v4: " << SCAN_ACL4_4); | |
335 | addr2[0] = '\0'; | |
336 | mask[0] = '\0'; | |
337 | iptype=AF_INET; | |
338 | ||
339 | // IPv6 | |
340 | } else if (sscanf(t, SCAN_ACL1_6, addr1, addr2, mask) == 3) { | |
341 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN1-v6: " << SCAN_ACL1_6); | |
342 | iptype=AF_INET6; | |
343 | } else if (sscanf(t, SCAN_ACL2_6, addr1, addr2, &c) >= 2) { | |
344 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN2-v6: " << SCAN_ACL2_6); | |
345 | mask[0] = '\0'; | |
346 | iptype=AF_INET6; | |
347 | } else if (sscanf(t, SCAN_ACL3_6, addr1, mask) == 2) { | |
348 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN3-v6: " << SCAN_ACL3_6); | |
349 | addr2[0] = '\0'; | |
350 | iptype=AF_INET6; | |
351 | } else if (sscanf(t, SCAN_ACL4_6, addr1, mask) == 2) { | |
352 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN4-v6: " << SCAN_ACL4_6); | |
353 | addr2[0] = '\0'; | |
354 | iptype=AF_INET6; | |
355 | ||
356 | // Neither | |
357 | } else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) { | |
358 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: non-IP pattern: %[^/]/%s"); | |
359 | addr2[0] = '\0'; | |
360 | } else if (sscanf(t, "%s", addr1) == 1) { | |
361 | /* | |
362 | * Note, must use plain getaddrinfo() here because at startup | |
363 | * ipcache hasn't been initialized | |
364 | * TODO: offload this to one of the Ip::Address lookups. | |
365 | */ | |
366 | ||
367 | debugs(28, 5, "aclIpParseIpData: Lookup Host/IP " << addr1); | |
368 | struct addrinfo *hp = NULL, *x = NULL; | |
369 | struct addrinfo hints; | |
370 | Ip::Address *prev_addr = NULL; | |
371 | ||
372 | memset(&hints, 0, sizeof(struct addrinfo)); | |
373 | ||
374 | int errcode = getaddrinfo(addr1,NULL,&hints,&hp); | |
375 | if (hp == NULL) { | |
376 | delete q; | |
377 | if (strcmp(addr1, "::1") == 0) { | |
378 | debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled in host DNS resolver."); | |
379 | } else { | |
380 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << addr1 << | |
381 | "' in '" << t << "', flags=" << hints.ai_flags << | |
382 | " : (" << errcode << ") " << gai_strerror(errcode) ); | |
383 | self_destruct(); | |
384 | } | |
385 | return NULL; | |
386 | } | |
387 | ||
388 | Q = &q; | |
389 | ||
390 | for (x = hp; x != NULL;) { | |
391 | if ((r = *Q) == NULL) | |
392 | r = *Q = new acl_ip_data; | |
393 | ||
394 | /* getaddrinfo given a host has a nasty tendency to return duplicate addr's */ | |
395 | /* BUT sorted fortunately, so we can drop most of them easily */ | |
396 | r->addr1 = *x; | |
397 | x = x->ai_next; | |
398 | if ( prev_addr && r->addr1 == *prev_addr) { | |
399 | debugs(28, 3, "aclIpParseIpData: Duplicate host/IP: '" << r->addr1 << "' dropped."); | |
400 | delete r; | |
401 | *Q = NULL; | |
402 | continue; | |
403 | } else | |
404 | prev_addr = &r->addr1; | |
405 | ||
406 | debugs(28, 3, "aclIpParseIpData: Located host/IP: '" << r->addr1 << "'"); | |
407 | ||
408 | r->addr2.setAnyAddr(); | |
409 | r->mask.setNoAddr(); | |
410 | ||
411 | Q = &r->next; | |
412 | ||
413 | debugs(28, 3, "" << addr1 << " --> " << r->addr1 ); | |
414 | } | |
415 | ||
416 | freeaddrinfo(hp); | |
417 | ||
418 | if (*Q != NULL) { | |
419 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << t << "'"); | |
420 | self_destruct(); | |
421 | return NULL; | |
422 | } | |
423 | ||
424 | return q; | |
425 | } | |
426 | ||
427 | /* ignore IPv6 addresses when built with IPv4-only */ | |
428 | if ( iptype == AF_INET6 && !Ip::EnableIpv6) { | |
429 | debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled."); | |
430 | delete q; | |
431 | return NULL; | |
432 | } | |
433 | ||
434 | /* Decode addr1 */ | |
435 | if (!*addr1 || !(q->addr1 = addr1)) { | |
436 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: unknown first address in '" << t << "'"); | |
437 | delete q; | |
438 | self_destruct(); | |
439 | return NULL; | |
440 | } | |
441 | ||
442 | /* Decode addr2 */ | |
443 | if (!*addr2) | |
444 | q->addr2.setAnyAddr(); | |
445 | else if (!(q->addr2=addr2) ) { | |
446 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: unknown second address in '" << t << "'"); | |
447 | delete q; | |
448 | self_destruct(); | |
449 | return NULL; | |
450 | } | |
451 | ||
452 | /* Decode mask (NULL or empty means a exact host mask) */ | |
453 | if (!DecodeMask(mask, q->mask, iptype)) { | |
454 | debugs(28, DBG_CRITICAL, "aclParseIpData: unknown netmask '" << mask << "' in '" << t << "'"); | |
455 | delete q; | |
456 | self_destruct(); | |
457 | return NULL; | |
458 | } | |
459 | ||
460 | changed = 0; | |
461 | changed += q->addr1.applyMask(q->mask); | |
462 | changed += q->addr2.applyMask(q->mask); | |
463 | ||
464 | if (changed) | |
465 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: WARNING: Netmask masks away part of the specified IP in '" << t << "'"); | |
466 | ||
467 | debugs(28,9, HERE << "Parsed: " << q->addr1 << "-" << q->addr2 << "/" << q->mask << "(/" << q->mask.cidr() <<")"); | |
468 | ||
469 | /* 1.2.3.4/255.255.255.0 --> 1.2.3.0 */ | |
470 | /* Same as IPv6 (not so trivial to depict) */ | |
471 | return q; | |
472 | } | |
473 | ||
474 | void | |
475 | ACLIP::parse() | |
476 | { | |
477 | if (data == NULL) | |
478 | data = new IPSplay(); | |
479 | ||
480 | while (char *t = ConfigParser::strtokFile()) { | |
481 | acl_ip_data *q = acl_ip_data::FactoryParse(t); | |
482 | ||
483 | while (q != NULL) { | |
484 | /* pop each result off the list and add it to the data tree individually */ | |
485 | acl_ip_data *next_node = q->next; | |
486 | q->next = NULL; | |
487 | if (!data->find(q,acl_ip_data::NetworkCompare)) | |
488 | data->insert(q, acl_ip_data::NetworkCompare); | |
489 | q = next_node; | |
490 | } | |
491 | } | |
492 | } | |
493 | ||
494 | ACLIP::~ACLIP() | |
495 | { | |
496 | if (data) { | |
497 | data->destroy(); | |
498 | delete data; | |
499 | } | |
500 | } | |
501 | ||
502 | struct IpAclDumpVisitor { | |
503 | SBufList contents; | |
504 | void operator() (acl_ip_data * const & ip) { | |
505 | contents.push_back(ip->toSBuf()); | |
506 | } | |
507 | }; | |
508 | ||
509 | SBufList | |
510 | ACLIP::dump() const | |
511 | { | |
512 | IpAclDumpVisitor visitor; | |
513 | data->visit(visitor); | |
514 | return visitor.contents; | |
515 | } | |
516 | ||
517 | bool | |
518 | ACLIP::empty() const | |
519 | { | |
520 | return data->empty(); | |
521 | } | |
522 | ||
523 | int | |
524 | ACLIP::match(const Ip::Address &clientip) | |
525 | { | |
526 | static acl_ip_data ClientAddress; | |
527 | /* | |
528 | * aclIpAddrNetworkCompare() takes two acl_ip_data pointers as | |
529 | * arguments, so we must create a fake one for the client's IP | |
530 | * address. Since we are scanning for a single IP mask and addr2 | |
531 | * MUST be set to empty. | |
532 | */ | |
533 | ClientAddress.addr1 = clientip; | |
534 | ClientAddress.addr2.setEmpty(); | |
535 | ClientAddress.mask.setEmpty(); | |
536 | ||
537 | const acl_ip_data * const * result = data->find(&ClientAddress, aclIpAddrNetworkCompare); | |
538 | debugs(28, 3, "aclIpMatchIp: '" << clientip << "' " << (result ? "found" : "NOT found")); | |
539 | return (result != NULL); | |
540 | } | |
541 | ||
542 | acl_ip_data::acl_ip_data() :addr1(), addr2(), mask(), next (NULL) {} | |
543 | ||
544 | acl_ip_data::acl_ip_data(Ip::Address const &anAddress1, Ip::Address const &anAddress2, Ip::Address const &aMask, acl_ip_data *aNext) : addr1(anAddress1), addr2(anAddress2), mask(aMask), next(aNext) {} | |
545 |