]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/RegexData.cc
2 * DEBUG: section 28 Access Control
3 * AUTHOR: Duane Wessels
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
34 * Copyright (c) 2011, Marcus Kool
39 #include "acl/Checklist.h"
40 #include "acl/RegexData.h"
41 #include "ConfigParser.h"
44 #include "RegexList.h"
48 aclDestroyRegexList(RegexList
* data
)
50 RegexList
*next
= NULL
;
52 for (; data
; data
= next
) {
54 regfree(&data
->regex
);
55 safe_free(data
->pattern
);
56 memFree(data
, MEM_RELIST
);
60 ACLRegexData::~ACLRegexData()
62 aclDestroyRegexList(data
);
66 ACLRegexData::match(char const *word
)
71 debugs(28, 3, "aclRegexData::match: checking '" << word
<< "'");
73 RegexList
*first
, *prev
;
79 RegexList
*current
= first
;
82 debugs(28, 3, "aclRegexData::match: looking for '" << current
->pattern
<< "'");
84 if (regexec(¤t
->regex
, word
, 0, 0, 0) == 0) {
86 /* shift the element just found to the second position
88 prev
->next
= current
->next
;
89 current
->next
= first
->next
;
90 first
->next
= current
;
93 debugs(28, 2, "aclRegexData::match: match '" << current
->pattern
<< "' found in '" << word
<< "'");
98 current
= current
->next
;
105 ACLRegexData::dump() const
108 RegexList
*temp
= data
;
109 int flags
= REG_EXTENDED
| REG_NOSUB
;
111 while (temp
!= NULL
) {
112 if (temp
->flags
!= flags
) {
113 if ((temp
->flags
®_ICASE
) != 0) {
114 sl
.push_back(SBuf("-i"));
116 sl
.push_back(SBuf("+i"));
121 sl
.push_back(SBuf(temp
->pattern
));
129 removeUnnecessaryWildcards(char * t
)
133 if (strncmp(t
, "^.*", 3) == 0)
136 /* NOTE: an initial '.' might seem unnessary but is not;
137 * it can be a valid requirement that cannot be optimised
139 while (*t
== '.' && *(t
+1) == '*') {
144 debugs(28, DBG_IMPORTANT
, "" << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
145 debugs(28, DBG_IMPORTANT
, "WARNING: regular expression '" << orig
<< "' has only wildcards and matches all strings. Using '.*' instead.");
149 debugs(28, DBG_IMPORTANT
, "" << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
150 debugs(28, DBG_IMPORTANT
, "WARNING: regular expression '" << orig
<< "' has unnecessary wildcard(s). Using '" << t
<< "' instead.");
157 compileRE(RegexList
**Tail
, char * RE
, int flags
)
163 if (RE
== NULL
|| *RE
== '\0')
166 if ((errcode
= regcomp(&comp
, RE
, flags
)) != 0) {
168 regerror(errcode
, &comp
, errbuf
, sizeof errbuf
);
169 debugs(28, DBG_CRITICAL
, "" << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
170 debugs(28, DBG_CRITICAL
, "ERROR: invalid regular expression: '" << RE
<< "': " << errbuf
);
173 debugs(28, 2, "compileRE: compiled '" << RE
<< "' with flags " << flags
);
175 q
= (RegexList
*) memAllocate(MEM_RELIST
);
176 q
->pattern
= xstrdup(RE
);
185 /** Compose and compile one large RE from a set of (small) REs.
186 * The ultimate goal is to have only one RE per ACL so that regexec() is
187 * called only once per ACL.
190 compileOptimisedREs(RegexList
**curlist
, wordlist
* wl
)
194 RegexList
**newlistp
;
196 int flags
= REG_EXTENDED
| REG_NOSUB
;
197 int largeREindex
= 0;
198 char largeRE
[BUFSIZ
];
207 RElen
= strlen( wl
->key
);
209 if (strcmp(wl
->key
, "-i") == 0) {
210 if (flags
& REG_ICASE
) {
211 /* optimisation of -i ... -i */
212 debugs(28, 2, "compileOptimisedREs: optimisation of -i ... -i" );
214 debugs(28, 2, "compileOptimisedREs: -i" );
215 newlistp
= compileRE( newlistp
, largeRE
, flags
);
216 if (newlistp
== NULL
) {
217 aclDestroyRegexList( newlist
);
221 largeRE
[largeREindex
=0] = '\0';
223 } else if (strcmp(wl
->key
, "+i") == 0) {
224 if ((flags
& REG_ICASE
) == 0) {
225 /* optimisation of +i ... +i */
226 debugs(28, 2, "compileOptimisedREs: optimisation of +i ... +i");
228 debugs(28, 2, "compileOptimisedREs: +i");
229 newlistp
= compileRE( newlistp
, largeRE
, flags
);
230 if (newlistp
== NULL
) {
231 aclDestroyRegexList( newlist
);
235 largeRE
[largeREindex
=0] = '\0';
237 } else if (RElen
+ largeREindex
+ 3 < BUFSIZ
-1) {
238 debugs(28, 2, "compileOptimisedREs: adding RE '" << wl
->key
<< "'");
239 if (largeREindex
> 0) {
240 largeRE
[largeREindex
] = '|';
243 largeRE
[largeREindex
] = '(';
245 for (char * t
= wl
->key
; *t
!= '\0'; ++t
) {
246 largeRE
[largeREindex
] = *t
;
249 largeRE
[largeREindex
] = ')';
251 largeRE
[largeREindex
] = '\0';
254 debugs(28, 2, "compileOptimisedREs: buffer full, generating new optimised RE..." );
255 newlistp
= compileRE( newlistp
, largeRE
, flags
);
256 if (newlistp
== NULL
) {
257 aclDestroyRegexList( newlist
);
260 largeRE
[largeREindex
=0] = '\0';
261 continue; /* do the loop again to add the RE to largeRE */
266 newlistp
= compileRE( newlistp
, largeRE
, flags
);
267 if (newlistp
== NULL
) {
268 aclDestroyRegexList( newlist
);
272 /* all was successful, so put the new list at the tail */
273 if (*curlist
== NULL
) {
276 for (Tail
= curlist
; *Tail
!= NULL
; Tail
= &((*Tail
)->next
))
281 debugs(28, 2, "compileOptimisedREs: " << numREs
<< " REs are optimised into one RE.");
283 debugs(28, (opt_parse_cfg_only
?DBG_IMPORTANT
:2), "" << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
284 debugs(28, (opt_parse_cfg_only
?DBG_IMPORTANT
:2), "WARNING: there are more than 100 regular expressions. " <<
285 "Consider using less REs or use rules without expressions like 'dstdomain'.");
292 compileUnoptimisedREs(RegexList
**curlist
, wordlist
* wl
)
296 int flags
= REG_EXTENDED
| REG_NOSUB
;
298 for (Tail
= curlist
; *Tail
!= NULL
; Tail
= &((*Tail
)->next
))
302 if (strcmp(wl
->key
, "-i") == 0) {
304 } else if (strcmp(wl
->key
, "+i") == 0) {
307 newTail
= compileRE( Tail
, wl
->key
, flags
);
309 debugs(28, DBG_CRITICAL
, "ERROR: Skipping regular expression. Compile failed: '" << wl
->key
<< "'");
318 aclParseRegexList(RegexList
**curlist
)
323 debugs(28, 2, HERE
<< "aclParseRegexList: new Regex line or file");
325 while ((t
= ConfigParser::RegexStrtokFile()) != NULL
) {
326 const char *clean
= removeUnnecessaryWildcards(t
);
327 if (strlen(clean
) > BUFSIZ
-1) {
328 debugs(28, DBG_CRITICAL
, "" << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
329 debugs(28, DBG_CRITICAL
, "ERROR: Skipping regular expression. Larger than " << BUFSIZ
-1 << " characters: '" << clean
<< "'");
331 debugs(28, 3, "aclParseRegexList: buffering RE '" << clean
<< "'");
332 wordlistAdd(&wl
, clean
);
336 if (!compileOptimisedREs(curlist
, wl
)) {
337 debugs(28, DBG_IMPORTANT
, "WARNING: optimisation of regular expressions failed; using fallback method without optimisation");
338 compileUnoptimisedREs(curlist
, wl
);
341 wordlistDestroy(&wl
);
345 ACLRegexData::parse()
347 aclParseRegexList(&data
);
351 ACLRegexData::empty() const
356 ACLData
<char const *> *
357 ACLRegexData::clone() const
359 /* Regex's don't clone yet. */
361 return new ACLRegexData
;