]>
Commit | Line | Data |
---|---|---|
8000a965 | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 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" |
16c5ad96 | 15 | #include "ConfigParser.h" |
582c2af2 | 16 | #include "Debug.h" |
055421ee | 17 | #include "ip/tools.h" |
0eb49b6d | 18 | #include "MemBuf.h" |
d295d770 | 19 | #include "wordlist.h" |
8000a965 | 20 | |
21 | void * | |
ced8def3 | 22 | ACLIP::operator new (size_t) |
8000a965 | 23 | { |
24 | fatal ("ACLIP::operator new: unused"); | |
25 | return (void *)1; | |
26 | } | |
27 | ||
28 | void | |
ced8def3 | 29 | ACLIP::operator delete (void *) |
8000a965 | 30 | { |
31 | fatal ("ACLIP::operator delete: unused"); | |
32 | } | |
33 | ||
60cad937 AJ |
34 | /** |
35 | * print/format an acl_ip_data structure for debugging output. | |
36 | * | |
f53969cc SM |
37 | \param buf string buffer to write to |
38 | \param len size of the buffer available | |
8000a965 | 39 | */ |
40 | void | |
41 | acl_ip_data::toStr(char *buf, int len) const | |
42 | { | |
cc192b50 | 43 | char *b1 = buf; |
44 | char *b2 = NULL; | |
45 | char *b3 = NULL; | |
46 | int rlen = 0; | |
62e76326 | 47 | |
4dd643d5 | 48 | addr1.toStr(b1, len - rlen ); |
cc192b50 | 49 | rlen = strlen(buf); |
50 | b2 = buf + rlen; | |
51 | ||
4dd643d5 | 52 | if (!addr2.isAnyAddr()) { |
26ac0430 | 53 | b2[0] = '-'; |
742a021b | 54 | ++rlen; |
4dd643d5 | 55 | addr2.toStr(&(b2[1]), len - rlen ); |
cc192b50 | 56 | rlen = strlen(buf); |
26ac0430 | 57 | } else |
62e76326 | 58 | b2[0] = '\0'; |
59 | ||
cc192b50 | 60 | b3 = buf + rlen; |
61 | ||
4dd643d5 | 62 | if (!mask.isNoAddr()) { |
26ac0430 | 63 | b3[0] = '/'; |
742a021b | 64 | ++rlen; |
4dd643d5 | 65 | int cidr = mask.cidr() - (addr1.isIPv4()?96:0); |
7764e92d | 66 | snprintf(&(b3[1]), (len-rlen), "%u", (unsigned int)(cidr<0?0:cidr) ); |
26ac0430 | 67 | } else |
62e76326 | 68 | b3[0] = '\0'; |
8000a965 | 69 | } |
70 | ||
dfad5100 FC |
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 | ||
8000a965 | 80 | /* |
077fe581 | 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) | |
8000a965 | 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 | { | |
b7ac5457 | 90 | Ip::Address A = p->addr1; |
62e76326 | 91 | |
cc192b50 | 92 | /* apply netmask */ |
4dd643d5 | 93 | A.applyMask(q->mask); |
62e76326 | 94 | |
8378b076 | 95 | debugs(28,9, "aclIpAddrNetworkCompare: compare: " << p->addr1 << "/" << q->mask << " (" << A << ") vs " << |
af6a12ee | 96 | q->addr1 << "-" << q->addr2 << "/" << q->mask); |
8378b076 | 97 | |
4dd643d5 | 98 | if (q->addr2.isAnyAddr()) { /* single address check */ |
62e76326 | 99 | |
cc192b50 | 100 | return A.matchIPAddr( q->addr1 ); |
62e76326 | 101 | |
cc192b50 | 102 | } else { /* range address check */ |
62e76326 | 103 | |
cc192b50 | 104 | if ( (A >= q->addr1) && (A <= q->addr2) ) |
105 | return 0; /* valid. inside range. */ | |
62e76326 | 106 | else |
cc192b50 | 107 | return A.matchIPAddr( q->addr1 ); /* outside of range, 'less than' */ |
8000a965 | 108 | } |
109 | } | |
110 | ||
8000a965 | 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. | |
077fe581 | 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. | |
8000a965 | 119 | */ |
120 | int | |
121 | acl_ip_data::NetworkCompare(acl_ip_data * const & a, acl_ip_data * const &b) | |
122 | { | |
123 | int ret; | |
cc192b50 | 124 | bool bina = true; |
8000a965 | 125 | ret = aclIpAddrNetworkCompare(b, a); |
62e76326 | 126 | |
8000a965 | 127 | if (ret != 0) { |
cc192b50 | 128 | bina = false; |
62e76326 | 129 | ret = aclIpAddrNetworkCompare(a, b); |
8000a965 | 130 | } |
62e76326 | 131 | |
8000a965 | 132 | if (ret == 0) { |
cc192b50 | 133 | char buf_n1[3*(MAX_IPSTRLEN+1)]; |
134 | char buf_n2[3*(MAX_IPSTRLEN+1)]; | |
26ac0430 | 135 | if (bina) { |
cc192b50 | 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 | } | |
fa84c01d FC |
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 << "'"); | |
8000a965 | 145 | } |
62e76326 | 146 | |
8000a965 | 147 | return ret; |
148 | } | |
149 | ||
a7b15245 | 150 | /** |
077fe581 | 151 | * Decode an ascii representation (asc) of a IP netmask address or CIDR, |
152 | * and place resulting information in mask. | |
8000a965 | 153 | * This function should NOT be called if 'asc' is a hostname! |
154 | */ | |
155 | bool | |
b7ac5457 | 156 | acl_ip_data::DecodeMask(const char *asc, Ip::Address &mask, int ctype) |
8000a965 | 157 | { |
78d7484b | 158 | char junk; |
159 | int a1 = 0; | |
8000a965 | 160 | |
cc192b50 | 161 | /* default is a mask that doesn't change any IP */ |
4dd643d5 | 162 | mask.setNoAddr(); |
cc192b50 | 163 | |
26ac0430 | 164 | if (!asc || !*asc) { |
077fe581 | 165 | return true; |
8000a965 | 166 | } |
167 | ||
cc192b50 | 168 | /* An int mask 128, 32 */ |
169 | if ((sscanf(asc, "%d%c", &a1, &junk)==1) && | |
26ac0430 AJ |
170 | (a1 <= 128) && (a1 >= 0) |
171 | ) { | |
4dd643d5 | 172 | return mask.applyMask(a1, ctype); |
78d7484b | 173 | } |
62e76326 | 174 | |
78d7484b | 175 | /* dotted notation */ |
cc192b50 | 176 | /* assignment returns true if asc contained an IP address as text */ |
dff9ee49 | 177 | if ((mask = asc)) { |
dff9ee49 | 178 | /* HACK: IPv4 netmasks don't cleanly map to IPv6 masks. */ |
4f875552 | 179 | debugs(28, DBG_CRITICAL, "WARNING: Netmasks are deprecated. Please use CIDR masks instead."); |
4dd643d5 | 180 | if (mask.isIPv4()) { |
dff9ee49 AJ |
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, thats their fault, and we do warn. see bug 2601 for the effects if we don't do this. */ | |
4dd643d5 | 184 | unsigned int m = mask.cidr(); |
dff9ee49 | 185 | debugs(28, DBG_CRITICAL, "WARNING: IPv4 netmasks are particularly nasty when used to compare IPv6 to IPv4 ranges."); |
4f875552 | 186 | debugs(28, DBG_CRITICAL, "WARNING: For now we will assume you meant to write /" << m); |
dff9ee49 | 187 | /* reset the mask completely, and crop to the CIDR boundary back properly. */ |
4dd643d5 AJ |
188 | mask.setNoAddr(); |
189 | return mask.applyMask(m,AF_INET); | |
dff9ee49 | 190 | } |
077fe581 | 191 | return true; |
dff9ee49 | 192 | } |
62e76326 | 193 | |
077fe581 | 194 | return false; |
8000a965 | 195 | } |
196 | ||
cc192b50 | 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" | |
8000a965 | 207 | |
208 | acl_ip_data * | |
209 | acl_ip_data::FactoryParse(const char *t) | |
210 | { | |
cc192b50 | 211 | LOCAL_ARRAY(char, addr1, 256); |
8000a965 | 212 | LOCAL_ARRAY(char, addr2, 256); |
213 | LOCAL_ARRAY(char, mask, 256); | |
cc192b50 | 214 | acl_ip_data *r = NULL; |
215 | acl_ip_data **Q = NULL; | |
b7ac5457 | 216 | Ip::Address temp; |
8000a965 | 217 | char c; |
cc192b50 | 218 | unsigned int changed; |
8000a965 | 219 | acl_ip_data *q = new acl_ip_data; |
cc192b50 | 220 | int iptype = AF_UNSPEC; |
221 | ||
222 | debugs(28, 5, "aclIpParseIpData: " << t); | |
62e76326 | 223 | |
cc192b50 | 224 | /* Special ACL RHS "all" matches entire Internet */ |
a37d6070 | 225 | if (strcmp(t, "all") == 0) { |
2c1b9590 | 226 | debugs(28, 9, "aclIpParseIpData: magic 'all' found."); |
4dd643d5 AJ |
227 | q->addr1.setAnyAddr(); |
228 | q->addr2.setEmpty(); | |
229 | q->mask.setAnyAddr(); | |
62e76326 | 230 | return q; |
8000a965 | 231 | } |
62e76326 | 232 | |
7764e92d AJ |
233 | /* Detect some old broken strings equivalent to 'all'. |
234 | * treat them nicely. But be loud until its fixed. */ | |
a37d6070 TX |
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) { | |
7764e92d AJ |
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."); | |
4dd643d5 AJ |
240 | q->addr1.setAnyAddr(); |
241 | q->addr2.setEmpty(); | |
242 | q->mask.setAnyAddr(); | |
7764e92d AJ |
243 | return q; |
244 | } | |
245 | ||
7764e92d AJ |
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 */ | |
a37d6070 | 249 | if (strcmp(t, "ipv4") == 0) { |
4dd643d5 AJ |
250 | q->mask.setNoAddr(); |
251 | q->mask.applyMask(0, AF_INET); | |
7764e92d AJ |
252 | return q; |
253 | } | |
254 | ||
cc192b50 | 255 | /* Special ACL RHS "ipv6" matches IPv6-Unicast Internet */ |
a37d6070 | 256 | if (strcmp(t, "ipv6") == 0) { |
2c1b9590 | 257 | debugs(28, 9, "aclIpParseIpData: magic 'ipv6' found."); |
18a8e998 AJ |
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::"; | |
4dd643d5 AJ |
264 | q->mask.setNoAddr(); |
265 | q->mask.applyMask(4, AF_INET6); | |
18a8e998 AJ |
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::"; | |
4dd643d5 AJ |
271 | q->mask.setNoAddr(); |
272 | q->mask.applyMask(3, AF_INET6); | |
18a8e998 AJ |
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::"; | |
4dd643d5 AJ |
278 | q->mask.setNoAddr(); |
279 | q->mask.applyMask(2, AF_INET6); | |
18a8e998 AJ |
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::"; | |
4dd643d5 AJ |
285 | q->mask.setNoAddr(); |
286 | q->mask.applyMask(2, AF_INET6); | |
18a8e998 AJ |
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::"; | |
4dd643d5 AJ |
292 | q->mask.setNoAddr(); |
293 | q->mask.applyMask(3, AF_INET6); | |
18a8e998 AJ |
294 | |
295 | /* Future global unicast space: E000::/4 */ | |
296 | q->next = new acl_ip_data; | |
297 | q = q->next; | |
298 | q->addr1 = "E000::"; | |
4dd643d5 AJ |
299 | q->mask.setNoAddr(); |
300 | q->mask.applyMask(4, AF_INET6); | |
18a8e998 AJ |
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::"; | |
4dd643d5 AJ |
308 | q->mask.setNoAddr(); |
309 | q->mask.applyMask(7, AF_INET6); | |
18a8e998 AJ |
310 | |
311 | /* Link-Local unicast space: FE80::/10 */ | |
312 | q->next = new acl_ip_data; | |
313 | q = q->next; | |
314 | q->addr1 = "FE80::"; | |
4dd643d5 AJ |
315 | q->mask.setNoAddr(); |
316 | q->mask.applyMask(10, AF_INET6); | |
18a8e998 AJ |
317 | |
318 | return r; | |
cc192b50 | 319 | } |
62e76326 | 320 | |
cc192b50 | 321 | // IPv4 |
322 | if (sscanf(t, SCAN_ACL1_4, addr1, addr2, mask) == 3) { | |
2c1b9590 | 323 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN1-v4: " << SCAN_ACL1_4); |
cc192b50 | 324 | iptype=AF_INET; |
325 | } else if (sscanf(t, SCAN_ACL2_4, addr1, addr2, &c) >= 2) { | |
2c1b9590 | 326 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN2-v4: " << SCAN_ACL2_4); |
62e76326 | 327 | mask[0] = '\0'; |
cc192b50 | 328 | iptype=AF_INET; |
329 | } else if (sscanf(t, SCAN_ACL3_4, addr1, mask) == 2) { | |
2c1b9590 | 330 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN3-v4: " << SCAN_ACL3_4); |
62e76326 | 331 | addr2[0] = '\0'; |
cc192b50 | 332 | iptype=AF_INET; |
333 | } else if (sscanf(t, SCAN_ACL4_4, addr1,&c) == 2) { | |
2c1b9590 | 334 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN4-v4: " << SCAN_ACL4_4); |
cc192b50 | 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) { | |
d9a200ce | 341 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN1-v6: " << SCAN_ACL1_6); |
cc192b50 | 342 | iptype=AF_INET6; |
343 | } else if (sscanf(t, SCAN_ACL2_6, addr1, addr2, &c) >= 2) { | |
d9a200ce | 344 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN2-v6: " << SCAN_ACL2_6); |
cc192b50 | 345 | mask[0] = '\0'; |
346 | iptype=AF_INET6; | |
347 | } else if (sscanf(t, SCAN_ACL3_6, addr1, mask) == 2) { | |
d9a200ce | 348 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN3-v6: " << SCAN_ACL3_6); |
cc192b50 | 349 | addr2[0] = '\0'; |
350 | iptype=AF_INET6; | |
351 | } else if (sscanf(t, SCAN_ACL4_6, addr1, mask) == 2) { | |
d9a200ce | 352 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: SCAN4-v6: " << SCAN_ACL4_6); |
cc192b50 | 353 | addr2[0] = '\0'; |
354 | iptype=AF_INET6; | |
355 | ||
356 | // Neither | |
8000a965 | 357 | } else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) { |
2c1b9590 | 358 | debugs(28, 9, "aclIpParseIpData: '" << t << "' matched: non-IP pattern: %[^/]/%s"); |
62e76326 | 359 | addr2[0] = '\0'; |
8000a965 | 360 | } else if (sscanf(t, "%s", addr1) == 1) { |
62e76326 | 361 | /* |
27bc2077 | 362 | * Note, must use plain getaddrinfo() here because at startup |
62e76326 | 363 | * ipcache hasn't been initialized |
b7ac5457 | 364 | * TODO: offload this to one of the Ip::Address lookups. |
62e76326 | 365 | */ |
366 | ||
cc192b50 | 367 | debugs(28, 5, "aclIpParseIpData: Lookup Host/IP " << addr1); |
368 | struct addrinfo *hp = NULL, *x = NULL; | |
369 | struct addrinfo hints; | |
b7ac5457 | 370 | Ip::Address *prev_addr = NULL; |
cc192b50 | 371 | |
372 | memset(&hints, 0, sizeof(struct addrinfo)); | |
373 | ||
27bc2077 | 374 | int errcode = getaddrinfo(addr1,NULL,&hints,&hp); |
cc192b50 | 375 | if (hp == NULL) { |
fe41e23f | 376 | delete q; |
7d036ab5 AJ |
377 | if (strcmp(addr1, "::1") == 0) { |
378 | debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled in host DNS resolver."); | |
7d036ab5 AJ |
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 | } | |
cc192b50 | 385 | return NULL; |
62e76326 | 386 | } |
387 | ||
388 | Q = &q; | |
389 | ||
cc192b50 | 390 | for (x = hp; x != NULL;) { |
62e76326 | 391 | if ((r = *Q) == NULL) |
392 | r = *Q = new acl_ip_data; | |
393 | ||
cc192b50 | 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; | |
26ac0430 | 398 | if ( prev_addr && r->addr1 == *prev_addr) { |
cc192b50 | 399 | debugs(28, 3, "aclIpParseIpData: Duplicate host/IP: '" << r->addr1 << "' dropped."); |
400 | delete r; | |
401 | *Q = NULL; | |
402 | continue; | |
26ac0430 | 403 | } else |
cc192b50 | 404 | prev_addr = &r->addr1; |
405 | ||
406 | debugs(28, 3, "aclIpParseIpData: Located host/IP: '" << r->addr1 << "'"); | |
62e76326 | 407 | |
4dd643d5 AJ |
408 | r->addr2.setAnyAddr(); |
409 | r->mask.setNoAddr(); | |
62e76326 | 410 | |
411 | Q = &r->next; | |
412 | ||
cc192b50 | 413 | debugs(28, 3, "" << addr1 << " --> " << r->addr1 ); |
62e76326 | 414 | } |
415 | ||
fe41e23f AJ |
416 | freeaddrinfo(hp); |
417 | ||
78d7484b | 418 | if (*Q != NULL) { |
fa84c01d | 419 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << t << "'"); |
4b0f5de8 | 420 | self_destruct(); |
cc192b50 | 421 | return NULL; |
78d7484b | 422 | } |
423 | ||
62e76326 | 424 | return q; |
8000a965 | 425 | } |
62e76326 | 426 | |
cc192b50 | 427 | /* ignore IPv6 addresses when built with IPv4-only */ |
055421ee AJ |
428 | if ( iptype == AF_INET6 && !Ip::EnableIpv6) { |
429 | debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled."); | |
b2187b85 | 430 | delete q; |
cc192b50 | 431 | return NULL; |
432 | } | |
cc192b50 | 433 | |
8000a965 | 434 | /* Decode addr1 */ |
f8d0a1ef | 435 | if (!*addr1 || !(q->addr1 = addr1)) { |
fa84c01d | 436 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: unknown first address in '" << t << "'"); |
62e76326 | 437 | delete q; |
4b0f5de8 | 438 | self_destruct(); |
62e76326 | 439 | return NULL; |
8000a965 | 440 | } |
62e76326 | 441 | |
8000a965 | 442 | /* Decode addr2 */ |
f8d0a1ef | 443 | if (!*addr2) |
4dd643d5 | 444 | q->addr2.setAnyAddr(); |
f8d0a1ef | 445 | else if (!(q->addr2=addr2) ) { |
fa84c01d | 446 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: unknown second address in '" << t << "'"); |
62e76326 | 447 | delete q; |
94e13b6c | 448 | self_destruct(); |
62e76326 | 449 | return NULL; |
8000a965 | 450 | } |
62e76326 | 451 | |
2503e5e1 | 452 | /* Decode mask (NULL or empty means a exact host mask) */ |
cc192b50 | 453 | if (!DecodeMask(mask, q->mask, iptype)) { |
fa84c01d | 454 | debugs(28, DBG_CRITICAL, "aclParseIpData: unknown netmask '" << mask << "' in '" << t << "'"); |
62e76326 | 455 | delete q; |
4b0f5de8 | 456 | self_destruct(); |
62e76326 | 457 | return NULL; |
8000a965 | 458 | } |
62e76326 | 459 | |
cc192b50 | 460 | changed = 0; |
4dd643d5 AJ |
461 | changed += q->addr1.applyMask(q->mask); |
462 | changed += q->addr2.applyMask(q->mask); | |
62e76326 | 463 | |
cc192b50 | 464 | if (changed) |
fa84c01d | 465 | debugs(28, DBG_CRITICAL, "aclIpParseIpData: WARNING: Netmask masks away part of the specified IP in '" << t << "'"); |
62e76326 | 466 | |
4dd643d5 | 467 | debugs(28,9, HERE << "Parsed: " << q->addr1 << "-" << q->addr2 << "/" << q->mask << "(/" << q->mask.cidr() <<")"); |
2c1b9590 | 468 | |
8000a965 | 469 | /* 1.2.3.4/255.255.255.0 --> 1.2.3.0 */ |
cc192b50 | 470 | /* Same as IPv6 (not so trivial to depict) */ |
8000a965 | 471 | return q; |
472 | } | |
62e76326 | 473 | |
8000a965 | 474 | void |
475 | ACLIP::parse() | |
476 | { | |
08a133e6 FC |
477 | if (data == NULL) |
478 | data = new IPSplay(); | |
479 | ||
16c5ad96 | 480 | while (char *t = ConfigParser::strtokFile()) { |
62e76326 | 481 | acl_ip_data *q = acl_ip_data::FactoryParse(t); |
482 | ||
483 | while (q != NULL) { | |
18a8e998 | 484 | /* pop each result off the list and add it to the data tree individually */ |
e4ae841b | 485 | acl_ip_data *next_node = q->next; |
18a8e998 | 486 | q->next = NULL; |
5bc2be30 FC |
487 | if (!data->find(q,acl_ip_data::NetworkCompare)) |
488 | data->insert(q, acl_ip_data::NetworkCompare); | |
e4ae841b | 489 | q = next_node; |
62e76326 | 490 | } |
788542bd | 491 | } |
8000a965 | 492 | } |
493 | ||
494 | ACLIP::~ACLIP() | |
495 | { | |
f5dc4237 | 496 | if (data) { |
6a32ab4f | 497 | data->destroy(); |
f5dc4237 FC |
498 | delete data; |
499 | } | |
8000a965 | 500 | } |
501 | ||
6a32ab4f FC |
502 | struct IpAclDumpVisitor { |
503 | SBufList contents; | |
504 | void operator() (acl_ip_data * const & ip) { | |
505 | contents.push_back(ip->toSBuf()); | |
506 | } | |
507 | }; | |
508 | ||
8966008b | 509 | SBufList |
8000a965 | 510 | ACLIP::dump() const |
511 | { | |
6a32ab4f FC |
512 | IpAclDumpVisitor visitor; |
513 | data->visit(visitor); | |
514 | return visitor.contents; | |
8000a965 | 515 | } |
516 | ||
517 | bool | |
519bae94 | 518 | ACLIP::empty() const |
8000a965 | 519 | { |
290eb6b9 | 520 | return data->empty(); |
8000a965 | 521 | } |
522 | ||
523 | int | |
5c51bffb | 524 | ACLIP::match(const 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 | |
6a32ab4f FC |
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); | |
8000a965 | 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 |