~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to src/acl/Ip.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2009-09-24 14:51:06 UTC
  • mfrom: (1.1.12 upstream)
  • mto: (20.2.1 sid)
  • mto: This revision was merged to the branch mainline in revision 21.
  • Revision ID: james.westby@ubuntu.com-20090924145106-38jgrzmj0d73pha5
Tags: 3.1.0.13-1
* Upload to experimental

* New upstream release
  - Fixes Follow-X-Forwarded-For support (Closes: #523943)
  - Adds IPv6 support (Closes: #432351)

* debian/rules
  - Removed obsolete configuration options
  - Enable db and radius basic authentication modules

* debian/patches/01-cf.data.debian
  - Adapted to new upstream version

* debian/patches/02-makefile-defaults
  - Adapted to new upstream version

* debian/{squid.postinst,squid.rc,README.Debian,watch}
  - Updated references to squid 3.1

* debian/squid3.install
  - Install CSS file for error pages
  - Install manual pages for new authentication modules

* debian/squid3-common.install
  - Install documented version of configuration file in /usr/share/doc/squid3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
23
 *
 
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.
 
28
 *
 
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
 
 
36
#include "squid.h"
 
37
#include "acl/Ip.h"
 
38
#include "acl/Checklist.h"
 
39
#include "MemBuf.h"
 
40
#include "wordlist.h"
 
41
 
 
42
void *
 
43
ACLIP::operator new (size_t byteCount)
 
44
{
 
45
    fatal ("ACLIP::operator new: unused");
 
46
    return (void *)1;
 
47
}
 
48
 
 
49
void
 
50
ACLIP::operator delete (void *address)
 
51
{
 
52
    fatal ("ACLIP::operator delete: unused");
 
53
}
 
54
 
 
55
/**
 
56
 * Writes an IP ACL data into a buffer, then copies the buffer into the wordlist given
 
57
 *
 
58
 \param ip      ACL data structure to display
 
59
 \param state   wordlist structure which is being generated
 
60
 */
 
61
void
 
62
ACLIP::DumpIpListWalkee(acl_ip_data * const & ip, void *state)
 
63
{
 
64
    char tmpbuf[ ((MAX_IPSTRLEN*2)+6) ]; // space for 2 IPs and a CIDR mask(3) and seperators(3).
 
65
    MemBuf mb;
 
66
    wordlist **W = static_cast<wordlist **>(state);
 
67
    tmpbuf[0] = '\0';
 
68
 
 
69
    mb.init();
 
70
    assert(mb.max_capacity > 0 && 1==1 );
 
71
 
 
72
    ip->toStr(tmpbuf, sizeof(tmpbuf) );
 
73
    assert(mb.max_capacity > 0 && 2==2 );
 
74
    mb.append(tmpbuf, strlen(tmpbuf) );
 
75
    assert(mb.max_capacity > 0 && 3==3);
 
76
    wordlistAdd(W, mb.buf);
 
77
    mb.clean();
 
78
}
 
79
 
 
80
/**
 
81
 * print/format an acl_ip_data structure for debugging output.
 
82
 *
 
83
 \param buf     string buffer to write to
 
84
 \param len     size of the buffer available
 
85
 */
 
86
void
 
87
acl_ip_data::toStr(char *buf, int len) const
 
88
{
 
89
    char *b1 = buf;
 
90
    char *b2 = NULL;
 
91
    char *b3 = NULL;
 
92
    int rlen = 0;
 
93
 
 
94
    addr1.NtoA(b1, len - rlen );
 
95
    rlen = strlen(buf);
 
96
    b2 = buf + rlen;
 
97
 
 
98
    if (!addr2.IsAnyAddr()) {
 
99
        b2[0] = '-';
 
100
        rlen++;
 
101
        addr2.NtoA(&(b2[1]), len - rlen );
 
102
        rlen = strlen(buf);
 
103
    } else
 
104
        b2[0] = '\0';
 
105
 
 
106
    b3 = buf + rlen;
 
107
 
 
108
    if (!mask.IsNoAddr()) {
 
109
        b3[0] = '/';
 
110
        rlen++;
 
111
#if USE_IPV6
 
112
        snprintf(&(b3[1]), (len-rlen), "%u", mask.GetCIDR() - (addr1.IsIPv4()?96:0) );
 
113
#else
 
114
        snprintf(&(b3[1]), (len-rlen), "%u", mask.GetCIDR() );
 
115
#endif
 
116
    } else
 
117
        b3[0] = '\0';
 
118
}
 
119
 
 
120
/*
 
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)
 
124
 * is an entry in some address-based access control element.  This
 
125
 * function is called via ACLIP::match() and the splay library.
 
126
 */
 
127
int
 
128
aclIpAddrNetworkCompare(acl_ip_data * const &p, acl_ip_data * const &q)
 
129
{
 
130
    IpAddress A = p->addr1;
 
131
 
 
132
    /* apply netmask */
 
133
    A.ApplyMask(q->mask);
 
134
 
 
135
    debugs(28,9, "aclIpAddrNetworkCompare: compare: " << p->addr1 << "/" << q->mask << " (" << A << ")  vs " <<
 
136
           q->addr1 << "-" << q->addr2 << "/" << q->mask);
 
137
 
 
138
    if (q->addr2.IsAnyAddr()) {       /* single address check */
 
139
 
 
140
        return A.matchIPAddr( q->addr1 );
 
141
 
 
142
    } else {                   /* range address check */
 
143
 
 
144
        if ( (A >= q->addr1) && (A <= q->addr2) )
 
145
            return 0; /* valid. inside range. */
 
146
        else
 
147
            return A.matchIPAddr( q->addr1 ); /* outside of range, 'less than' */
 
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.
 
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.
 
160
 */
 
161
int
 
162
acl_ip_data::NetworkCompare(acl_ip_data * const & a, acl_ip_data * const &b)
 
163
{
 
164
    int ret;
 
165
    bool bina = true;
 
166
    ret = aclIpAddrNetworkCompare(b, a);
 
167
 
 
168
    if (ret != 0) {
 
169
        bina = false;
 
170
        ret = aclIpAddrNetworkCompare(a, b);
 
171
    }
 
172
 
 
173
    if (ret == 0) {
 
174
        char buf_n1[3*(MAX_IPSTRLEN+1)];
 
175
        char buf_n2[3*(MAX_IPSTRLEN+1)];
 
176
        if (bina) {
 
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
        }
 
183
        debugs(28, 0, "WARNING: (" << (bina?'B':'A') << ") '" << buf_n1 << "' is a subnetwork of (" << (bina?'A':'B') << ") '" << buf_n2 << "'");
 
184
        debugs(28, 0, "WARNING: because of this '" << (bina?buf_n2:buf_n1) << "' is ignored to keep splay tree searching predictable");
 
185
        debugs(28, 0, "WARNING: You should probably remove '" << buf_n1 << "' from the ACL named '" << AclMatchedName << "'");
 
186
    }
 
187
 
 
188
    return ret;
 
189
}
 
190
 
 
191
/**
 
192
 * Decode an ascii representation (asc) of a IP netmask address or CIDR,
 
193
 * and place resulting information in mask.
 
194
 * This function should NOT be called if 'asc' is a hostname!
 
195
 */
 
196
bool
 
197
acl_ip_data::DecodeMask(const char *asc, IpAddress &mask, int ctype)
 
198
{
 
199
    char junk;
 
200
    int a1 = 0;
 
201
 
 
202
    /* default is a mask that doesn't change any IP */
 
203
    mask.SetNoAddr();
 
204
 
 
205
    if (!asc || !*asc) {
 
206
        return true;
 
207
    }
 
208
 
 
209
    /* An int mask 128, 32 */
 
210
    if ((sscanf(asc, "%d%c", &a1, &junk)==1) &&
 
211
            (a1 <= 128) && (a1  >= 0)
 
212
       ) {
 
213
        return mask.ApplyMask(a1, ctype);
 
214
    }
 
215
 
 
216
    /* dotted notation */
 
217
    /* assignment returns true if asc contained an IP address as text */
 
218
    if ((mask = asc)) {
 
219
#if USE_IPV6
 
220
        /* HACK: IPv4 netmasks don't cleanly map to IPv6 masks. */
 
221
        debugs(28, DBG_IMPORTANT, "WARNING: Netmasks are deprecated. Please use CIDR masks instead.");
 
222
        if (mask.IsIPv4()) {
 
223
            /* locate what CIDR mask was _probably_ meant to be in its native protocol format. */
 
224
            /* this will completely crap out with a security fail-open if the admin is playing mask tricks */
 
225
            /* however, thats their fault, and we do warn. see bug 2601 for the effects if we don't do this. */
 
226
            unsigned int m = mask.GetCIDR();
 
227
            debugs(28, DBG_CRITICAL, "WARNING: IPv4 netmasks are particularly nasty when used to compare IPv6 to IPv4 ranges.");
 
228
            debugs(28, DBG_CRITICAL, "WARNING: For now we assume you meant to write /" << m);
 
229
            /* reset the mask completely, and crop to the CIDR boundary back properly. */
 
230
            mask.SetNoAddr();
 
231
            return mask.ApplyMask(m,AF_INET);
 
232
        }
 
233
#endif /* USE_IPV6 */
 
234
        return true;
 
235
    }
 
236
 
 
237
    return false;
 
238
}
 
239
 
 
240
/* Handle either type of address, IPv6 will be discarded with a warning if disabled */
 
241
#define SCAN_ACL1_6       "%[0123456789ABCDEFabcdef:]-%[0123456789ABCDEFabcdef:]/%[0123456789]"
 
242
#define SCAN_ACL2_6       "%[0123456789ABCDEFabcdef:]-%[0123456789ABCDEFabcdef:]%c"
 
243
#define SCAN_ACL3_6       "%[0123456789ABCDEFabcdef:]/%[0123456789]"
 
244
#define SCAN_ACL4_6       "%[0123456789ABCDEFabcdef:]/%c"
 
245
/* We DO need to know which is which though, for proper CIDR masking. */
 
246
#define SCAN_ACL1_4       "%[0123456789.]-%[0123456789.]/%[0123456789.]"
 
247
#define SCAN_ACL2_4       "%[0123456789.]-%[0123456789.]%c"
 
248
#define SCAN_ACL3_4       "%[0123456789.]/%[0123456789.]"
 
249
#define SCAN_ACL4_4       "%[0123456789.]/%c"
 
250
 
 
251
acl_ip_data *
 
252
acl_ip_data::FactoryParse(const char *t)
 
253
{
 
254
    LOCAL_ARRAY(char, addr1, 256);
 
255
    LOCAL_ARRAY(char, addr2, 256);
 
256
    LOCAL_ARRAY(char, mask, 256);
 
257
    acl_ip_data *r = NULL;
 
258
    acl_ip_data **Q = NULL;
 
259
    IpAddress temp;
 
260
    char c;
 
261
    unsigned int changed;
 
262
    acl_ip_data *q = new acl_ip_data;
 
263
    int iptype = AF_UNSPEC;
 
264
 
 
265
    debugs(28, 5, "aclIpParseIpData: " << t);
 
266
 
 
267
    /* Special ACL RHS "all" matches entire Internet */
 
268
    if (strcasecmp(t, "all") == 0) {
 
269
        debugs(28, 9, "aclIpParseIpData: magic 'all' found.");
 
270
        q->addr1.SetAnyAddr();
 
271
        q->addr2.SetEmpty();
 
272
        q->mask.SetAnyAddr();
 
273
        return q;
 
274
    }
 
275
 
 
276
#if USE_IPV6
 
277
    /* Special ACL RHS "ipv6" matches IPv6-Unicast Internet */
 
278
    if (strcasecmp(t, "ipv6") == 0) {
 
279
        debugs(28, 9, "aclIpParseIpData: magic 'ipv6' found.");
 
280
        t = "2000::/3";
 
281
        /* AYJ: due to the nature os IPv6 this will not always work,
 
282
         *      we may need to turn recursive to catch all the valid v6 sub-nets. */
 
283
    }
 
284
#endif
 
285
 
 
286
// IPv4
 
287
    if (sscanf(t, SCAN_ACL1_4, addr1, addr2, mask) == 3) {
 
288
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN1-v4: " << SCAN_ACL1_4);
 
289
        iptype=AF_INET;
 
290
    } else if (sscanf(t, SCAN_ACL2_4, addr1, addr2, &c) >= 2) {
 
291
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN2-v4: " << SCAN_ACL2_4);
 
292
        mask[0] = '\0';
 
293
        iptype=AF_INET;
 
294
    } else if (sscanf(t, SCAN_ACL3_4, addr1, mask) == 2) {
 
295
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN3-v4: " << SCAN_ACL3_4);
 
296
        addr2[0] = '\0';
 
297
        iptype=AF_INET;
 
298
    } else if (sscanf(t, SCAN_ACL4_4, addr1,&c) == 2) {
 
299
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN4-v4: " << SCAN_ACL4_4);
 
300
        addr2[0] = '\0';
 
301
        mask[0] = '\0';
 
302
        iptype=AF_INET;
 
303
 
 
304
// IPv6
 
305
    } else if (sscanf(t, SCAN_ACL1_6, addr1, addr2, mask) == 3) {
 
306
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN1-v4: " << SCAN_ACL1_6);
 
307
        iptype=AF_INET6;
 
308
    } else if (sscanf(t, SCAN_ACL2_6, addr1, addr2, &c) >= 2) {
 
309
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN2-v4: " << SCAN_ACL2_6);
 
310
        mask[0] = '\0';
 
311
        iptype=AF_INET6;
 
312
    } else if (sscanf(t, SCAN_ACL3_6, addr1, mask) == 2) {
 
313
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN3-v4: " << SCAN_ACL3_6);
 
314
        addr2[0] = '\0';
 
315
        iptype=AF_INET6;
 
316
    } else if (sscanf(t, SCAN_ACL4_6, addr1, mask) == 2) {
 
317
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN4-v4: " << SCAN_ACL4_6);
 
318
        addr2[0] = '\0';
 
319
        iptype=AF_INET6;
 
320
 
 
321
// Neither
 
322
    } else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) {
 
323
        debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: non-IP pattern: %[^/]/%s");
 
324
        addr2[0] = '\0';
 
325
    } else if (sscanf(t, "%s", addr1) == 1) {
 
326
        /*
 
327
         * Note, must use plain xgetaddrinfo() here because at startup
 
328
         * ipcache hasn't been initialized
 
329
         * TODO: offload this to one of the IpAddress lookups.
 
330
         */
 
331
 
 
332
        debugs(28, 5, "aclIpParseIpData: Lookup Host/IP " << addr1);
 
333
        struct addrinfo *hp = NULL, *x = NULL;
 
334
        struct addrinfo hints;
 
335
        IpAddress *prev_addr = NULL;
 
336
 
 
337
        memset(&hints, 0, sizeof(struct addrinfo));
 
338
 
 
339
        if ( iptype != AF_UNSPEC ) {
 
340
            hints.ai_flags |= AI_NUMERICHOST;
 
341
        }
 
342
 
 
343
#if 0 && USE_IPV6 && !IPV6_SPECIAL_SPLITSTACK
 
344
        hints.ai_flags |= AI_V4MAPPED | AI_ALL;
 
345
#endif
 
346
 
 
347
        int errcode = xgetaddrinfo(addr1,NULL,&hints,&hp);
 
348
        if (hp == NULL) {
 
349
            debugs(28, 0, "aclIpParseIpData: Bad host/IP: '" << addr1 <<
 
350
                   "' in '" << t << "', flags=" << hints.ai_flags <<
 
351
                   " : (" << errcode << ") " << xgai_strerror(errcode) );
 
352
            self_destruct();
 
353
            return NULL;
 
354
        }
 
355
 
 
356
        Q = &q;
 
357
 
 
358
        for (x = hp; x != NULL;) {
 
359
            if ((r = *Q) == NULL)
 
360
                r = *Q = new acl_ip_data;
 
361
 
 
362
            /* getaddrinfo given a host has a nasty tendency to return duplicate addr's */
 
363
            /* BUT sorted fortunately, so we can drop most of them easily */
 
364
            r->addr1 = *x;
 
365
            x = x->ai_next;
 
366
            if ( prev_addr && r->addr1 == *prev_addr) {
 
367
                debugs(28, 3, "aclIpParseIpData: Duplicate host/IP: '" << r->addr1 << "' dropped.");
 
368
                delete r;
 
369
                *Q = NULL;
 
370
                continue;
 
371
            } else
 
372
                prev_addr = &r->addr1;
 
373
 
 
374
            debugs(28, 3, "aclIpParseIpData: Located host/IP: '" << r->addr1 << "'");
 
375
 
 
376
            r->addr2.SetAnyAddr();
 
377
            r->mask.SetNoAddr();
 
378
 
 
379
            Q = &r->next;
 
380
 
 
381
            debugs(28, 3, "" << addr1 << " --> " << r->addr1 );
 
382
        }
 
383
 
 
384
        if (*Q != NULL) {
 
385
            debugs(28, 0, "aclIpParseIpData: Bad host/IP: '" << t << "'");
 
386
            self_destruct();
 
387
            return NULL;
 
388
        }
 
389
 
 
390
        xfreeaddrinfo(hp);
 
391
 
 
392
        return q;
 
393
    }
 
394
 
 
395
#if !USE_IPV6
 
396
    /* ignore IPv6 addresses when built with IPv4-only */
 
397
    if ( iptype == AF_INET6 ) {
 
398
        debugs(28, 0, "aclIpParseIpData: IPv6 has not been enabled. build with '--enable-ipv6'");
 
399
        return NULL;
 
400
    }
 
401
#endif
 
402
 
 
403
    /* Decode addr1 */
 
404
    if (!*addr1 || !(q->addr1 = addr1)) {
 
405
        debugs(28, 0, "aclIpParseIpData: unknown first address in '" << t << "'");
 
406
        delete q;
 
407
        self_destruct();
 
408
        return NULL;
 
409
    }
 
410
 
 
411
    /* Decode addr2 */
 
412
    if (!*addr2)
 
413
        q->addr2.SetAnyAddr();
 
414
    else if (!(q->addr2=addr2) ) {
 
415
        debugs(28, 0, "aclIpParseIpData: unknown second address in '" << t << "'");
 
416
        delete q;
 
417
        self_destruct();
 
418
        return NULL;
 
419
    }
 
420
 
 
421
    /* Decode mask (NULL or empty means a exact host mask) */
 
422
    if (!DecodeMask(mask, q->mask, iptype)) {
 
423
        debugs(28, 0, "aclParseIpData: unknown netmask '" << mask << "' in '" << t << "'");
 
424
        delete q;
 
425
        self_destruct();
 
426
        return NULL;
 
427
    }
 
428
 
 
429
    changed = 0;
 
430
    changed += q->addr1.ApplyMask(q->mask);
 
431
    changed += q->addr2.ApplyMask(q->mask);
 
432
 
 
433
    if (changed)
 
434
        debugs(28, 0, "aclIpParseIpData: WARNING: Netmask masks away part of the specified IP in '" << t << "'");
 
435
 
 
436
    debugs(28,9, HERE << "Parsed: " << q->addr1 << "-" << q->addr2 << "/" << q->mask << "(/" << q->mask.GetCIDR() <<")");
 
437
 
 
438
    /* 1.2.3.4/255.255.255.0  --> 1.2.3.0 */
 
439
    /* Same as IPv6 (not so trivial to depict) */
 
440
    return q;
 
441
}
 
442
 
 
443
void
 
444
ACLIP::parse()
 
445
{
 
446
    char *t = NULL;
 
447
 
 
448
    while ((t = strtokFile())) {
 
449
        acl_ip_data *q = acl_ip_data::FactoryParse(t);
 
450
 
 
451
        while (q != NULL) {
 
452
            data = data->insert(q, acl_ip_data::NetworkCompare);
 
453
            q = q->next;
 
454
        }
 
455
    }
 
456
}
 
457
 
 
458
ACLIP::~ACLIP()
 
459
{
 
460
    if (data)
 
461
        data->destroy(IPSplay::DefaultFree);
 
462
}
 
463
 
 
464
wordlist *
 
465
ACLIP::dump() const
 
466
{
 
467
    wordlist *w = NULL;
 
468
    data->walk (DumpIpListWalkee, &w);
 
469
    return w;
 
470
}
 
471
 
 
472
bool
 
473
ACLIP::empty () const
 
474
{
 
475
    return data->empty();
 
476
}
 
477
 
 
478
int
 
479
ACLIP::match(IpAddress &clientip)
 
480
{
 
481
    static acl_ip_data ClientAddress;
 
482
    /*
 
483
     * aclIpAddrNetworkCompare() takes two acl_ip_data pointers as
 
484
     * arguments, so we must create a fake one for the client's IP
 
485
     * address. Since we are scanning for a single IP mask and addr2
 
486
     * MUST be set to empty.
 
487
     */
 
488
    ClientAddress.addr1 = clientip;
 
489
    ClientAddress.addr2.SetEmpty();
 
490
    ClientAddress.mask.SetEmpty();
 
491
 
 
492
    data = data->splay(&ClientAddress, aclIpAddrNetworkCompare);
 
493
    debugs(28, 3, "aclIpMatchIp: '" << clientip << "' " << (splayLastResult ? "NOT found" : "found"));
 
494
    return !splayLastResult;
 
495
}
 
496
 
 
497
acl_ip_data::acl_ip_data () :addr1(), addr2(), mask(), next (NULL) {}
 
498
 
 
499
acl_ip_data::acl_ip_data (IpAddress const &anAddress1, IpAddress const &anAddress2, IpAddress const &aMask, acl_ip_data *aNext) : addr1(anAddress1), addr2(anAddress2), mask(aMask), next(aNext) {}