blob: 344a91d4c12f3fcabae36bdeb909a5cdf8f590f1 [file] [log] [blame]
Willy Tarreaua84d3742007-05-07 00:36:48 +02001/*
2 * ACL management functions.
3 *
Willy Tarreau11382812008-07-09 16:18:21 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaua84d3742007-05-07 00:36:48 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreauae8b7962007-06-09 23:10:04 +020013#include <ctype.h>
Willy Tarreaua84d3742007-05-07 00:36:48 +020014#include <stdio.h>
15#include <string.h>
16
17#include <common/config.h>
18#include <common/mini-clist.h>
19#include <common/standard.h>
20
21#include <proto/acl.h>
Willy Tarreau404e8ab2009-07-26 19:40:40 +020022#include <proto/log.h>
Willy Tarreaua84d3742007-05-07 00:36:48 +020023
Willy Tarreaua9802632008-07-25 19:13:19 +020024/* The capabilities of filtering hooks describe the type of information
25 * available to each of them.
26 */
27const unsigned int filt_cap[] = {
28 [ACL_HOOK_REQ_FE_TCP] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY,
29 [ACL_HOOK_REQ_FE_TCP_CONTENT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY,
30 [ACL_HOOK_REQ_FE_HTTP_IN] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
31 [ACL_HOOK_REQ_FE_SWITCH] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
32 [ACL_HOOK_REQ_BE_TCP_CONTENT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
33 [ACL_HOOK_REQ_BE_HTTP_IN] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
34 [ACL_HOOK_REQ_BE_SWITCH] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
35 [ACL_HOOK_REQ_FE_HTTP_OUT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
36 [ACL_HOOK_REQ_BE_HTTP_OUT] = ACL_USE_TCP4_ANY|ACL_USE_TCP6_ANY|ACL_USE_TCP_ANY|ACL_USE_L4REQ_ANY|ACL_USE_L7REQ_ANY|ACL_USE_HDR_ANY,
37
38 [ACL_HOOK_RTR_BE_TCP_CONTENT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY,
39 [ACL_HOOK_RTR_BE_HTTP_IN] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
40 [ACL_HOOK_RTR_FE_TCP_CONTENT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
41 [ACL_HOOK_RTR_FE_HTTP_IN] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
42 [ACL_HOOK_RTR_BE_HTTP_OUT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
43 [ACL_HOOK_RTR_FE_HTTP_OUT] = ACL_USE_REQ_PERMANENT|ACL_USE_REQ_CACHEABLE|ACL_USE_L4RTR_ANY|ACL_USE_L7RTR_ANY,
44};
45
Willy Tarreaua84d3742007-05-07 00:36:48 +020046/* List head of all known ACL keywords */
47static struct acl_kw_list acl_keywords = {
48 .list = LIST_HEAD_INIT(acl_keywords.list)
49};
50
51
Willy Tarreaua5909832007-06-17 20:40:25 +020052/*
53 * These functions are only used for debugging complex configurations.
Willy Tarreaua84d3742007-05-07 00:36:48 +020054 */
Willy Tarreaua5909832007-06-17 20:40:25 +020055
Willy Tarreau58393e12008-07-20 10:39:22 +020056/* force TRUE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020057static int
Willy Tarreau58393e12008-07-20 10:39:22 +020058acl_fetch_true(struct proxy *px, struct session *l4, void *l7, int dir,
59 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua5909832007-06-17 20:40:25 +020060{
Willy Tarreau58393e12008-07-20 10:39:22 +020061 test->flags |= ACL_TEST_F_SET_RES_PASS;
Willy Tarreaua5909832007-06-17 20:40:25 +020062 return 1;
63}
64
Willy Tarreaub6fb4202008-07-20 11:18:28 +020065/* wait for more data as long as possible, then return TRUE. This should be
66 * used with content inspection.
67 */
68static int
69acl_fetch_wait_end(struct proxy *px, struct session *l4, void *l7, int dir,
70 struct acl_expr *expr, struct acl_test *test)
71{
72 if (dir & ACL_PARTIAL) {
73 test->flags |= ACL_TEST_F_MAY_CHANGE;
74 return 0;
75 }
76 test->flags |= ACL_TEST_F_SET_RES_PASS;
77 return 1;
78}
79
Willy Tarreau58393e12008-07-20 10:39:22 +020080/* force FALSE to be returned at the fetch level */
Willy Tarreaua5909832007-06-17 20:40:25 +020081static int
Willy Tarreau58393e12008-07-20 10:39:22 +020082acl_fetch_false(struct proxy *px, struct session *l4, void *l7, int dir,
83 struct acl_expr *expr, struct acl_test *test)
Willy Tarreaua84d3742007-05-07 00:36:48 +020084{
Willy Tarreau58393e12008-07-20 10:39:22 +020085 test->flags |= ACL_TEST_F_SET_RES_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +020086 return 1;
87}
88
Willy Tarreau58393e12008-07-20 10:39:22 +020089
90/*
91 * These functions are exported and may be used by any other component.
92 */
93
94/* ignore the current line */
95int acl_parse_nothing(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua5909832007-06-17 20:40:25 +020096{
Willy Tarreau58393e12008-07-20 10:39:22 +020097 return 1;
98}
99
100/* always fake a data retrieval */
101int acl_fetch_nothing(struct proxy *px, struct session *l4, void *l7, int dir,
102 struct acl_expr *expr, struct acl_test *test)
103{
104 return 1;
Willy Tarreaua5909832007-06-17 20:40:25 +0200105}
106
107/* always return false */
Willy Tarreau58393e12008-07-20 10:39:22 +0200108int acl_match_nothing(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua5909832007-06-17 20:40:25 +0200109{
Willy Tarreau11382812008-07-09 16:18:21 +0200110 return ACL_PAT_FAIL;
Willy Tarreaua5909832007-06-17 20:40:25 +0200111}
112
113
Willy Tarreaua84d3742007-05-07 00:36:48 +0200114/* NB: For two strings to be identical, it is required that their lengths match */
115int acl_match_str(struct acl_test *test, struct acl_pattern *pattern)
116{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200117 int icase;
118
Willy Tarreaua84d3742007-05-07 00:36:48 +0200119 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200120 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200121
122 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
123 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) == 0) ||
124 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) == 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200125 return ACL_PAT_PASS;
126 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200127}
128
Willy Tarreauf3d25982007-05-08 22:45:09 +0200129/* Executes a regex. It needs to change the data. If it is marked READ_ONLY
130 * then it will be allocated and duplicated in place so that others may use
131 * it later on. Note that this is embarrassing because we always try to avoid
132 * allocating memory at run time.
133 */
134int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern)
135{
136 char old_char;
137 int ret;
138
139 if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) {
140 char *new_str;
141
142 new_str = calloc(1, test->len + 1);
143 if (!new_str)
Willy Tarreau11382812008-07-09 16:18:21 +0200144 return ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200145
146 memcpy(new_str, test->ptr, test->len);
147 new_str[test->len] = 0;
148 if (test->flags & ACL_TEST_F_MUST_FREE)
149 free(test->ptr);
150 test->ptr = new_str;
151 test->flags |= ACL_TEST_F_MUST_FREE;
152 test->flags &= ~ACL_TEST_F_READ_ONLY;
153 }
154
155 old_char = test->ptr[test->len];
156 test->ptr[test->len] = 0;
157
158 if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200159 ret = ACL_PAT_PASS;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200160 else
Willy Tarreau11382812008-07-09 16:18:21 +0200161 ret = ACL_PAT_FAIL;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200162
163 test->ptr[test->len] = old_char;
164 return ret;
165}
166
Willy Tarreaua84d3742007-05-07 00:36:48 +0200167/* Checks that the pattern matches the beginning of the tested string. */
168int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern)
169{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200170 int icase;
171
Willy Tarreaua84d3742007-05-07 00:36:48 +0200172 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200173 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200174
175 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
176 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, pattern->len) != 0) ||
177 (!icase && strncmp(pattern->ptr.str, test->ptr, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200178 return ACL_PAT_FAIL;
179 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200180}
181
182/* Checks that the pattern matches the end of the tested string. */
183int acl_match_end(struct acl_test *test, struct acl_pattern *pattern)
184{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200185 int icase;
186
Willy Tarreaua84d3742007-05-07 00:36:48 +0200187 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200188 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200189 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
190 if ((icase && strncasecmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0) ||
191 (!icase && strncmp(pattern->ptr.str, test->ptr + test->len - pattern->len, pattern->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +0200192 return ACL_PAT_FAIL;
193 return ACL_PAT_PASS;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200194}
195
196/* Checks that the pattern is included inside the tested string.
197 * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
198 */
199int acl_match_sub(struct acl_test *test, struct acl_pattern *pattern)
200{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200201 int icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200202 char *end;
203 char *c;
204
205 if (pattern->len > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200206 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200207
208 end = test->ptr + test->len - pattern->len;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200209 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
210 if (icase) {
211 for (c = test->ptr; c <= end; c++) {
212 if (tolower(*c) != tolower(*pattern->ptr.str))
213 continue;
214 if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200215 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200216 }
217 } else {
218 for (c = test->ptr; c <= end; c++) {
219 if (*c != *pattern->ptr.str)
220 continue;
221 if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200222 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200223 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200224 }
Willy Tarreau11382812008-07-09 16:18:21 +0200225 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200226}
227
228/* This one is used by other real functions. It checks that the pattern is
229 * included inside the tested string, but enclosed between the specified
230 * delimitor, or a '/' or a '?' or at the beginning or end of the string.
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200231 * The delimitor is stripped at the beginning or end of the pattern.
Willy Tarreaua84d3742007-05-07 00:36:48 +0200232 */
233static int match_word(struct acl_test *test, struct acl_pattern *pattern, char delim)
234{
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200235 int may_match, icase;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200236 char *c, *end;
237 char *ps;
238 int pl;
239
240 pl = pattern->len;
241 ps = pattern->ptr.str;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200242 while (pl > 0 && (*ps == delim || *ps == '/' || *ps == '?')) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200243 pl--;
244 ps++;
245 }
246
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200247 while (pl > 0 &&
248 (ps[pl - 1] == delim || ps[pl - 1] == '/' || ps[pl - 1] == '?'))
Willy Tarreaua84d3742007-05-07 00:36:48 +0200249 pl--;
250
251 if (pl > test->len)
Willy Tarreau11382812008-07-09 16:18:21 +0200252 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200253
254 may_match = 1;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200255 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200256 end = test->ptr + test->len - pl;
257 for (c = test->ptr; c <= end; c++) {
258 if (*c == '/' || *c == delim || *c == '?') {
259 may_match = 1;
260 continue;
261 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200262
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200263 if (!may_match)
264 continue;
265
266 if (icase) {
267 if ((tolower(*c) == tolower(*ps)) &&
268 (strncasecmp(ps, c, pl) == 0) &&
269 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200270 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200271 } else {
272 if ((*c == *ps) &&
273 (strncmp(ps, c, pl) == 0) &&
274 (c == end || c[pl] == '/' || c[pl] == delim || c[pl] == '?'))
Willy Tarreau11382812008-07-09 16:18:21 +0200275 return ACL_PAT_PASS;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200276 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200277 may_match = 0;
278 }
Willy Tarreau11382812008-07-09 16:18:21 +0200279 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200280}
281
282/* Checks that the pattern is included inside the tested string, but enclosed
283 * between slashes or at the beginning or end of the string. Slashes at the
284 * beginning or end of the pattern are ignored.
285 */
286int acl_match_dir(struct acl_test *test, struct acl_pattern *pattern)
287{
288 return match_word(test, pattern, '/');
289}
290
291/* Checks that the pattern is included inside the tested string, but enclosed
292 * between dots or at the beginning or end of the string. Dots at the beginning
293 * or end of the pattern are ignored.
294 */
295int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern)
296{
297 return match_word(test, pattern, '.');
298}
299
300/* Checks that the integer in <test> is included between min and max */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200301int acl_match_int(struct acl_test *test, struct acl_pattern *pattern)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200302{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200303 if ((!pattern->val.range.min_set || pattern->val.range.min <= test->i) &&
304 (!pattern->val.range.max_set || test->i <= pattern->val.range.max))
Willy Tarreau11382812008-07-09 16:18:21 +0200305 return ACL_PAT_PASS;
306 return ACL_PAT_FAIL;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200307}
308
Willy Tarreaua67fad92007-05-08 19:50:09 +0200309int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern)
310{
311 struct in_addr *s;
312
313 if (test->i != AF_INET)
Willy Tarreau11382812008-07-09 16:18:21 +0200314 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200315
316 s = (void *)test->ptr;
317 if (((s->s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
Willy Tarreau11382812008-07-09 16:18:21 +0200318 return ACL_PAT_PASS;
319 return ACL_PAT_FAIL;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200320}
321
Willy Tarreaua84d3742007-05-07 00:36:48 +0200322/* Parse a string. It is allocated and duplicated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200323int acl_parse_str(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200324{
325 int len;
326
Willy Tarreauae8b7962007-06-09 23:10:04 +0200327 len = strlen(*text);
328 pattern->ptr.str = strdup(*text);
Willy Tarreaua84d3742007-05-07 00:36:48 +0200329 if (!pattern->ptr.str)
330 return 0;
331 pattern->len = len;
332 return 1;
333}
334
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200335/* Free data allocated by acl_parse_reg */
336static void acl_free_reg(void *ptr) {
337
338 regfree((regex_t *)ptr);
339}
340
Willy Tarreauf3d25982007-05-08 22:45:09 +0200341/* Parse a regex. It is allocated. */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200342int acl_parse_reg(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreauf3d25982007-05-08 22:45:09 +0200343{
344 regex_t *preg;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200345 int icase;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200346
347 preg = calloc(1, sizeof(regex_t));
348
349 if (!preg)
350 return 0;
351
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200352 icase = (pattern->flags & ACL_PAT_F_IGNORE_CASE) ? REG_ICASE : 0;
353 if (regcomp(preg, *text, REG_EXTENDED | REG_NOSUB | icase) != 0) {
Willy Tarreauf3d25982007-05-08 22:45:09 +0200354 free(preg);
355 return 0;
356 }
357
358 pattern->ptr.reg = preg;
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200359 pattern->freeptrbuf = &acl_free_reg;
Willy Tarreauf3d25982007-05-08 22:45:09 +0200360 return 1;
361}
362
Willy Tarreauae8b7962007-06-09 23:10:04 +0200363/* Parse a range of positive integers delimited by either ':' or '-'. If only
364 * one integer is read, it is set as both min and max. An operator may be
365 * specified as the prefix, among this list of 5 :
366 *
367 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
368 *
369 * The default operator is "eq". It supports range matching. Ranges are
370 * rejected for other operators. The operator may be changed at any time.
371 * The operator is stored in the 'opaque' argument.
372 *
Willy Tarreaua84d3742007-05-07 00:36:48 +0200373 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200374int acl_parse_int(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200375{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200376 signed long long i;
377 unsigned int j, last, skip = 0;
378 const char *ptr = *text;
379
380
Willy Tarreau8f8e6452007-06-17 21:51:38 +0200381 while (!isdigit((unsigned char)*ptr)) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200382 if (strcmp(ptr, "eq") == 0) *opaque = 0;
383 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
384 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
385 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
386 else if (strcmp(ptr, "le") == 0) *opaque = 4;
387 else
388 return 0;
389
390 skip++;
391 ptr = text[skip];
392 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200393
394 last = i = 0;
395 while (1) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200396 j = *ptr++;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200397 if ((j == '-' || j == ':') && !last) {
398 last++;
399 pattern->val.range.min = i;
400 i = 0;
401 continue;
402 }
403 j -= '0';
404 if (j > 9)
405 // also catches the terminating zero
406 break;
407 i *= 10;
408 i += j;
409 }
Willy Tarreauae8b7962007-06-09 23:10:04 +0200410
411 if (last && *opaque >= 1 && *opaque <= 4)
412 /* having a range with a min or a max is absurd */
413 return 0;
414
Willy Tarreaua84d3742007-05-07 00:36:48 +0200415 if (!last)
416 pattern->val.range.min = i;
417 pattern->val.range.max = i;
Willy Tarreauae8b7962007-06-09 23:10:04 +0200418
419 switch (*opaque) {
420 case 0: /* eq */
421 pattern->val.range.min_set = 1;
422 pattern->val.range.max_set = 1;
423 break;
424 case 1: /* gt */
425 pattern->val.range.min++; /* gt = ge + 1 */
426 case 2: /* ge */
427 pattern->val.range.min_set = 1;
428 pattern->val.range.max_set = 0;
429 break;
430 case 3: /* lt */
431 pattern->val.range.max--; /* lt = le - 1 */
432 case 4: /* le */
433 pattern->val.range.min_set = 0;
434 pattern->val.range.max_set = 1;
435 break;
436 }
437 return skip + 1;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200438}
439
Willy Tarreau4a26d2f2008-07-15 16:05:33 +0200440/* Parse a range of positive 2-component versions delimited by either ':' or
441 * '-'. The version consists in a major and a minor, both of which must be
442 * smaller than 65536, because internally they will be represented as a 32-bit
443 * integer.
444 * If only one version is read, it is set as both min and max. Just like for
445 * pure integers, an operator may be specified as the prefix, among this list
446 * of 5 :
447 *
448 * 0:eq, 1:gt, 2:ge, 3:lt, 4:le
449 *
450 * The default operator is "eq". It supports range matching. Ranges are
451 * rejected for other operators. The operator may be changed at any time.
452 * The operator is stored in the 'opaque' argument. This allows constructs
453 * such as the following one :
454 *
455 * acl obsolete_ssl ssl_req_proto lt 3
456 * acl unsupported_ssl ssl_req_proto gt 3.1
457 * acl valid_ssl ssl_req_proto 3.0-3.1
458 *
459 */
460int acl_parse_dotted_ver(const char **text, struct acl_pattern *pattern, int *opaque)
461{
462 signed long long i;
463 unsigned int j, last, skip = 0;
464 const char *ptr = *text;
465
466
467 while (!isdigit((unsigned char)*ptr)) {
468 if (strcmp(ptr, "eq") == 0) *opaque = 0;
469 else if (strcmp(ptr, "gt") == 0) *opaque = 1;
470 else if (strcmp(ptr, "ge") == 0) *opaque = 2;
471 else if (strcmp(ptr, "lt") == 0) *opaque = 3;
472 else if (strcmp(ptr, "le") == 0) *opaque = 4;
473 else
474 return 0;
475
476 skip++;
477 ptr = text[skip];
478 }
479
480 last = i = 0;
481 while (1) {
482 j = *ptr++;
483 if (j == '.') {
484 /* minor part */
485 if (i >= 65536)
486 return 0;
487 i <<= 16;
488 continue;
489 }
490 if ((j == '-' || j == ':') && !last) {
491 last++;
492 if (i < 65536)
493 i <<= 16;
494 pattern->val.range.min = i;
495 i = 0;
496 continue;
497 }
498 j -= '0';
499 if (j > 9)
500 // also catches the terminating zero
501 break;
502 i = (i & 0xFFFF0000) + (i & 0xFFFF) * 10;
503 i += j;
504 }
505
506 /* if we only got a major version, let's shift it now */
507 if (i < 65536)
508 i <<= 16;
509
510 if (last && *opaque >= 1 && *opaque <= 4)
511 /* having a range with a min or a max is absurd */
512 return 0;
513
514 if (!last)
515 pattern->val.range.min = i;
516 pattern->val.range.max = i;
517
518 switch (*opaque) {
519 case 0: /* eq */
520 pattern->val.range.min_set = 1;
521 pattern->val.range.max_set = 1;
522 break;
523 case 1: /* gt */
524 pattern->val.range.min++; /* gt = ge + 1 */
525 case 2: /* ge */
526 pattern->val.range.min_set = 1;
527 pattern->val.range.max_set = 0;
528 break;
529 case 3: /* lt */
530 pattern->val.range.max--; /* lt = le - 1 */
531 case 4: /* le */
532 pattern->val.range.min_set = 0;
533 pattern->val.range.max_set = 1;
534 break;
535 }
536 return skip + 1;
537}
538
Willy Tarreaua67fad92007-05-08 19:50:09 +0200539/* Parse an IP address and an optional mask in the form addr[/mask].
540 * The addr may either be an IPv4 address or a hostname. The mask
541 * may either be a dotted mask or a number of bits. Returns 1 if OK,
542 * otherwise 0.
543 */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200544int acl_parse_ip(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreaua67fad92007-05-08 19:50:09 +0200545{
Willy Tarreauae8b7962007-06-09 23:10:04 +0200546 if (str2net(*text, &pattern->val.ipv4.addr, &pattern->val.ipv4.mask))
547 return 1;
548 else
549 return 0;
Willy Tarreaua67fad92007-05-08 19:50:09 +0200550}
551
Willy Tarreaua84d3742007-05-07 00:36:48 +0200552/*
553 * Registers the ACL keyword list <kwl> as a list of valid keywords for next
554 * parsing sessions.
555 */
556void acl_register_keywords(struct acl_kw_list *kwl)
557{
558 LIST_ADDQ(&acl_keywords.list, &kwl->list);
559}
560
561/*
562 * Unregisters the ACL keyword list <kwl> from the list of valid keywords.
563 */
564void acl_unregister_keywords(struct acl_kw_list *kwl)
565{
566 LIST_DEL(&kwl->list);
567 LIST_INIT(&kwl->list);
568}
569
570/* Return a pointer to the ACL <name> within the list starting at <head>, or
571 * NULL if not found.
572 */
573struct acl *find_acl_by_name(const char *name, struct list *head)
574{
575 struct acl *acl;
576 list_for_each_entry(acl, head, list) {
577 if (strcmp(acl->name, name) == 0)
578 return acl;
579 }
580 return NULL;
581}
582
583/* Return a pointer to the ACL keyword <kw>, or NULL if not found. Note that if
584 * <kw> contains an opening parenthesis, only the left part of it is checked.
585 */
586struct acl_keyword *find_acl_kw(const char *kw)
587{
588 int index;
589 const char *kwend;
590 struct acl_kw_list *kwl;
591
592 kwend = strchr(kw, '(');
593 if (!kwend)
594 kwend = kw + strlen(kw);
595
596 list_for_each_entry(kwl, &acl_keywords.list, list) {
597 for (index = 0; kwl->kw[index].kw != NULL; index++) {
598 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
599 kwl->kw[index].kw[kwend-kw] == 0)
600 return &kwl->kw[index];
601 }
602 }
603 return NULL;
604}
605
606static void free_pattern(struct acl_pattern *pat)
607{
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200608
609 if (pat->ptr.ptr) {
610 if (pat->freeptrbuf)
611 pat->freeptrbuf(pat->ptr.ptr);
612
Willy Tarreaua84d3742007-05-07 00:36:48 +0200613 free(pat->ptr.ptr);
Krzysztof Piotr Oledzki8001d612008-05-31 13:53:23 +0200614 }
615
Willy Tarreaua84d3742007-05-07 00:36:48 +0200616 free(pat);
617}
618
619static void free_pattern_list(struct list *head)
620{
621 struct acl_pattern *pat, *tmp;
622 list_for_each_entry_safe(pat, tmp, head, list)
623 free_pattern(pat);
624}
625
626static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
627{
628 free_pattern_list(&expr->patterns);
629 LIST_INIT(&expr->patterns);
630 if (expr->arg.str)
631 free(expr->arg.str);
632 expr->kw->use_cnt--;
633 return expr;
634}
635
636/* Parse an ACL expression starting at <args>[0], and return it.
637 * Right now, the only accepted syntax is :
638 * <subject> [<value>...]
639 */
640struct acl_expr *parse_acl_expr(const char **args)
641{
642 __label__ out_return, out_free_expr, out_free_pattern;
643 struct acl_expr *expr;
644 struct acl_keyword *aclkw;
645 struct acl_pattern *pattern;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200646 int opaque, patflags;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200647 const char *arg;
648
649 aclkw = find_acl_kw(args[0]);
650 if (!aclkw || !aclkw->parse)
651 goto out_return;
652
653 expr = (struct acl_expr *)calloc(1, sizeof(*expr));
654 if (!expr)
655 goto out_return;
656
657 expr->kw = aclkw;
658 aclkw->use_cnt++;
659 LIST_INIT(&expr->patterns);
660 expr->arg.str = NULL;
Willy Tarreaubb768912007-06-10 11:17:01 +0200661 expr->arg_len = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200662
663 arg = strchr(args[0], '(');
664 if (arg != NULL) {
665 char *end, *arg2;
666 /* there is an argument in the form "subject(arg)" */
667 arg++;
668 end = strchr(arg, ')');
669 if (!end)
670 goto out_free_expr;
Willy Tarreauac778f52010-01-26 19:02:46 +0100671 arg2 = my_strndup(arg, end - arg);
Willy Tarreau1edb1442010-01-27 20:13:38 +0100672 if (!arg2)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200673 goto out_free_expr;
Willy Tarreaubb768912007-06-10 11:17:01 +0200674 expr->arg_len = end - arg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200675 expr->arg.str = arg2;
676 }
677
Willy Tarreaua84d3742007-05-07 00:36:48 +0200678 args++;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200679
680 /* check for options before patterns. Supported options are :
681 * -i : ignore case for all patterns by default
682 * -f : read patterns from those files
683 * -- : everything after this is not an option
684 */
685 patflags = 0;
686 while (**args == '-') {
687 if ((*args)[1] == 'i')
688 patflags |= ACL_PAT_F_IGNORE_CASE;
689 else if ((*args)[1] == 'f')
690 patflags |= ACL_PAT_F_FROM_FILE;
691 else if ((*args)[1] == '-') {
692 args++;
693 break;
694 }
695 else
696 break;
697 args++;
698 }
699
700 /* now parse all patterns */
Willy Tarreauae8b7962007-06-09 23:10:04 +0200701 opaque = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200702 while (**args) {
Willy Tarreauae8b7962007-06-09 23:10:04 +0200703 int ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200704 pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
705 if (!pattern)
706 goto out_free_expr;
Willy Tarreauc8d7c962007-06-17 08:20:33 +0200707 pattern->flags = patflags;
708
Willy Tarreauae8b7962007-06-09 23:10:04 +0200709 ret = aclkw->parse(args, pattern, &opaque);
710 if (!ret)
Willy Tarreaua84d3742007-05-07 00:36:48 +0200711 goto out_free_pattern;
712 LIST_ADDQ(&expr->patterns, &pattern->list);
Willy Tarreauae8b7962007-06-09 23:10:04 +0200713 args += ret;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200714 }
715
716 return expr;
717
718 out_free_pattern:
719 free_pattern(pattern);
720 out_free_expr:
721 prune_acl_expr(expr);
722 free(expr);
723 out_return:
724 return NULL;
725}
726
Krzysztof Piotr Oledzkia643baf2008-05-29 23:53:44 +0200727/* Purge everything in the acl <acl>, then return <acl>. */
728struct acl *prune_acl(struct acl *acl) {
729
730 struct acl_expr *expr, *exprb;
731
732 free(acl->name);
733
734 list_for_each_entry_safe(expr, exprb, &acl->expr, list) {
735 LIST_DEL(&expr->list);
736 prune_acl_expr(expr);
737 free(expr);
738 }
739
740 return acl;
741}
742
Willy Tarreaua84d3742007-05-07 00:36:48 +0200743/* Parse an ACL with the name starting at <args>[0], and with a list of already
744 * known ACLs in <acl>. If the ACL was not in the list, it will be added.
745 * A pointer to that ACL is returned.
746 *
747 * args syntax: <aclname> <acl_expr>
748 */
749struct acl *parse_acl(const char **args, struct list *known_acl)
750{
751 __label__ out_return, out_free_acl_expr, out_free_name;
752 struct acl *cur_acl;
753 struct acl_expr *acl_expr;
754 char *name;
755
Willy Tarreau2e74c3f2007-12-02 18:45:09 +0100756 if (invalid_char(*args))
757 goto out_return;
758
Willy Tarreaua84d3742007-05-07 00:36:48 +0200759 acl_expr = parse_acl_expr(args + 1);
760 if (!acl_expr)
761 goto out_return;
762
Willy Tarreau404e8ab2009-07-26 19:40:40 +0200763 /* Check for args beginning with an opening parenthesis just after the
764 * subject, as this is almost certainly a typo. Right now we can only
765 * emit a warning, so let's do so.
766 */
Krzysztof Piotr Oledzki4cdd8312009-10-05 00:23:35 +0200767 if (!strchr(args[1], '(') && *args[2] == '(')
Willy Tarreau404e8ab2009-07-26 19:40:40 +0200768 Warning("parsing acl '%s' :\n"
769 " matching '%s' for pattern '%s' is likely a mistake and probably\n"
770 " not what you want. Maybe you need to remove the extraneous space before '('.\n"
771 " If you are really sure this is not an error, please insert '--' between the\n"
772 " match and the pattern to make this warning message disappear.\n",
773 args[0], args[1], args[2]);
774
Willy Tarreaua84d3742007-05-07 00:36:48 +0200775 cur_acl = find_acl_by_name(args[0], known_acl);
776 if (!cur_acl) {
777 name = strdup(args[0]);
778 if (!name)
779 goto out_free_acl_expr;
780 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
781 if (cur_acl == NULL)
782 goto out_free_name;
783
784 LIST_INIT(&cur_acl->expr);
785 LIST_ADDQ(known_acl, &cur_acl->list);
786 cur_acl->name = name;
787 }
788
Willy Tarreaua9802632008-07-25 19:13:19 +0200789 cur_acl->requires |= acl_expr->kw->requires;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200790 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
791 return cur_acl;
792
793 out_free_name:
794 free(name);
795 out_free_acl_expr:
796 prune_acl_expr(acl_expr);
797 free(acl_expr);
798 out_return:
799 return NULL;
800}
801
Willy Tarreau16fbe822007-06-17 11:54:31 +0200802/* Some useful ACLs provided by default. Only those used are allocated. */
803
804const struct {
805 const char *name;
806 const char *expr[4]; /* put enough for longest expression */
807} default_acl_list[] = {
Willy Tarreau58393e12008-07-20 10:39:22 +0200808 { .name = "TRUE", .expr = {"always_true",""}},
809 { .name = "FALSE", .expr = {"always_false",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200810 { .name = "LOCALHOST", .expr = {"src","127.0.0.1/8",""}},
Willy Tarreau2492d5b2009-07-11 00:06:00 +0200811 { .name = "HTTP", .expr = {"req_proto_http",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200812 { .name = "HTTP_1.0", .expr = {"req_ver","1.0",""}},
813 { .name = "HTTP_1.1", .expr = {"req_ver","1.1",""}},
814 { .name = "METH_CONNECT", .expr = {"method","CONNECT",""}},
815 { .name = "METH_GET", .expr = {"method","GET","HEAD",""}},
816 { .name = "METH_HEAD", .expr = {"method","HEAD",""}},
817 { .name = "METH_OPTIONS", .expr = {"method","OPTIONS",""}},
818 { .name = "METH_POST", .expr = {"method","POST",""}},
819 { .name = "METH_TRACE", .expr = {"method","TRACE",""}},
820 { .name = "HTTP_URL_ABS", .expr = {"url_reg","^[^/:]*://",""}},
821 { .name = "HTTP_URL_SLASH", .expr = {"url_beg","/",""}},
822 { .name = "HTTP_URL_STAR", .expr = {"url","*",""}},
823 { .name = "HTTP_CONTENT", .expr = {"hdr_val(content-length)","gt","0",""}},
Emeric Brunbede3d02009-06-30 17:54:00 +0200824 { .name = "RDP_COOKIE", .expr = {"req_rdp_cookie_cnt","gt","0",""}},
Willy Tarreauc6317702008-07-20 09:29:50 +0200825 { .name = "REQ_CONTENT", .expr = {"req_len","gt","0",""}},
Willy Tarreaub6fb4202008-07-20 11:18:28 +0200826 { .name = "WAIT_END", .expr = {"wait_end",""}},
Willy Tarreau16fbe822007-06-17 11:54:31 +0200827 { .name = NULL, .expr = {""}}
828};
829
830/* Find a default ACL from the default_acl list, compile it and return it.
831 * If the ACL is not found, NULL is returned. In theory, it cannot fail,
832 * except when default ACLs are broken, in which case it will return NULL.
833 * If <known_acl> is not NULL, the ACL will be queued at its tail.
834 */
835struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
836{
837 __label__ out_return, out_free_acl_expr, out_free_name;
838 struct acl *cur_acl;
839 struct acl_expr *acl_expr;
840 char *name;
841 int index;
842
843 for (index = 0; default_acl_list[index].name != NULL; index++) {
844 if (strcmp(acl_name, default_acl_list[index].name) == 0)
845 break;
846 }
847
848 if (default_acl_list[index].name == NULL)
849 return NULL;
850
851 acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr);
852 if (!acl_expr)
853 goto out_return;
854
855 name = strdup(acl_name);
856 if (!name)
857 goto out_free_acl_expr;
858 cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
859 if (cur_acl == NULL)
860 goto out_free_name;
861
862 cur_acl->name = name;
Willy Tarreaua55b7dc2009-07-12 09:21:30 +0200863 cur_acl->requires |= acl_expr->kw->requires;
Willy Tarreau16fbe822007-06-17 11:54:31 +0200864 LIST_INIT(&cur_acl->expr);
865 LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
866 if (known_acl)
867 LIST_ADDQ(known_acl, &cur_acl->list);
868
869 return cur_acl;
870
871 out_free_name:
872 free(name);
873 out_free_acl_expr:
874 prune_acl_expr(acl_expr);
875 free(acl_expr);
876 out_return:
877 return NULL;
878}
Willy Tarreaua84d3742007-05-07 00:36:48 +0200879
880/* Purge everything in the acl_cond <cond>, then return <cond>. */
881struct acl_cond *prune_acl_cond(struct acl_cond *cond)
882{
883 struct acl_term_suite *suite, *tmp_suite;
884 struct acl_term *term, *tmp_term;
885
886 /* iterate through all term suites and free all terms and all suites */
887 list_for_each_entry_safe(suite, tmp_suite, &cond->suites, list) {
888 list_for_each_entry_safe(term, tmp_term, &suite->terms, list)
889 free(term);
890 free(suite);
891 }
892 return cond;
893}
894
895/* Parse an ACL condition starting at <args>[0], relying on a list of already
896 * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
897 * case of low memory). Supports multiple conditions separated by "or".
898 */
899struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol)
900{
901 __label__ out_return, out_free_suite, out_free_term;
Willy Tarreau74b98a82007-06-16 19:35:18 +0200902 int arg, neg;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200903 const char *word;
904 struct acl *cur_acl;
905 struct acl_term *cur_term;
906 struct acl_term_suite *cur_suite;
907 struct acl_cond *cond;
908
909 cond = (struct acl_cond *)calloc(1, sizeof(*cond));
910 if (cond == NULL)
911 goto out_return;
912
913 LIST_INIT(&cond->list);
914 LIST_INIT(&cond->suites);
915 cond->pol = pol;
916
917 cur_suite = NULL;
Willy Tarreau74b98a82007-06-16 19:35:18 +0200918 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200919 for (arg = 0; *args[arg]; arg++) {
920 word = args[arg];
921
922 /* remove as many exclamation marks as we can */
923 while (*word == '!') {
924 neg = !neg;
925 word++;
926 }
927
928 /* an empty word is allowed because we cannot force the user to
929 * always think about not leaving exclamation marks alone.
930 */
931 if (!*word)
932 continue;
933
Willy Tarreau16fbe822007-06-17 11:54:31 +0200934 if (strcasecmp(word, "or") == 0 || strcmp(word, "||") == 0) {
Willy Tarreaua84d3742007-05-07 00:36:48 +0200935 /* new term suite */
936 cur_suite = NULL;
937 neg = 0;
938 continue;
939 }
940
Willy Tarreau16fbe822007-06-17 11:54:31 +0200941 /* search for <word> in the known ACL names. If we do not find
942 * it, let's look for it in the default ACLs, and if found, add
943 * it to the list of ACLs of this proxy. This makes it possible
944 * to override them.
945 */
Willy Tarreaua84d3742007-05-07 00:36:48 +0200946 cur_acl = find_acl_by_name(word, known_acl);
Willy Tarreau16fbe822007-06-17 11:54:31 +0200947 if (cur_acl == NULL) {
948 cur_acl = find_acl_default(word, known_acl);
949 if (cur_acl == NULL)
950 goto out_free_suite;
951 }
Willy Tarreaua84d3742007-05-07 00:36:48 +0200952
953 cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
954 if (cur_term == NULL)
955 goto out_free_suite;
956
957 cur_term->acl = cur_acl;
958 cur_term->neg = neg;
Willy Tarreaua9802632008-07-25 19:13:19 +0200959 cond->requires |= cur_acl->requires;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200960
961 if (!cur_suite) {
962 cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
963 if (cur_term == NULL)
964 goto out_free_term;
965 LIST_INIT(&cur_suite->terms);
966 LIST_ADDQ(&cond->suites, &cur_suite->list);
967 }
968 LIST_ADDQ(&cur_suite->terms, &cur_term->list);
Willy Tarreau74b98a82007-06-16 19:35:18 +0200969 neg = 0;
Willy Tarreaua84d3742007-05-07 00:36:48 +0200970 }
971
972 return cond;
973
974 out_free_term:
975 free(cur_term);
976 out_free_suite:
977 prune_acl_cond(cond);
978 free(cond);
979 out_return:
980 return NULL;
981}
982
Willy Tarreau2bbba412010-01-28 16:48:33 +0100983/* Builds an ACL condition starting at the if/unless keyword. The complete
984 * condition is returned. NULL is returned in case of error or if the first
985 * word is neither "if" nor "unless". It automatically sets the file name and
986 * the line number in the condition for better error reporting, and adds the
987 * ACL requirements to the proxy's acl_requires.
988 */
989struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args)
990{
991 int pol = ACL_COND_NONE;
992 struct acl_cond *cond = NULL;
993
994 if (!strcmp(*args, "if")) {
995 pol = ACL_COND_IF;
996 args++;
997 }
998 else if (!strcmp(*args, "unless")) {
999 pol = ACL_COND_UNLESS;
1000 args++;
1001 }
1002 else
1003 return NULL;
1004
1005 cond = parse_acl_cond(args, &px->acl, pol);
1006 if (!cond)
1007 return NULL;
1008
1009 cond->file = file;
1010 cond->line = line;
1011 px->acl_requires |= cond->requires;
1012
1013 return cond;
1014}
1015
Willy Tarreau11382812008-07-09 16:18:21 +02001016/* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
Willy Tarreaub6866442008-07-14 23:54:42 +02001017 * ACL_PAT_PASS depending on the test results. ACL_PAT_MISS may only be
1018 * returned if <dir> contains ACL_PARTIAL, indicating that incomplete data
1019 * is being examined.
1020 * This function only computes the condition, it does not apply the polarity
1021 * required by IF/UNLESS, it's up to the caller to do this using something like
1022 * this :
Willy Tarreau11382812008-07-09 16:18:21 +02001023 *
1024 * res = acl_pass(res);
Willy Tarreaub6866442008-07-14 23:54:42 +02001025 * if (res == ACL_PAT_MISS)
1026 * return 0;
Willy Tarreau11382812008-07-09 16:18:21 +02001027 * if (cond->pol == ACL_COND_UNLESS)
1028 * res = !res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001029 */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001030int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, void *l7, int dir)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001031{
1032 __label__ fetch_next;
1033 struct acl_term_suite *suite;
1034 struct acl_term *term;
1035 struct acl_expr *expr;
1036 struct acl *acl;
1037 struct acl_pattern *pattern;
1038 struct acl_test test;
Willy Tarreau11382812008-07-09 16:18:21 +02001039 int acl_res, suite_res, cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001040
Willy Tarreau11382812008-07-09 16:18:21 +02001041 /* We're doing a logical OR between conditions so we initialize to FAIL.
1042 * The MISS status is propagated down from the suites.
1043 */
Willy Tarreaua84d3742007-05-07 00:36:48 +02001044 cond_res = ACL_PAT_FAIL;
1045 list_for_each_entry(suite, &cond->suites, list) {
Willy Tarreau11382812008-07-09 16:18:21 +02001046 /* Evaluate condition suite <suite>. We stop at the first term
1047 * which returns ACL_PAT_FAIL. The MISS status is still propagated
1048 * in case of uncertainty in the result.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001049 */
1050
1051 /* we're doing a logical AND between terms, so we must set the
1052 * initial value to PASS.
1053 */
1054 suite_res = ACL_PAT_PASS;
1055 list_for_each_entry(term, &suite->terms, list) {
1056 acl = term->acl;
1057
1058 /* FIXME: use cache !
1059 * check acl->cache_idx for this.
1060 */
1061
1062 /* ACL result not cached. Let's scan all the expressions
1063 * and use the first one to match.
1064 */
1065 acl_res = ACL_PAT_FAIL;
1066 list_for_each_entry(expr, &acl->expr, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001067 /* we need to reset context and flags */
1068 memset(&test, 0, sizeof(test));
Willy Tarreaua84d3742007-05-07 00:36:48 +02001069 fetch_next:
Willy Tarreaub6866442008-07-14 23:54:42 +02001070 if (!expr->kw->fetch(px, l4, l7, dir, expr, &test)) {
1071 /* maybe we could not fetch because of missing data */
1072 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1073 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001074 continue;
Willy Tarreaub6866442008-07-14 23:54:42 +02001075 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001076
Willy Tarreaua79534f2008-07-20 10:13:37 +02001077 if (test.flags & ACL_TEST_F_RES_SET) {
1078 if (test.flags & ACL_TEST_F_RES_PASS)
1079 acl_res |= ACL_PAT_PASS;
1080 else
1081 acl_res |= ACL_PAT_FAIL;
1082 }
1083 else {
1084 /* call the match() function for all tests on this value */
1085 list_for_each_entry(pattern, &expr->patterns, list) {
1086 acl_res |= expr->kw->match(&test, pattern);
1087 if (acl_res == ACL_PAT_PASS)
1088 break;
1089 }
Willy Tarreaua84d3742007-05-07 00:36:48 +02001090 }
1091 /*
Willy Tarreau11382812008-07-09 16:18:21 +02001092 * OK now acl_res holds the result of this expression
1093 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
Willy Tarreaua84d3742007-05-07 00:36:48 +02001094 *
Willy Tarreau11382812008-07-09 16:18:21 +02001095 * Then if (!MISS) we can cache the result, and put
Willy Tarreaua84d3742007-05-07 00:36:48 +02001096 * (test.flags & ACL_TEST_F_VOLATILE) in the cache flags.
1097 *
1098 * FIXME: implement cache.
1099 *
1100 */
1101
1102 /* now we may have some cleanup to do */
1103 if (test.flags & ACL_TEST_F_MUST_FREE) {
1104 free(test.ptr);
1105 test.len = 0;
1106 }
1107
Willy Tarreau11382812008-07-09 16:18:21 +02001108 /* we're ORing these terms, so a single PASS is enough */
1109 if (acl_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001110 break;
1111
Willy Tarreaua84d3742007-05-07 00:36:48 +02001112 if (test.flags & ACL_TEST_F_FETCH_MORE)
1113 goto fetch_next;
Willy Tarreaub6866442008-07-14 23:54:42 +02001114
1115 /* sometimes we know the fetched data is subject to change
1116 * later and give another chance for a new match (eg: request
1117 * size, time, ...)
1118 */
1119 if (test.flags & ACL_TEST_F_MAY_CHANGE && dir & ACL_PARTIAL)
1120 acl_res |= ACL_PAT_MISS;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001121 }
1122 /*
1123 * Here we have the result of an ACL (cached or not).
1124 * ACLs are combined, negated or not, to form conditions.
1125 */
1126
Willy Tarreaua84d3742007-05-07 00:36:48 +02001127 if (term->neg)
Willy Tarreau11382812008-07-09 16:18:21 +02001128 acl_res = acl_neg(acl_res);
Willy Tarreaua84d3742007-05-07 00:36:48 +02001129
1130 suite_res &= acl_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001131
1132 /* we're ANDing these terms, so a single FAIL is enough */
1133 if (suite_res == ACL_PAT_FAIL)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001134 break;
1135 }
1136 cond_res |= suite_res;
Willy Tarreau11382812008-07-09 16:18:21 +02001137
1138 /* we're ORing these terms, so a single PASS is enough */
1139 if (cond_res == ACL_PAT_PASS)
Willy Tarreaua84d3742007-05-07 00:36:48 +02001140 break;
1141 }
Willy Tarreau11382812008-07-09 16:18:21 +02001142 return cond_res;
Willy Tarreaua84d3742007-05-07 00:36:48 +02001143}
1144
1145
Willy Tarreaudd64f8d2008-07-27 22:02:32 +02001146/* Reports a pointer to the first ACL used in condition <cond> which requires
1147 * at least one of the USE_FLAGS in <require>. Returns NULL if none matches.
1148 * The construct is almost the same as for acl_exec_cond() since we're walking
1149 * down the ACL tree as well. It is important that the tree is really walked
1150 * through and never cached, because that way, this function can be used as a
1151 * late check.
1152 */
1153struct acl *cond_find_require(struct acl_cond *cond, unsigned int require)
1154{
1155 struct acl_term_suite *suite;
1156 struct acl_term *term;
1157 struct acl *acl;
1158
1159 list_for_each_entry(suite, &cond->suites, list) {
1160 list_for_each_entry(term, &suite->terms, list) {
1161 acl = term->acl;
1162 if (acl->requires & require)
1163 return acl;
1164 }
1165 }
1166 return NULL;
1167}
1168
1169
Willy Tarreaua84d3742007-05-07 00:36:48 +02001170/************************************************************************/
1171/* All supported keywords must be declared here. */
1172/************************************************************************/
1173
1174/* Note: must not be declared <const> as its list will be overwritten */
1175static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02001176 { "always_true", acl_parse_nothing, acl_fetch_true, acl_match_nothing, ACL_USE_NOTHING },
1177 { "always_false", acl_parse_nothing, acl_fetch_false, acl_match_nothing, ACL_USE_NOTHING },
1178 { "wait_end", acl_parse_nothing, acl_fetch_wait_end, acl_match_nothing, ACL_USE_NOTHING },
Willy Tarreaua84d3742007-05-07 00:36:48 +02001179#if 0
1180 { "time", acl_parse_time, acl_fetch_time, acl_match_time },
1181#endif
1182 { NULL, NULL, NULL, NULL }
1183}};
1184
1185
1186__attribute__((constructor))
1187static void __acl_init(void)
1188{
1189 acl_register_keywords(&acl_kws);
1190}
1191
1192
1193/*
1194 * Local variables:
1195 * c-indent-level: 8
1196 * c-basic-offset: 8
1197 * End:
1198 */