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