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